Sequenza di attraversamento della griglia


17

Se prendi un foglio di carta millimetrata e disegni una linea inclinata che va verso mdestra e nverso l'alto, attraversi le griglie n-1orizzontali e m-1verticali in una sequenza. Scrivi il codice per generare quella sequenza.

Ad esempio, m=5e n=3dà:

Griglie che attraversano per m = 5, n = 3

Possibilmente correlati: ritmi Generazione euclidee , tassellature di Fibonacci , FizzBuzz

Input: due numeri interi positivi m,nche sono relativamente primi

Output: restituisce o stampa gli incroci come una sequenza di due token distinti. Ad esempio, potrebbe essere una stringa di He V, un elenco di Truee False, o 0'e 1' s stampato su righe separate. Può esserci un separatore tra i token purché sia ​​sempre lo stesso e non, diciamo, un numero variabile di spazi.

Casi test:

Il primo caso di test produce output vuoti o nessun output.

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

Nel formato (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])

2
Oggi su PPCG: golf Bresenham's Line Drawing Algorithm
Sparr,

In base al formato alternativo aggiunto, è possibile / deve essere ripetuto l'input come parte dell'output? Altrimenti, non capisco perché l'input e l'output facciano parte dello stesso elenco.
Reto Koradi,

@RetoKoradi No, non dovresti includere l'input. L'ho messo in tuple per semplificare l'elaborazione dei casi di test.
xnor

Posso prevedere la risposta, ma non può far male chiedere: sarebbe accettabile usare il carattere spazio come uno dei token di output? Una conseguenza sarebbe che potrebbero esserci spazi iniziali / finali significativi nell'output. Non ci sarebbero altri spazi, quindi tutti gli spazi sarebbero significativi.
Reto Koradi,

@RetoKoradi No, perché gli spazi finali non sono visibili.
xnor

Risposte:


7

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

L'output per entrambi usa 1 e 0 (es. 101101).


Ecco una spiegazione di quello di struzzo:

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

E una spiegazione di come funziona tutto, usando il codice Ruby come guida:

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

5

Python, 53

Questo utilizza l'output dell'elenco Vero / Falso. Niente di speciale qui.

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

4

Pyth - 32 24 byte

Jmm,chk@Qddt@Qd2eMS+hJeJ

Accetta input tramite stdin con il formato [m,n]. Stampa il risultato su stdout come un elenco di 0 e 1, dove 0 = V e 1 = H.

Provalo online


Spiegazione:

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

È possibile salvare un byte utilizzando l'operatore di mappa sintattica per la fine della mappatura. eMè lo stesso di med.
Maltysen,

Inoltre, puoi semplicemente eliminarlo @"VH"poiché ti è consentito stampare 0e 1invece di Ve H.
Maltysen,

È possibile salvare ancora un altro byte utilizzando l'assegnazione in linea con J. Ecco cosa ho finora a 25 byte: pyth.herokuapp.com/…
Maltysen,

@Maltysen, grazie penso che tu possa rimuovere in jkquanto l'output può essere un elenco.
Tyilo,

Puoi dare 23 un'occhiata al mio commento sull'assegnazione in linea.
Maltysen,

4

Codice macchina IA-32, 26 byte

Hexdump del codice:

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

Ho iniziato dal seguente codice 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;
    }
}

Scrive l'output nel buffer fornito. Non restituisce la lunghezza dell'output, ma non è davvero necessario: la lunghezza dell'output è sempre 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]);
    }
}

Per convertire il codice C in codice macchina, ho fatto qualche modifica, per fare uno dei if/elserami vuoti, e confrontare con 0invece di 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;
    }
}

Da qui, scrivere il codice dell'assembly inline è semplice:

__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)
    }
}

Sono curioso: perché funziona questo algoritmo?
xnor

@xnor Informalmente, tiene traccia della sequenza fizzbuzz . Ecco tla "distanza da buzz". Se la distanza è almeno n, vai fizz, altrimenti vai buzz; aggiorna la distanza; ripetere fino a quando non è 0.
Anatolyg

3

Python - 125 byte

Utilizza un algoritmo molto semplice, aumenta solo le coordinate e rileva quando attraversa le linee e le stampa. Sto cercando di tradurre in 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

Quel ciclo while sta controllando il numero di in le quindi controllando se qualcuno dei valori ha superato un limite int sottraendo.

Prende input come 39, 100da stdin e stampa come HHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHsu stdout in una riga.


3

CJam, 15 byte

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

Provalo qui.

Stampa 01 per V e 10per H.

Spiegazione

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.

La linea diagonale attraversa una linea orizzontale per ogni 1 / n dell'intera linea diagonale e attraversa una linea verticale per ogni 1 / m.


Aggiungerai una spiegazione per questo? È molto intrigante, ma almeno da una rapida occhiata iniziale non capisco perché funzioni. Da giocarci, noto che funziona solo per valori che sono primi primi (che è dato nella descrizione del problema), mentre il mio funziona per tutti i valori. Quindi la matematica sottostante è ovviamente molto diversa.
Reto Koradi,

Dopo averlo lasciato affondare ancora un po ', credo di capire almeno la parte dell'algoritmo. Devono studiare la logica di generazione dell'output in un secondo momento.
Reto Koradi,

@RetoKoradi Edited.
jimmy23013,

2

TI-BASIC, 32

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

Semplice. Utilizza una sequenza di 0e 1, separata da interruzioni di riga. I vantaggi di TI-BASIC sono la gcd(moltiplicazione implicita a due byte , ma i suoi svantaggi sono il ciclo For che include il valore finale e i 5 byte spesi per l'input.



1

Haskell, 78 byte

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

Esempio di utilizzo:

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

Come funziona: crea un elenco dei valori x di tutti gli incroci verticali (x,0)per xin [1,2, ..., m-1] ( 0indica verticale) e aggiungi l'elenco dei valori x di tutti gli incroci orizzontali (y*m/n,1)per yin [1,2, ..., n-1] ( 1indica orizzontale). Ordina e prendi i secondi elementi delle coppie.

Maledizione del giorno: di nuovo devo spendere 17 byte per il importperché sortè dentro Data.Liste non nella libreria standard.


1

KDB (Q), 44 byte

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

Spiegazione

Trova tutti i valori dell'asse x dei punti di intersezione e ordinali. Se mod 1 è zero la sua "V", diverso da zero è "H".

Test

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

1

CJam, 26 24 byte

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

Provalo online

Molto semplice, praticamente un'implementazione diretta di un algoritmo di tipo Bresenham.

Spiegazione:

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.

L'ultimo 01deve essere spuntato perché il loop è arrivato fino al punto finale, che non fa parte dell'output desiderato. Nota che siamo in grado non solo di ridurre il numero di loop di 1. In caso contrario, per N > M, tutti i 0s dall'ultima iterazione mancheranno, mentre abbiamo bisogno solo di sbarazzarsi del proprio all'ultimo 0.


1
Puoi usare >per ;W<.
jimmy23013,

@ jimmy23013 Buona idea. Dal momento che so di avere uno 1in cima allo stack, potrei anche usarlo in modo produttivo.
Reto Koradi,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.