O caminho do gnu

23

Golf um programa ou função que forneça a localização do gnu que começa no quadrado em um tabuleiro de xadrez infinito numerado em uma espiral quadrada no sentido anti-horário, onde o gnu sempre visita o quadrado numerado mais baixo ela pode alcançar o que ela ainda não visitou.nth1

Inspiração: The Trapped Knight e OEIS A316667 .

Editar: Esta sequência está agora no OEIS como A323763 .

O código pode produzir o local , os primeiros locais ou gerar a sequência sem entrada.nthn

Sinta-se à vontade para fornecer a localização dela após (ou até) n saltos, mas, se houver, indique isso claramente em sua resposta e certifique-se de que uma entrada de n=0 produza 1(ou, [1]se apropriado).

Como é , o objetivo é produzir o código de trabalho no menor número de bytes possível no idioma escolhido.

Nota: o GNU fica preso (bem como o cavaleiro em sua localização em , praça , e o camelo em sua localização em , praça ) em seu 12899744968 ^ {\ text {th}} localização no quadrado 12851850258 . O comportamento do seu código pode ser indefinido para n maior que isso. (Obrigado ao Deadcode pelo código C ++ que encontrou isso!)2016th20843723rd708112899744968th12851850258n

Detalhe

O quadro se parece com o abaixo e continua indefinidamente:

101 100  99  98  97  96  95  94  93  92  91
102  65  64  63  62  61  60  59  58  57  90
103  66  37  36  35  34  33  32  31  56  89
104  67  38  17  16  15  14  13  30  55  88
105  68  39  18   5   4   3  12  29  54  87
106  69  40  19   6   1   2  11  28  53  86
107  70  41  20   7   8   9  10  27  52  85
108  71  42  21  22  23  24  25  26  51  84
109  72  43  44  45  46  47  48  49  50  83
110  73  74  75  76  77  78  79  80  81  82
111 112 113 114 115 116 117 118 119 120 121

Um gnu é uma peça de xadrez de fada "gnu" - uma peça de xadrez não-padrão que pode se mover tanto como cavaleiro (um ) e como um camelo (um ). Como tal, ela poderia mudar para qualquer um desses locais a partir do local inicial :(1,2)( 1 , 3 ) 1(1,3)
1

  .   .   .   .   .   .   .   .   .   .   .
  .   .   .   .  35   .  33   .   .   .   .
  .   .   .   .  16   .  14   .   .   .   .
  .   .  39  18   .   .   .  12  29   .   .
  .   .   .   .   .  (1)  .   .   .   .   .
  .   .  41  20   .   .   .  10  27   .   .
  .   .   .   .  22   .  24   .   .   .   .
  .   .   .   .  45   .  47   .   .   .   .
  .   .   .   .   .   .   .   .   .   .   .

O mais baixo deles é e ela ainda não visitou esse quadrado; portanto, é o segundo termo na sequência.1010

Em seguida, ela poderia passar de para qualquer um desses locais:10

  .   .   .   .   .   .   .   .   .   .   .
  .   .   .   .   .   .  14   .  30   .   .
  .   .   .   .   .   .   3   .  29   .   .
  .   .   .   .   6   1   .   .   .  53  86
  .   .   .   .   .   .   . (10)  .   .   .
  .   .   .   .  22  23   .   .   .  51  84
  .   .   .   .   .   .  47   .  49   .   .
  .   .   .   .   .   .  78   .  80   .   .
  .   .   .   .   .   .   .   .   .   .   .

No entanto, ela já visitou a praça portanto, sua terceira localização é a praça , a mais baixa que ela ainda não visitou.13


Os primeiros termos do caminho do GNU são:100

1, 10, 3, 6, 9, 4, 7, 2, 5, 8, 11, 14, 18, 15, 12, 16, 19, 22, 41, 17, 33, 30, 34, 13, 27, 23, 20, 24, 44, 40, 21, 39, 36, 60, 31, 53, 26, 46, 25, 28, 32, 29, 51, 47, 75, 42, 45, 71, 74, 70, 38, 35, 59, 56, 86, 50, 78, 49, 52, 80, 83, 79, 115, 73, 107, 67, 64, 68, 37, 61, 93, 55, 58, 54, 84, 48, 76, 43, 69, 103, 63, 66, 62, 94, 57, 87, 125, 82, 118, 77, 113, 72, 106, 148, 65, 97, 137, 91, 129, 85

Os primeiros saltos são movimentos de cavaleiro, de modo que os primeiros termos coincidem com o A316667 .1112

Jonathan Allan
fonte
Comentários não são para discussão prolongada; esta conversa foi movida para o bate-papo .
Mego

Respostas:

21

JavaScript (Node.js) ,  191 ... 166  164 bytes

Economizou 2 bytes graças a @grimy .

Retorna o N º prazo.

n=>(g=(x,y)=>n--?g(Buffer('QPNP1O?O@242Q3C3').map(m=c=>g[i=4*((x+=c%6-2)*x>(y+=c%7-2)*y?x:y)**2,i-=(x>y||-1)*(i**.5+x+y)]|i>m||(H=x,V=y,m=i))&&H,V,g[m]=1):m+1)(1,2)

