Gitterkreuzungssequenz

17

Wenn Sie ein Blatt Millimeterpapier nehmen und eine geneigte Linie zeichnen, die mEinheiten nach rechts und nEinheiten nach oben zeigt, kreuzen Sie n-1horizontale und m-1vertikale Gitterlinien in einer bestimmten Reihenfolge. Schreiben Sie Code, um diese Sequenz auszugeben.

Zum Beispiel m=5und n=3gibt:

Gitternetzlinien kreuzen sich für m = 5, n = 3

Möglicherweise verwandt: Euklidische Rhythmen erzeugen , Fibonacci- Fliesen , FizzBuzz

Eingabe: Zwei positive ganze Zahlen m,n, die relativ prim sind

Ausgabe: Gibt die Kreuzungen als Folge von zwei unterschiedlichen Token zurück oder druckt sie aus. Zum Beispiel kann es sich um eine Zeichenfolge aus Hund V, eine Liste aus Trueund Falseoder 0's und 1' s handeln, die in separaten Zeilen gedruckt werden. Es kann ein Trennzeichen zwischen Tokens geben, solange es immer dasselbe ist, und nicht etwa eine variable Anzahl von Leerzeichen.

Testfälle:

Der erste Testfall gibt eine leere Ausgabe oder keine Ausgabe aus.

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

Im Format (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
quelle
2
Heute auf PPCG: Golf Bresenhams Strichzeichnungsalgorithmus
Sparr
Kann / muss die Eingabe aufgrund des von Ihnen hinzugefügten alternativen Formats als Teil der Ausgabe wiederholt werden? Ansonsten verstehe ich nicht, warum die Eingabe und Ausgabe Teil derselben Liste sind.
Reto Koradi
@RetoKoradi Nein, Sie sollten die Eingabe nicht einschließen. Ich habe es in Tupel geschrieben, um die Bearbeitung der Testfälle zu vereinfachen.
Donnerstag,
Ich kann die Antwort vorhersagen, aber es kann nicht schaden, zu fragen: Wäre es akzeptabel, das Leerzeichen als eines der Ausgabetoken zu verwenden? Eine Konsequenz wäre, dass es signifikante führende / nachfolgende Leerzeichen in der Ausgabe geben könnte. Es gäbe keine anderen Räume, daher wären alle Räume von Bedeutung.
Reto Koradi
@RetoKoradi Nein, da nachgestellte Leerzeichen nicht sichtbar sind.
Xnor

Antworten:

7

Ruby, 92; Strauß 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%

Die Ausgabe für beide verwendet Einsen und Nullen (z. B. 101101).


Hier ist eine Erklärung für den Strauß:

: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)

Und eine Erklärung, wie das Ganze funktioniert, unter Verwendung des Ruby-Codes als Leitfaden:

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)
}
Türknauf
quelle
5

Python, 53

Dies verwendet die Ausgabe der True / False-Liste. Nichts besonderes hier.

lambda m,n:[x%m<1for x in range(1,m*n)if x%m*(x%n)<1]
Feersum
quelle
4

Pyth - 32 24 Bytes

Jmm,chk@Qddt@Qd2eMS+hJeJ

Übernimmt die Eingabe über stdin mit dem Format [m,n] . Gibt das Ergebnis als Liste der Nullen und Einsen an stdout aus, wobei 0 = V und 1 = H.

Testen Sie es online


Erläuterung:

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
quelle
Sie können ein Byte speichern, indem Sie den syntaktischen Zuordnungsoperator für das Zuordnungsende verwenden. eMist das gleiche wie med.
Maltysen
Sie können auch einfach herausnehmen, @"VH"da Sie drucken dürfen 0und 1statt Vund H.
Maltysen
Sie können noch ein weiteres Byte speichern, indem Sie die Inline-Zuweisung mit verwenden J. Hier ist, was ich bisher bei 25 Bytes habe: pyth.herokuapp.com/…
Maltysen
@Maltysen, danke ich denke du kannst es entfernen, jkda die Ausgabe eine Liste sein kann.
Tyilo
Sie können sich meinen Kommentar zur Inline-Zuordnung ansehen.
Maltysen
4

IA-32 Maschinencode, 26 Bytes

Hexdump des Codes:

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

Ich habe mit dem folgenden C-Code begonnen:

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;
    }
}

Es schreibt die Ausgabe in den bereitgestellten Puffer. Es gibt nicht die Länge der Ausgabe zurück, aber es wird nicht wirklich benötigt: Die Ausgabelänge ist immer 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]);
    }
}

