Onde o cavaleiro pode estar em N movimentos?

21

Este é o Buraco-3 do Torneio de Outono da APL CodeGolf . Eu sou o autor original do problema lá e, portanto, posso republicá-lo aqui.


Dado:

  1. um número de turnos (indique se nenhum movimento é 0, caso contrário, assumiremos que é chamado 1) e

  2. uma lista de uma ou mais posições iniciais (de qualquer forma, por exemplo, 0 ou 1 coordenada indexada ou 64 números / caracteres consecutivos ou A1 – H8 - indicar qual), em um tabuleiro de xadrez 8 por 8,

retornar (em qualquer ordem) a lista de posições únicas (no mesmo formato da entrada) em que os cavaleiros podem estar após o número determinado de turnos.

  • Cada cavaleiro deve se mover a cada turno, mas você não precisa se preocupar com vários cavaleiros que ocupam o mesmo quadrado.

  • Um cavaleiro só pode se mover para as posições marcadas com X em relação à sua posição atual, marcadas com ♞:
    onde um cavaleiro pode se mover

Exemplos (coordenadas 1-indexadas)

1mover de [[1,1]]: [[2,3],[3,2]]

2move de [[1,1]]: [[1,1],[1,3],[1,5],[2,4],[3,1],[3,5],[4,2],[4,4],[5,1],[5,3]]

1mover de [[1,1],[5,7]]: [[2,3],[3,2],[3,6],[3,8],[4,5],[6,5],[7,6],[7,8]]

2move de [[1,1],[5,7]]: [[1,1],[1,3],[1,5],[1,7],[2,4],[2,6],[2,8],[3,1],[3,3],[3,5],[3,7],[4,2],[4,4],[4,6],[4,8],[5,1],[5,3],[5,5],[5,7],[6,4],[6,6],[6,8],[7,3],[7,7],[8,4],[8,6],[8,8]]

0move de [[3,4]]: [[3,4]]

Adão
fonte
Os espaços de xadrez podem ser introduzidos e gerados pela numeração de 0 a 63 em vez de [classificação, arquivo]?
Dave
@ Dave Claro, por que não? Apenas seja consistente com a E / S.
Adám
8
Eu juro que eu ler este HNQ como "Onde o cavaleiro estar em movimentos Ni"
Sidney
3
Chamada de alerta: a notação para o cavaleiro é N.
Joshua
Podemos usar a indexação baseada em 1 no número de etapas? Por exemplo[[1,1]], 2 -> [[2,3],[3,2]]
Zgarb 18/10

Respostas:

11

Wolfram Language (Mathematica) , 45 bytes

Como a outra solução está incorreta (veja o comentário de Martin abaixo), eu decido postar minha solução:

8~KnightTourGraph~8~AdjacencyList~#&~Nest~##&

Experimente online!

Notação infix final ...

Toma 2 entradas, a primeira é uma lista de números no intervalo [1,64] descreve as posições iniciais do cavaleiro, a segunda é o número de etapas.

Esta solução depende da extrema conveniência das funções integradas do Mathematica:

  • AdjacencyListO may pode pegar uma lista de vértices no lado direito e retornar uma lista de vértices adjacentes a qualquer um deles, duplicatas já removidas e classificadas .
  • KnightTourGraphé um builtin. Não é surpresa.
  • Nestrecebe argumentos em ordem Nest[f, expr, n], os quais podemos dividir no ##lado direito como Nest[f, ##].
  • E, finalmente, o Mathematica analisa a~b~c~d~ecomo (a~b~c)~d~e, portanto, nenhum colchete é necessário. Sem notação infix e achatada ##, seria Nest[AdjacencyList[KnightTourGraph[8, 8], #] &, #, #2]&.
user202729
fonte
1
Não acho que haja algo errado em superar uma solução existente.
Adám
1
Isso funciona com várias posições iniciais?
Adám
Surpreendente! Agora eu preciso descobrir como ti ler este ...
Dave
Provavelmente seriam 17 bytes na hipotética linguagem de golfe Mthmca.
Michael Stern
7

JavaScript (ES7), 99 bytes

Formato de entrada / saída: índices dos quadrados em [0 ... 63] .

f=(a,n)=>n--?f([...Array(64).keys()].filter(p=>!a.every(P=>(p%8-P%8)**2^((p>>3)-(P>>3))**2^5)),n):a

Casos de teste

