Sekwencja przekraczania siatki

17

Jeśli weźmiesz arkusz papieru milimetrowego i narysujesz nachyloną linię, która prowadzi mjednostki w prawo, a njednostki w górę, przecinasz n-1poziome i m-1pionowe linie siatki w pewnej sekwencji. Napisz kod, aby wygenerować tę sekwencję.

Na przykład m=5i n=3daje:

Przecięcie linii siatki dla m = 5, n = 3

Prawdopodobnie związane: rytmy Generowanie euklidesowej , tilings Fibonacciego , FizzBuzz

Wejście: Dwie dodatnie liczby całkowite, m,nktóre są względnie pierwsze

Wyjście: Zwróć lub wydrukuj skrzyżowania jako sekwencję dwóch różnych tokenów. Na przykład może to być ciąg Hi V, lista Truei False, lub 0„i 1” są wydrukowane w osobnych wierszach. Może istnieć separator między tokenami, o ile jest zawsze taki sam, a nie, powiedzmy, zmienna liczba spacji.

Przypadki testowe:

Pierwszy przypadek testowy daje pusty wynik lub brak wyjścia.

1 1 
1 2 H
2 1 V
1 3 HH
3 2 VHV
3 5 HVHHVH
5 3 VHVVHV
10 3 VVVHVVVHVVV
4 11 HHVHHHVHHHVHH
19 17 VHVHVHVHVHVHVHVHVVHVHVHVHVHVHVHVHV
39 100 HHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHH

W formacie (m,n,output_as_list_of_0s_and_1s):

(1, 1, [])
(1, 2, [0])
(2, 1, [1])
(1, 3, [0, 0])
(3, 2, [1, 0, 1])
(3, 5, [0, 1, 0, 0, 1, 0])
(5, 3, [1, 0, 1, 1, 0, 1])
(10, 3, [1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1])
(4, 11, [0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0])
(19, 17, [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1])
(39, 100, [0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0])
xnor
źródło
2
Dzisiaj w PPCG: Algorytm rysowania linii golfa Bresenhama
Sparr
Czy w oparciu o dodany format alternatywny można / należy powtórzyć dane wejściowe jako część wyniku? W przeciwnym razie nie rozumiem, dlaczego dane wejściowe i wyjściowe są częścią tej samej listy.
Reto Koradi
@RetoKoradi Nie, nie należy dołączać danych wejściowych. Umieszczam go w krotkach, aby ułatwić przetwarzanie przypadków testowych.
xnor
Potrafię przewidzieć odpowiedź, ale pytanie nie może zaszkodzić: czy można użyć znaku spacji jako jednego z tokenów wyjściowych? Konsekwencją byłoby, że na wyjściu mogą występować znaczące spacje wiodące / końcowe. Nie byłoby innych spacji, więc wszystkie spacje byłyby znaczące.
Reto Koradi,
@RetoKoradi Nie, ponieważ końcowe spacje nie są widoczne.
xnor

Odpowiedzi:

7

Ruby, 92; Struś 0.7.0 , 38