Um den C-Code in Maschinencode umzuwandeln, habe ich zuerst einige Anpassungen vorgenommen, um einen der if/elseZweige leer zu machen und mit zu vergleichen, 0anstatt mit 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;
    }
}

Von hier aus ist das Schreiben des Inline-Assembler-Codes unkompliziert:

__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)
    }
}
anatolyg
quelle
Ich bin gespannt - warum funktioniert dieser Algorithmus?
Donnerstag,
@xnor Informell verfolgt es die Fizzbuzz-Sequenz . Hier tist die "Entfernung zu buzz". Wenn der Abstand mindestens ist n, gehen Sie fizz, sonst gehen Sie buzz; aktualisiere die Entfernung; Wiederholen, bis es 0 ist.
Anatolyg
3

Python - 125 Bytes

Verwendet einen sehr einfachen Algorithmus, erhöht nur die Koordinaten und erkennt, wenn er die Linien kreuzt und druckt. Bin auf der Suche nach Pyth zu übersetzen.

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

Diese while-Schleife überprüft die Anzahl der lInes und dann, ob einer der Werte eine int-Grenze überschreitet, indem sie subtrahiert.

Nimmt Eingaben wie 39, 100von stdin und druckt wie HHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHvon stdout in einer Zeile.

Maltysen
quelle
3

CJam, 15 Bytes

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

Probieren Sie es hier aus.

Es druckt 01für V und 10für H.

Erläuterung

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.

Die diagonale Linie kreuzt eine horizontale Linie für jeweils 1 / n der gesamten diagonalen Linie und eine vertikale Linie für jeweils 1 / m.

jimmy23013
quelle
Fügen Sie eine Erklärung dafür hinzu? Es ist sehr faszinierend, aber zumindest auf den ersten Blick verstehe ich nicht, warum es funktioniert. Wenn ich damit spiele, bemerke ich, dass es nur für Werte funktioniert, die relative Primzahlen sind (was in der Problembeschreibung angegeben ist), während meine Werte für alle Werte funktionieren. Die zugrunde liegende Mathematik ist also offensichtlich sehr unterschiedlich.
Reto Koradi
Nachdem ich es noch ein wenig nachgelassen habe, glaube ich, dass ich zumindest den Algorithmus-Teil verstehe. Muss später die Logik der Ausgabegenerierung studieren.
Reto Koradi
@RetoKoradi Bearbeitet.
Jimmy23013
2

TI-BASIC, 32

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

Einfach. Verwendet eine durch Zeilenumbrüche getrennte Folge von 0und 1. Die Vorteile von TI-BASIC sind die Zwei-Byte- gcd(und die implizite Multiplikation, die Nachteile sind jedoch die For-Schleife mit dem Endwert und den 5 für die Eingabe aufgewendeten Bytes.

Lirtosiast
quelle
2

Python, 47

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

Wie Anatolygs Algorithmus , jedoch direkt mit Modulen überprüft.

xnor
quelle
1

Haskell, 78 Bytes

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

Anwendungsbeispiel:

*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]

So funktioniert es: Erstellen Sie eine Liste der x-Werte aller vertikalen Kreuzungen (x,0)für xin [1,2, ..., m-1] ( 0zeigt vertikal an) und hängen Sie die Liste der x-Werte aller horizontalen Kreuzungen an(y*m/n,1) für yin an [1,2, ..., n-1] (1 zeigt horizontal an). Sortieren und nehmen Sie die zweiten Elemente der Paare.

Fluch des Tages: Ich muss wieder 17 Bytes aufwenden, importweil sortin Data.Listund nicht in der Standardbibliothek.

nimi
quelle
1

KDB (Q), 44 Bytes

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

Erläuterung

Finde alle x Achsenwerte von Schnittpunkten und sortiere sie. Wenn mod 1 Null ist, ist sein "V", nicht Null ist "H".

Prüfung

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

CJam, 26 24 Bytes

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

Probieren Sie es online aus

Sehr einfach, so ziemlich eine direkte Implementierung eines Algorithmus vom Typ Bresenham.

Erläuterung:

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.

Das letzte 01muss gepoppt werden, da die Schleife bis zum Endpunkt durchlief, was nicht Teil der gewünschten Ausgabe ist. Beachten Sie, dass wir die Anzahl der Schleifen nicht einfach um 1 reduzieren können . Andernfalls fehlen N > Malle 0s der letzten Iteration, während wir nur die allerletzten entfernen müssen 0.

Reto Koradi
quelle
1
Sie können >für verwenden ;W<.
Jimmy23013
@ Jimmy23013 Gute Idee. Da ich weiß, dass ich 1oben auf dem Stapel einen habe, kann ich ihn genauso gut produktiv einsetzen.
Reto Koradi