Experimente online! ou Veja uma versão formatada

Quão?

Índices espirais

Para converter as coordenadas (x,y) no índice espiral I , primeiro calculamos a camada eu com:

L=max(|x|,|y|)

Que dá:

3210+1+2+333333333232222231321112303210123+13211123+23222223+33333333

Em seguida, calculamos a posição na camada com:P

P={2L+x+yif x>y(2L+x+y)if xy

Que dá:

3210+1+2+330123456210123471210125803210369+143234710+254567811+3-6-7-8-9-10-11-12

O índice final é dado por:Eu

Eu=4eu2-P

NB: A fórmula acima fornece uma espiral indexada em 0.

No código JS, computamos imediatamente com:4eu2

i = 4 * (x * x > y * y ? x : y) ** 2

E subtraia com:P

i -= (x > y || -1) * (i ** 0.5 + x + y)

Movimentos do GNU

Dada a posição atual , os 16 quadrados-alvo possíveis do gnu são testados na seguinte ordem:(x,y)

-3-2-1x+1+2+3-3911-2810-1761213y+1541415+220 0+331

Nós os percorremos aplicando 16 pares de valores assinados . Cada par é codificado como um único caractere ASCII.(dx,dy)

 ID | char. | ASCII code | c%6-2 | c%7-2 | cumulated
----+-------+------------+-------+-------+-----------
  0 |  'Q'  |     81     |   +1  |   +2  |  (+1,+2)
  1 |  'P'  |     80     |    0  |   +1  |  (+1,+3)
  2 |  'N'  |     78     |   -2  |   -1  |  (-1,+2)
  3 |  'P'  |     80     |    0  |   +1  |  (-1,+3)
  4 |  '1'  |     49     |   -1  |   -2  |  (-2,+1)
  5 |  'O'  |     79     |   -1  |    0  |  (-3,+1)
  6 |  '?'  |     63     |   +1  |   -2  |  (-2,-1)
  7 |  'O'  |     79     |   -1  |    0  |  (-3,-1)
  8 |  '@'  |     64     |   +2  |   -1  |  (-1,-2)
  9 |  '2'  |     50     |    0  |   -1  |  (-1,-3)
 10 |  '4'  |     52     |   +2  |   +1  |  (+1,-2)
 11 |  '2'  |     50     |    0  |   -1  |  (+1,-3)
 12 |  'Q'  |     81     |   +1  |   +2  |  (+2,-1)
 13 |  '3'  |     51     |   +1  |    0  |  (+3,-1)
 14 |  'C'  |     67     |   -1  |   +2  |  (+2,+1)
 15 |  '3'  |     51     |   +1  |    0  |  (+3,+1)

Nós manter o controle do valor mínimo encontrado na e das coordenadas da célula correspondente em .m(H,V)

Uma vez encontrado o melhor candidato, o marcamos como visitado, definindo uma flag no objeto , que também é nossa principal função recursiva.g

Na primeira iteração, começamos com e . Isso garante que a primeira célula selecionada seja e que seja a primeira célula a ser marcada como visitada.x=1y=2(0 0,0 0)

Arnauld
fonte
3
Tanto golfe, mal posso esperar pelo resumo de como toda a magia funciona!
Jonathan Allan
você precisou usar Bufferpara forçar cada caractere a ser interpretado como um único byte?
Jonah
1
@ Jonah Embora tenha sido descontinuado, o Bufferconstrutor ainda aceita uma string. Portanto, sim, essa é uma maneira bastante barata de convertê-lo em uma lista de bytes - ao contrário de [..."string"].map(c=>do_something_with(c.charCodeAt())).
Arnauld
1
-2 bytes na codificação de coordenadas: TIO
Grimmy
@ Grimy Muito bem feito!
Arnauld
8

Coco , 337 276 bytes

import math
def g((x,y))=
 A=abs(abs(x)-abs(y))+abs(x)+abs(y)
 int(A**2+math.copysign(A+x-y,.5-x-y)+1)
def f():
 p=x,y=0,0;s={p};z=[2,3,1,1]*2
 while 1:yield g(p);p=x,y=min(((a+x,b+y)for a,b in zip((1,1,2,-2,-1,-1,3,-3)*2,z+[-v for v in z])if(a+x,b+y)not in s),key=g);s.add(p)

Retorna um gerador de valores. Provavelmente poderia ser jogado mais. (Especialmente a sequência de tuplos de diferença.) Algoritmo espiral feita de esta resposta math.se .

Experimente online!

Solomon Ucko
fonte
1
for a,b in (-> for a,b in((talvez você também possa jogar golfe na tupla delta das tuplas)
Jonathan Allan
1
Não há necessidade qe um zip é menor para as tuplas: é possível que 306 bytes ainda possam ser jogados, é claro
Jonathan Allan
1
... que tal isso para 284? EDIT ... isso para 278
Jonathan Allan
1
FWIW, essa resposta math.se tem x e y trocados e tanto negativa relativamente ao sistema de coordenadas neste desafio (se for positivo x é certo e y é para cima). Não que isso fizesse alguma diferença devido às simetrias, mas ainda assim.
Deadcode
1
0.5-> .5para outro byte salvo; A**2-> A*Apor mais um.
Jonathan Allan
8

05AB1E , 77 65 58 57 52 bytes

Xˆ0UF3D(Ÿ0KãʒÄ1¢}εX+}Dε·nàDtyÆ+yO·<.±*->}D¯KßDˆkèU}¯

