Sequência de cruzamento de grade

17

Se você pegar uma folha de papel milimetrado e desenhar uma linha inclinada que vai para a mdireita e para ncima, você cruza linhas de grade n-1horizontais e m-1verticais em alguma sequência. Escreva o código para produzir essa sequência.

Por exemplo, m=5e n=3fornece:

Linhas de grade cruzando para m = 5, n = 3

Possivelmente relacionado: Gerando ritmos euclidianos , inclinações de Fibonacci , FizzBuzz

Entrada: Dois números inteiros positivos m,nrelativamente primos

Saída: retorne ou imprima os cruzamentos como uma sequência de dois tokens distintos. Por exemplo, poderia ser uma sequência de He V, uma lista de Truee False, ou 0's e 1' impressos em linhas separadas. Pode haver um separador entre tokens, desde que seja sempre o mesmo, e não, digamos, um número variável de espaços.

Casos de teste:

O primeiro caso de teste fornece saída vazia ou nenhuma saída.

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

No 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])
xnor
fonte
2
Hoje no PPCG: algoritmo de desenho de linha de Bresenham do golfe
Sparr
Com base no formato alternativo que você adicionou, a entrada pode / deve ser repetida como parte da saída? Caso contrário, não entendo por que a entrada e a saída fazem parte da mesma lista.
Reto Koradi
@RetoKoradi Não, você não deve incluir a entrada. Coloquei-o em tuplas para facilitar o processamento dos casos de teste.
xnor
Posso prever a resposta, mas não é demais perguntar: seria aceitável usar o caractere de espaço como um dos tokens de saída? Uma conseqüência seria que poderia haver espaços iniciais / finais significativos na saída. Não haveria outros espaços, portanto todos os espaços seriam significativos.
Reto Koradi
@RetoKoradi Não, porque os espaços finais não são visíveis.
Xnor

Respostas:

7

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

A saída para ambos usa 1 e 0 (ex. 101101 ).


Aqui está uma explicação do avestruz:

: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 uma explicação de como tudo funciona, usando o código Ruby como guia:

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)
}
Maçaneta da porta
fonte
5

Python, 53

Isso usa a saída da lista Verdadeiro / Falso. Nada de especial aqui.

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

Pitão - 32 24 bytes

Jmm,chk@Qddt@Qd2eMS+hJeJ

Recebe entrada via stdin com o formato [m,n]. Imprime o resultado em stdout como uma lista de 0 e 1, em que 0 = V e 1 = H.

Teste on-line


Explicação:

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
fonte
Você pode salvar um byte usando o operador de mapa sintático para o final do mapeamento. eMé o mesmo que med.
Maltysen
Além disso, você pode retirar @"VH"já que tem permissão para imprimir 0e 1não Ve H.
Maltysen 23/06
Você pode salvar mais um byte usando a atribuição embutida com J. Aqui está o que eu tenho até agora em 25 bytes: pyth.herokuapp.com/…
Maltysen
@ Maltysen, obrigado Eu acho que você pode remover jkcomo a saída pode ser uma lista.
Tyilo
Você pode ver 23 comentários sobre meu trabalho em linha.
Maltysen
4

Código de máquina IA-32, 26 bytes

Hexdump do código:

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

Comecei a partir do seguinte código 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;
    }
}

Ele grava a saída no buffer fornecido. Ele não retorna o comprimento da saída, mas não é realmente necessário: o comprimento da saída é 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]);
    }
}

Para converter o código C em código de máquina, primeiro fiz alguns ajustes, para tornar um dos if/elseramos vazio e comparar com0 em vez de 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;
    }
}

A partir daqui, escrever o código de montagem em linha é direto:

__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
fonte
Estou curioso - por que esse algoritmo funciona?
xnor
@xnor Informalmente, ele rastreia a sequência do fizzbuzz . Aqui testá a "distância para buzz". Se a distância for pelo menos n, vá fizz, então vá buzz; atualize a distância; repita até que seja
zero
3

Python - 125 bytes

Utiliza um algoritmo muito simples, apenas incrementa as coordenadas e detecta quando cruza as linhas e imprime. Estou procurando traduzir para 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

Esse loop while está verificando o número de l ines e, em seguida, verificando se algum dos valores ultrapassou um limite int subtraindo.

Toma entradas como 39, 100stdin e imprime como HHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHHVHHVHHHVHHVHHHVHHVHHHVHHstdout em uma linha.

Maltysen
fonte
3

CJam, 15 bytes

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

Experimente aqui.

Imprime 01para V e10 para H.

Explicação

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.

A linha diagonal cruza uma linha horizontal para cada 1 / n de toda a linha diagonal e cruza uma linha vertical para cada 1 / m.

jimmy23013
fonte
Você vai adicionar uma explicação para isso? É muito intrigante, mas pelo menos desde uma rápida olhada inicial, não entendo por que funciona. Ao brincar com ele, percebo que ele funciona apenas para valores que são primos relativos (que são dados na descrição do problema), enquanto o meu funciona para todos os valores. Portanto, a matemática subjacente é obviamente muito diferente.
Reto Koradi 02/07/2015
Depois de deixar isso afundar um pouco mais, acredito que entendo pelo menos a parte do algoritmo. Tem que estudar a lógica de geração de saída posteriormente.
Reto Koradi 02/07/2015
@RetoKoradi Editado.
precisa saber é o seguinte
2

TI-BASIC, 32

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

Direto. Usa uma sequência de 0e 1, separada por quebras de linha. As vantagens do TI-BASIC são a gcd(multiplicação implícita e de dois bytes , mas suas desvantagens são o loop For, incluindo o valor final e os 5 bytes gastos na entrada.

lirtosiast
fonte
2

Python, 47

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

Como o algoritmo de anatolyg , mas verificado diretamente com os módulos.

xnor
fonte
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]]

Exemplo de uso:

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

Como funciona: faça uma lista dos valores x de todos os cruzamentos verticais (x,0)para xem [1,2, ..., m-1] ( 0indica vertical) e anexe a lista dos valores x de todos os cruzamentos horizontais (y*m/n,1)para yem [1,2, ..., n-1] (1 indica horizontal). Classifique e pegue os segundos elementos dos pares.

Maldição do dia: novamente eu tenho que gastar 17 bytes no importporque sortestá dentro Data.Liste não na biblioteca padrão.

nimi
fonte
1

KDB (Q), 44 bytes

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

Explicação

Encontre tudo x valores do eixo dos pontos de interseção e ordene-os. Se o mod 1 for zero, seu "V", diferente de zero, será "H".

Teste

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

CJam, 26 24 bytes

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

Experimente online

Muito simples, praticamente uma implementação direta de um algoritmo do tipo Bresenham.

Explicação:

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.

O último 01precisa ser exibido porque o loop foi até o ponto final, o que não faz parte do resultado desejado. Note que podemos não basta reduzir a contagem de loop 1. Caso contrário, para N > M, todos os 0s da última iteração vai estar ausente, enquanto nós só precisa se livrar do último 0.

Reto Koradi
fonte
11
Você pode usar >para ;W<.
#
@ jimmy23013 Boa ideia. Como sei que tenho um 1no topo da pilha, posso usá-lo produtivamente.
Reto Koradi