f=->m,n{((1..m-1).map{|x|[x,1]}+(1..n-1).map{|x|[1.0*x*m/n,0]}).sort_by(&:first).map &:last}
:n;:m1-,{)o2W}%n1-,{)m n/*0pW}%+_H$_T%

Dane wyjściowe dla obu z nich używają 1 i 0 (np. 101101).


Oto wyjaśnienie strusia:

:n;:m    store n and m as variables, keep m on the stack
1-,      from ex. 5, generate [0 1 2 3]
{...}%   map...
  )        increment, now 5 -> [1 2 3 4]
  o        push 1 (the digit 1 is special-cased as `o')
  2W       wrap the top two stack elements into an array
           we now have [[1 1] [2 1] [3 1] [4 1]]
n1-,     doing the same thing with n
{...}%   map...
  )        increment, now 3 -> [1 2]
  m n/*    multiply by slope to get the x-value for a certain y-value
  0        push 0
  pW       wrap the top two stack elements (2 is special-cased as `p')
+        concatenate the two arrays
_H$      sort-by first element (head)
_T%      map to last element (tail)

I wyjaśnienie, jak to wszystko działa, używając kodu Ruby jako przewodnika:

f = ->m,n {
    # general outline:
    # 1. collect a list of the x-coordinates of all the crossings
    # 2. sort this list by x-coordinate
    # 3. transform each coordinate into a 1 or 0 (V or H)
    # observation: there are (m-1) vertical crossings, and (n-1) horizontal
    #   crossings. the vertical ones lie on integer x-values, and the
    #   horizontal on integer y-values
    # collect array (1)
    (
        # horizontal
        (1..m-1).map{|x| [x, 1] } +
        # vertical
        (1..n-1).map{|x| [1.0 * x * m/n, 0] }  # multiply by slope to turn
                                               # y-value into x-value
    )
    .sort_by(&:first)  # sort by x-coordinate (2)
    .map &:last        # transform into 1's and 0's (3)
}
Klamka
źródło
5

Python, 53

Wykorzystuje dane wyjściowe z listy Prawda / Fałsz. Nic specjalnego.

lambda m,n:[x%m<1for x in range(1,m*n)if x%m*(x%n)<1]
feersum
źródło
4

Pyth - 32 24 bajty

Jmm,chk@Qddt@Qd2eMS+hJeJ

Pobiera dane wejściowe za pośrednictwem standardowego formatu [m,n]. Wyświetla wynik na standardowe wyjście jako listę zer i jedynek, gdzie 0 = V, a 1 = H.

Przetestuj online


Wyjaśnienie:

J                           # J = 
 m             2            # map(lambda d: ..., range(2))
  m        t@Qd             # map(lambda k: ..., range(input[d] - 1))
   ,chk@Qdd                 # [(k + 1) / input[d], d]
                eMS+hJeJ    # print map(lambda x: x[-1], sorted(J[0] + J[-1])))
Tyilo
źródło
Możesz zapisać bajt za pomocą syntaktycznego operatora mapy dla końca mapowania. eMjest taki sam jak med.
Maltysen
Ponadto możesz po prostu wyjąć, @"VH"ponieważ możesz drukować, 0a 1zamiast Vi H.
Maltysen
Możesz zapisać kolejny bajt, używając przypisania wbudowanego z J. Oto, co do tej pory mam przy 25 bajtach: pyth.herokuapp.com/…
Maltysen
@Maltysen, dzięki, myślę, że możesz usunąć, jkponieważ wyjściem może być lista.
Tyilo,
Możesz uzyskać 23 spojrzenie na mój komentarz na temat przypisania wbudowanego.
Maltysen
4

Kod maszynowy IA-32, 26 bajtów

Hexdump kodu:

60 8b 7c 24 24 8d 34 11 33 c0 2b d1 74 08 73 03
03 d6 40 aa eb f2 61 c2 04 00

Zacząłem od następującego kodu C:

void doit(int m, int n, uint8_t* out)
{
    int t = m;
    while (true)
    {
        if (t >= n)
        {
            t -= n;
            *out++ = 1;
        }
        else
        {
            t += m;
            *out++ = 0;
        }
        if (t == n)
            break;
    }
}

Zapisuje dane wyjściowe w dostarczonym buforze. Nie zwraca długości danych wyjściowych, ale nie jest tak naprawdę potrzebne: długość wyjściowa wynosi zawsze m + n - 2:

int main()
{
    char out[100];
    int m = 10;
    int n = 3;
    doit(m, n, out);
    for (int i = 0; i < m + n - 2; ++i)
    {
        printf("%d ", out[i]);
    }
}

Aby przekonwertować kod C na kod maszynowy, najpierw zrobił kilka szczypanie, aby jeden z if/elseoddziałów opróżnić i porównać 0zamiast n:

void doit(int m, int n, char* out)
{
    int t = n;
    while (true)
    {
        int r = 0;
        t -= m;
        if (t == 0)
            break;
        if (t >= 0)
        {
        }
        else
        {
            t += m + n;
            ++r;
        }
        *out++ = r;
    }
}

Odtąd pisanie kodu asemblera jest proste:

__declspec(naked) void __fastcall doit(int x, int y, char* out)
{
    _asm
    {
        pushad;                 // save all registers
        mov edi, [esp + 0x24];  // edi is the output address
        lea esi, [ecx + edx];   // esi is the sum m+n
    myloop:                     // edx is the working value (t)
        xor eax, eax;           // eax is the value to write (r)
        sub edx, ecx;
        jz myout;
        jae mywrite;
        add edx, esi;
        inc eax;
    mywrite:
        stosb;                  // write one value to the output
        jmp myloop;
    myout:
        popad;                  // restore all registers
        ret 4;                  // return (discarding 1 parameter on stack)
    }
}
anatolig
źródło
Jestem ciekawy - dlaczego ten algorytm działa?
xnor
@xnor Nieformalnie śledzi sekwencję fizzbuzz . Oto t„odległość do buzz”. Jeśli odległość jest co najmniej n, idź fizz, albo idź buzz; zaktualizować odległość; powtarzaj do 0.
anatolyg
3

Python - 125 bajtów

Wykorzystuje bardzo prosty algorytm, po prostu zwiększa współrzędne i wykrywa, kiedy przecina linie i drukuje. Chcę przetłumaczyć na Pyth.

a,b=input()
i=1e-4
x=y=l=o=p=0
k=""
while len(k)<a+b-2:x+=i*a;y+=i*b;k+="V"*int(x//1-o//1)+"H"*int(y//1-p//1);o,p=x,y
print k

Ta pętla while sprawdza liczbę lines, a następnie sprawdza, czy którakolwiek z wartości nie przekroczyła wewnętrznej granicy, odejmując.

Pobiera dane wejściowe jak 39, 100ze standardowego wejścia i wypisuje jak standardowe HHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHw jednym wierszu.

Maltysen
źródło
3

CJam, 15 bajtów

Ll~_:*,\ff{%!^}

Wypróbuj tutaj.

Drukuje 01dla V i 10H.

Wyjaśnienie

L          e# An empty list.
l~         e# Evaluate the input.
_:*,       e# [0, m*n).
\          e# The input (m and n).
ff{%!      e# Test if each number in [0, m*n) is divisible by m and n.
^}         e# If divisible by m, add an 10, or if divisible by n, add an 01 into
           e# the previous list. If divisible by neither, the two 0s cancel out.
           e# It's just for output. So we don't care about what the previous list
           e# is -- as long as it contains neither 0 or 1.

Linia ukośna przecina linię poziomą na każdy 1 / n całej linii ukośnej i przecina linię pionową na każdy 1 / m.

jimmy23013
źródło
Czy dodasz wyjaśnienie? To bardzo intrygujące, ale przynajmniej od pierwszego szybkiego spojrzenia nie rozumiem, dlaczego to działa. Grając z nim, zauważam, że działa tylko dla wartości, które są względnymi liczbami pierwszymi (co podano w opisie problemu), podczas gdy moje działa dla wszystkich wartości. Podstawowa matematyka jest oczywiście bardzo różna.
Reto Koradi,
Po dłuższym zanurzeniu wydaje mi się, że rozumiem przynajmniej część algorytmu. Muszę później przestudiować logikę generowania danych wyjściowych.
Reto Koradi,
@RetoKoradi Edytowane.
jimmy23013
2

TI-BASIC, 32

Prompt M,N
For(X,1,MN-1
gcd(X,MN
If log(Ans
Disp N=Ans
End

Bezpośredni. Wykorzystuje sekwencję 0i 1, oddzielone podziałami linii. Zaletami TI-BASIC są dwubajtowe gcd(i dorozumiane mnożenie, ale jego wadami są pętla For, w tym wartość końcowa i 5 bajtów wydanych na dane wejściowe.

lirtosiast
źródło
2

Python, 47

lambda m,n:[m>i*n%(m+n)for i in range(1,m+n-1)]

Jak algorytm anatolyga , ale sprawdzany bezpośrednio za pomocą modułów.

xnor
źródło
1

Haskell, 78 bajtów

import Data.List
m#n=map snd$sort$[(x,0)|x<-[1..m-1]]++[(y*m/n,1)|y<-[1..n-1]]

Przykład użycia:

*Main> 19 # 17
[0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0]
*Main> 10 # 3
[0,0,0,1,0,0,0,1,0,0,0]

Jak to działa: sporządzić listę wartości x wszystkich skrzyżowań pionowych (x,0)dla xw [1,2, ..., m-1] ( 0wskazuje w pionie) i dołączyć listę wartości x wszystkich skrzyżowań poziomych (y*m/n,1)dla yw [1,2, ..., n-1] ( 1wskazuje poziomo). Posortuj i weź drugie elementy par.

Klątwa dnia: znowu muszę wydać 17 bajtów, importponieważ sortjest w Data.Liststandardowej bibliotece, a nie w niej.

nimi
źródło
1

KDB (Q), 44 bajty

{"HV"0=mod[asc"f"$1_til[x],1_(x*til y)%y;1]}

Wyjaśnienie

Znajdź wszystkie wartości osi x punktów przecięcia i posortuj je. Jeśli mod 1 wynosi zero, jego „V”, niezerowe oznacza „H”.

Test

q){"HV"0=mod[asc"f"$1_til[x],1_(x*til y)%y;1]}[5;3]
"VHVVHV"
WooiKent Lee
źródło
1

CJam, 26 24 bajtów

l~:N;:M{TN+Mmd:T;0a*1}*>

Wypróbuj online

Bardzo prosta, prawie bezpośrednia implementacja algorytmu typu Bresenham.

Wyjaśnienie:

l~    Get input and convert to 2 integers.
:N;   Store away N in variable, and pop from stack.
:M    Store away M in variable.
{     Loop M times.
  T     T is the pending remainder.
  N+    Add N to pending remainder.
  M     Push M.
  md    Calculate div and mod.
  :T;   Store away mod in T, and pop it from stack
  0a    Wrap 0 in array so that it is replicated by *, not multiplied.
  *     Emit div 0s...
  1     ... and a 1.
}*      End of loop over M.
>       Pop the last 1 and 0.

Ostatni 01musi zostać usunięty, ponieważ pętla przeszła aż do punktu końcowego, który nie jest częścią pożądanego wyjścia. Należy pamiętać, że możemy nie tylko zmniejszyć liczbę pętli o 1. W przeciwnym razie, N > Mwszystkie 0s od ostatniej iteracji będzie brakować, gdy musimy tylko pozbyć się bardzo ostatnio 0.

Reto Koradi
źródło
1
Możesz użyć >do ;W<.
jimmy23013
@ jimmy23013 Dobry pomysł. Ponieważ wiem, że mam 1stos na szczycie, równie dobrze mogę go produktywnie wykorzystać.
Reto Koradi