-6 bytes graças a @Arnauld usando uma porta de sua fórmula.

n+1

Experimente on-line (o ïrodapé remove o .0para tornar a saída mais compacta, mas fique à vontade para removê-lo para ver o resultado real).

Explicação do código:

Xˆ             # Put integer 1 in the global_array (global_array is empty by default)
0U             # Set variable `X` to 0 (`X` is 1 by default)
F              # Loop the (implicit) input amount of times:
 3D          #  Push the list in the range [-3,3]: [-3,-2,-1,0,1,2,3]
     0K        #  Remove the 0: [-3,-2,-1,1,2,3]
       ã       #  Cartesian product with itself, creating each possible pair: [[3,3],[3,2],[3,1],[3,-1],[3,-2],[3,-3],[2,3],[2,2],[2,1],[2,-1],[2,-2],[2,-3],[1,3],[1,2],[1,1],[1,-1],[1,-2],[1,-3],[-1,3],[-1,2],[-1,1],[-1,-1],[-1,-2],[-1,-3],[-2,3],[-2,2],[-2,1],[-2,-1],[-2,-2],[-2,-3],[-3,3],[-3,2],[-3,1],[-3,-1],[-3,-2],[-3,-3]]
        ʒ   }  #  Filter this list of pairs by:
         Ä     #   Where the absolute values of the pair
          1¢   #   Contains exactly one 1
               #  (We now have the following pairs left: [[3,1],[3,-1],[2,1],[2,-1],[1,3],[1,2],[1,-2],[1,-3],[-1,3],[-1,2],[-1,-2],[-1,-3],[-2,1],[-2,-1],[-3,1],[-3,-1]])
 εX+}          #  Add the variable `X` (previous coordinate) to each item in the list
 D             #  Duplicate this list of coordinates
  ε            #  Map each `x,y`-coordinate to:
   ·           #   Double both the `x` and `y` in the coordinate
    n          #   Then take the square of each
     à         #   And then pop and push the maximum of the two
   Dt          #   Duplicate this maximum, and take its square-root
     yÆ        #   Calculate `x-y`
       +       #   And add it to the square-root
   yO          #   Calculate `x+y`
     ·         #   Double it
      <        #   Decrease it by 1
             #   And pop and push its signum (-1 if < 0; 0 if 0; 1 if > 0)
   *           #   Multiply these two together
    -          #   And subtract it from the duplicated maximum
   >           #   And finally increase it by 1 to make it 1-based instead of 0-based
  }D           #  After the map: Duplicate that list with values
    ¯K         #  Remove all values that are already present in the global_array
      ß        #  Pop the list of (remaining) values and push the minimum
       Dˆ      #  Duplicate this minimum, and pop and add the copy to the global_array
         k     #  Then get its index in the complete list of values
          è    #  And use that index to get the corresponding coordinate
           U   #  Pop and store this coordinate in variable `X` for the next iteration
             # After the outer loop: push the global_array (which is output implicitly)

Explicação geral:

global_array[1]
x,yX[0,0]

x,y

[[x+3,y+1], [x+3,y-1], [x+2,y+1], [x+2,y-1], [x+1,y+3], [x+1,y+2], [x+1,y-2], [x+1,y-3], [x-1,y+3], [x-1,y+2], [x-1,y-2], [x-1,y-3], [x-2,y+1], [x-2,y-1], [x-3,y+1], [x-3,y-1]]

x,yX

x,yx,y

T=mumax((2x)2,(2y)2)
R=T-(x-y+T)sEugnvocêm((x+y)2-1)+1

Qual é a mesma fórmula que @Arnauld está usando em sua resposta , mas escrita de forma diferente para usar os componentes internos do 05AB1E para duplo, quadrado, -1, +1, etc.

(Se você quiser ver apenas essa parte espiral do código em ação: experimente online .)

x,yglobal_array
global_arrayXx,y

Depois de repetir a inputquantidade de vezes, o programa produzirá isso global_arraycomo resultado.

Kevin Cruijssen
fonte
1
FWIW, aqui está uma porta de minha própria fórmula para converter as coordenadas em índices espirais. É 5 bytes mais curto, mas produz flutuadores. (Eu não sei se isso é um problema ou não.)
Arnauld
y-y
@ Arnauld Obrigado, isso economiza 5 bytes adicionais. :) EDIT: Que você já mencionou em seu primeiro comentário. ; p
Kevin Cruijssen 28/01