Esse snippet inclui duas funções auxiliares para converter de e para o formato fornecido pelo OP.

Quão?

Um movimento de (x, y) para (X, Y) é um movimento válido de cavaleiro se tivermos:

  • | xX | = 1 e | yY | = 2 ou
  • | xX | = 2 e | yY | = 1

Esquadrando em vez de usar valores absolutos, isso pode ser expresso como:

  • (xX) ² = 1 e (yY) ² = 4 , ou
  • (xX) ² = 4 e (yY) ² = 1

Porque 1 e 4 são os únicos quadrados perfeitos que dão 5 quando XOR estavam juntos, temos um movimento válido de cavaleiro se:

(xX) ² XOR (aa) ² XOR 5 = 0

Aplicamos esta fórmula a cada quadrado p = 8y + x no tabuleiro e a cada quadrado de cavaleiro P = 8Y + X para deduzir os novos possíveis quadrados alvo de cavaleiro e repetimos recursivamente esse processo n vezes.

Arnauld
fonte
5

Oitava, 69 bytes

function a=f(a,n,b=~a)for k=1:n;a=b&imdilate(a,de2bi(")0#0)"-31));end

Demo Online!

A entrada / saída é a configuração da placa no início / fim como uma matriz binária 8 * 8.

Explicação:

Para as netapas, repita a dilatação morfológica do quadro com a seguinte máscara:

01010
10001
00100
10001
01010
rahnema1
fonte
5

Retina , 147 102 bytes

.$
$*	
¶
 ¶
{s`((?<=N(....|.{11}|.{13})?.{7})|(?=.{8}(....|.{11}|.{13})?N))\S(?=.*	)
n
Ts`	Nn`_:N`.*¶	

Experimente online! Aceita entrada como um tabuleiro de 8x8 de :s com os cavaleiros marcados com Ns, com um dígito para o número de turnos na próxima linha (não faz sentido ter mais de 9 turnos, mas se você insistir, posso apoiá-lo por mais um byte). Observe que a saída contém espaço em branco adicional. Editar: salvou 45 bytes graças a @MartinEnder. Explicação: O primeiro estágio converte o número de turnos em unário, mas usando caracteres de tabulação, para que não sejam correspondidos posteriormente por acidente, enquanto o segundo estágio adiciona alguns espaços à direita do quadro para impedir que as expressões regulares se agrupem. A beira. A terceira etapa substitui todas as Ns e :s que são movimento de um cavaleiro longe de um Ncom umn enquanto que a quarta fase elimina quaisquer restantes Ns, muda ons para Ns e subtrai 1 da contagem de movimentos. Isso se repete até que a contagem de movimentos seja zero.

Neil
fonte
Isso é mais impressionante. Definitivamente não é a ferramenta certa para o trabalho!
Adám 18/10/19
4

Gelatina , 29 bytes

+þ1,2Œ!×þ1,-p`¤¤Ẏ¤Ẏ⁼%8$$ÐfQµ¡

Experimente online!

Coordenadas indexadas em 0. Quase certo que isso é subótimo.

-1 byte graças a user202729

Explicação

+þ1,2Œ!×þ1,-p`¤¤Ẏ¤Ẏ⁼%8$$ÐfQµ¡  Main Link
+þ                             Addition Table (all pairs using + as combining function) with
  1,2Œ!×þ1,-p`¤¤Ẏ¤             All knight moves:
  1,2                          [1, 2]
     Œ!                        All permutations ([1, 2], [2, 1])
       ×þ                      Product Table (all pairs using × as combining function) with
         1,-p`¤                [1, 1], [1, -1], [-1, 1], [-1, -1]
         1,-                   [1, -1]
            p`                 Cartestian Product with itself
               ¤               All knight moves (in a nested array) as a nilad
                Ẏ¤             Tighten (flatten once); all knight moves in a (semi-)flat array
                        Ðf     Keep elements where
                   ⁼%8$$       The element equals itself modulo 8 (discard all elements out of the range)
                          Q    Remove Duplicates
                           µ   Start new monadic chain (essentially, terminates previous chain)
                            ¡  Repeat n times; n is implicitly the second input (right argument)
HyperNeutrino
fonte
1
Geléia 0-indexada?
Adám 18/10/19
1
@ Adám Facilita a filtragem: P
HyperNeutrino 18/17
2
Espero que o Jelly consiga fazer isso em menos de 15 bytes, devido ao atual detentor de registro no APL em 24 caracteres.
Adám
Quando você tem> = 3 $, é provável que você possa movê-lo para o link anterior e consultar novamente Ç.
user202729
@ user202729 Ah, é verdade, obrigado.
HyperNeutrino
3

05AB1E , 27 25 bytes

Obrigado a Emigna por economizar 2 bytes!

Usa coordenadas indexadas em 1.

Código:

F•eĆ•SÍü‚Dí«δ+€`Ùʒ{`9‹*0›

Usa a codificação 05AB1E .Experimente online!

Explicação:

F                          # Do the following <input_1> times..
 •eĆ•SÍ                    #   Push [-1, -2, 1, 2, -1]
       ü‚                  #   Pairwise pairing: [[-1, -2], [-2, 1], [1, 2], [2, -1]]
         D                 #   Duplicate the array
          í                #   Reverse each element
           «               #   Concatenate to the previous array

Isso nos dá a seguinte matriz:

[[-1, -2], [-2, 1], [1, 2], [2, -1], [-2, -1], [1, -2], [2, 1], [-1, 2]]

Quais são os deltas dos movimentos do cavaleiro.

            δ+             #   Addition vectorized on both sides
              €`           #   Flatten each element
                Ù          #   Uniquify
                 ʒ         #   Keep elements which..
                  {`9‹     #     Has a maximum element smaller than 9
                      *0›  #     And a minimum element larger than 0
Adnan
fonte
Você pode usar em •eĆ•SÍü‚vez de Ƶ‡4в2ô<D(«salvar 2 bytes.
Emigna
@ Emigna Ahh, isso é inteligente, obrigado!
Adnan
2

Python 3, 105 bytes

p=lambda g,i:i and list(set(p([x+y for x in g for y in[6,10,15,17,-6,-10,-15,-17]if 0<=x+y<64],i-1)))or g

Tem que usar um lambda nomeado para a recursão. Não tenho certeza se isso é desqualificante. Passe nas posições iniciais como lista de números quadrados indexados em 0. 0 conta como nenhum movimento.

mypetlion
fonte
2

Java (OpenJDK 8) , 124 bytes

(m,p)->{for(;m-->0;)for(long a=p,i=p=0,j;i<64;i++)for(j=64;j-->0;)p|=(p=i%8-j%8)*p+(p=i/8-j/8)*p==5?(a>>i&1)<<j:0;return p;}

Experimente online!

Formato de entrada / saída

A entrada / saída é representada como bits em um long(64 bits): bits definidos significam que um cavalo está presente, bits não definidos significam nenhum cavalo. Exemplo:

// [[0, 0]]
0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000001L

Explicações

(m, p) -> {                          // Lambda. No currying because m and p are modified
 for(;m-->0;)                        // For each move
  for(long a=p,i=p=0,j;i<64;i++)     // Declare variables, move p to a, create a new p and loop on bits of a.
   for(j=64;j-->0;)                  // Loop on bits of p.
    p |=                             // Assign to p a value.
     (p=i%8-j%8)*p+(p=i/8-j/8)*p==5  // If i -> j is a valid horse move, see Arnauld's JavaScript answer for full explanations
      ? (a>>i&1)<<j                  // Assign the presence of the horse (i-th bit of a) to the resulting board (j-th bit of p).
      : 0;                           // Else it's not a valid horse move
 return p;
}

Créditos

  • 19 bytes salvos graças ao Nevay!
  • Reutilizou o (X-x)²+(Y-y)²==5truque da resposta JavaScript de Arnauld
  • Mais 1 byte salvo graças ao Nevay no novo algoritmo!
  • Mais 7 bytes salvos graças ao Nevay novamente, passando de int[]para 64 bits long.
Olivier Grégoire
fonte
1
169 bytes:(m,p)->{for(;m-->0;){int i=64,a[]=p,x,y,u[]={1,3,5,9,15,19,21,23};for(p=new int[i];i-->0;)for(int z:u)if((((x=i/8+z/5-2)|(y=i%8+z%5-2))&-8)==0)p[x*8+y]|=a[i];}return p;}
Nevay
1
-1 byte:(m,p)->{for(int i,j,a[],x;m-->0;)for(a=p,p=new int[i=64];i-->0;)for(j=64;j-->0;)p[j]|=(x=i%8-j%8)*x+(x=i/8-j/8)*x==5?a[i]:0;return p;}
Nevay 20/10
Obrigado @Nevay! Adicionar código para remover parênteses / blocos é sempre bom! ;-)
Olivier Grégoire
1
-7 bytes substituindo int[]por long:(m,p)->{for(long i,j,a;m-->0;)for(a=p,p=i=0;i<64;i++)for(j=64;j-->0;)p|=(p=i%8-j%8)*p+(p=i/8-j/8)*p==5?(a>>i&1)<<j:0;return p;}
Nevay 21/10
Saúde, eu nem pensei em fazer isso! Bom trabalho, @Nevay ;-)
Olivier Grégoire
2

Geléia , 29 28 bytes

8Rp`
“¦Ʋƈ2’D_2ṡ2+€µẎ
ÇƓ¡f1£Q

Experimente online!

O número de turnos ocorre no STDIN e o quadrado é um argumento.

Isso vincula a solução Jelly da @ HyperNeutrino, mas com uma abordagem diferente.

Agora, batendo @HyperNeutrino por 1 byte inteiro!

São necessárias sugestões para eliminar alguns bytes!

Link 1 (O tabuleiro de xadrez)

8Rp`
8R   = The list [1,2,3,4,5,6,7,8]
  p` = cartesian multiplied with itself (this results in the chessboard)

Link 2 (geração de movimento)

“¦Ʋƈ2’D_2ṡ2+€µẎ
“¦Ʋƈ2’          = the number 103414301
      D         = converted into a list of digits
       _2       = subtract two from each element
         ṡ2     = overlapping pairs
           +€   = add to the list of squares
             µ  = Make sure the next part isn't treated as a right argument
              Ẏ = Tighten the list (Reducing the depth by one)

Link 3 (verificação quadrada)

ÇƓ¡f1£Q
ÇƓ¡     = Repeat link #2 the requested amount of times
   f1£  = Remove everything not a member of link #1 (not on the chess board)
      Q = Make sure squares don't appear more than once
Zacharý
fonte
1

Casca , 18 bytes

u!¡ṁö`fΠR2ḣ8=5ṁ□z-

Usa indexação baseada em 1 de quadrados e etapas. Experimente online!

Explicação

u!¡ṁö`fΠR2ḣ8=5ṁ□z-  Implicit inputs, say P=[[1,1],[5,7]] and n=2
  ¡                 Iterate on P:
   ṁö               Map the following function, then concatenate:
                     Argument is a pair, say p=[5,7].
          ḣ8         The range [1,2,..,8]
       ΠR2           Repeat twice, take cartesian product: [[1,1],[1,2],..,[8,8]]
     `f              Filter with this predicate:
                      Argument is a pair, say q=[3,8].
                z-    Zip p and q with difference: [-2,1]
              ṁ□      Sum of squares: 5
            =5        Is it 5? Yes, so [3,8] is kept.
 !                  Take n'th step of the iteration.
u                   Remove duplicates, implicitly print.
Zgarb
fonte
1

R , 145 183 134 bytes

Este é o resultado do excelente jogo de golfe de Giuseppe do meu algo inicial não muito golfe (veja o comentário abaixo)

function(x,n){x=x%/%8*24+x%%8
t=c(49,47,26,22)
t=c(t,-t)
for(i in 1:n)x=intersect(v<-outer(1:8,0:7*24,"+"),outer(x,t,"+"))
match(x,v)}

Experimente online!

A entrada e a saída são baseadas em 1 ... 64. Toma um vetor de posição usando a notação 1 ... 64. Mapeia para uma notação 1: 576, que é uma super placa composta por nove placas. Nesta notação, a cada iteração, cada cavaleiro deve ser capaz de se mover em +/- 22,26,47,49 Retorne as posições futuras na notação 1 ... 64, excluindo as que caem do quadro central. O exemplo TIO exibe o resultado usando uma matriz 8x8.

NofP
fonte
Isso parece falhar no primeiro caso de teste (ele retorna 4 coordenadas em vez de 2).
Zgarb 19/10/19
Obrigado por apontar o Zgarb, acho que resolvi o problema agora
NofP
154 bytes
Giuseppe
ou 148 bytes, se você o levar[0...63] .
21717 Giuseppe
1
134 bytes , [1..64]para entrada e saída. +1, porém, é uma excelente resposta.
Giuseppe