Où le chevalier peut-il être dans N mouvements?

21

Il s'agit du trou 3 du tournoi d'automne d'APL CodeGolf . Je suis l'auteur original du problème là-bas, et donc autorisé à le publier à nouveau ici.


Donné:

  1. un certain nombre de tours (veuillez indiquer si aucun mouvement n'est égal à 0, sinon nous supposerons qu'il s'appelle 1) et

  2. une liste d'une ou plusieurs positions de départ (sous n'importe quelle forme, par exemple 0 ou 1 coordonnées indexées ou 64 nombres / caractères consécutifs ou A1 – H8 - indiquer laquelle), sur un échiquier de 8 par 8,

retourner (dans n'importe quel ordre) la liste des positions uniques (dans le même format que l'entrée) où le chevalier peut se trouver après le nombre de tours donné.

  • Chaque chevalier doit se déplacer à chaque tour, mais vous n'avez pas à vous soucier de plusieurs chevaliers occupant la même case.

  • Un chevalier ne peut se déplacer qu'aux positions marquées d'un X par rapport à sa position actuelle, marquées d'un ♞:
    où un chevalier peut se déplacer

Exemples (coordonnées indexées 1)

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

2se déplace de [[1,1]]: [[1,1],[1,3],[1,5],[2,4],[3,1],[3,5],[4,2],[4,4],[5,1],[5,3]]

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

2se déplace 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]]

0se déplace de [[3,4]]: [[3,4]]

Adam
la source
Les espaces d'échecs peuvent-ils être entrés et sortis en numérotant de 0 à 63 au lieu de [rang, fichier]?
Dave
@ Dave Bien sûr, pourquoi pas? Soyez simplement cohérent avec les E / S.
Adám
8
Je jure avoir lu ce HNQ comme "Où le chevalier se trouve dans les mouvements de Ni"
Sidney
3
Alerte au jeu de mots: la notation pour le chevalier est N.
Joshua
Peut-on utiliser une indexation basée sur 1 sur le nombre d'étapes? Par exemple[[1,1]], 2 -> [[2,3],[3,2]]
Zgarb

Réponses:

11

Wolfram Language (Mathematica) , 45 octets

Parce que l'autre solution est incorrecte (voir le commentaire de Martin ci-dessous), je décide donc de poster ma solution:

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

Essayez-le en ligne!

Notation infixe ultime ...

Prend 2 entrées, le premier est une liste de nombres dans la gamme [1,64]décrivant les positions de départ du chevalier, le second est le nombre de pas.

Cette solution repose sur l'extrême commodité des fonctions intégrées de Mathematica:

  • AdjacencyListpeut prendre une liste de sommets sur son côté droit, et retourner une liste de sommets adjacents à l'un de ceux-ci, les doublons déjà supprimés et triés .
  • KnightTourGraphest une fonction intégrée. Pas étonnant.
  • Nestprend les arguments dans l'ordre Nest[f, expr, n], que nous pouvons répartir ##sur son côté droit comme Nest[f, ##].
  • Et enfin, Mathematica analyse a~b~c~d~ecomme (a~b~c)~d~e, donc aucun crochet n'est nécessaire. Sans notation infixée et aplatie ##, ce serait le cas Nest[AdjacencyList[KnightTourGraph[8, 8], #] &, #, #2]&.
user202729
la source
1
Je ne pense pas qu'il y ait quelque chose de mal à déjouer une solution existante.
Adám
1
Est-ce que cela fonctionne avec plusieurs positions de départ?
Adám
Incroyable! Maintenant, je dois comprendre comment lire ceci ...
Dave
Ce serait probablement 17 octets dans le langage hypothétique du golf Mthmca.
Michael Stern
7

JavaScript (ES7), 99 octets

Format d'entrée / sortie: indices carrés dans [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

Cas de test

Cet extrait de code comprend deux fonctions d'assistance pour traduire à partir et vers le format fourni par l'OP.

Comment?

Un mouvement de (x, y) vers (X, Y) est un mouvement de chevalier valide si nous avons soit:

  • | xX | = 1 et | yY | = 2 , ou
  • | xX | = 2 et | yY | = 1

En mettant au carré au lieu d'utiliser des valeurs absolues, cela peut s'exprimer comme suit:

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

Parce que 1 et 4 sont les seuls carrés parfaits qui donnent 5 lorsque XOR sont ensemble, nous avons un mouvement de chevalier valide si:

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

Nous appliquons cette formule à chaque carré p = 8y + x sur le plateau et à chaque carré de chevalier P = 8Y + X pour déduire les nouveaux carrés cibles de chevalier possibles, et répétons récursivement ce processus n fois.

Arnauld
la source
5

Octave, 69 octets

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

Démo en ligne!

L'entrée / sortie est la configuration de la carte au début / fin en tant que matrice binaire 8 * 8.

Explication:

Pour les nétapes, répétez la dilatation morphologique de la planche avec le masque suivant:

01010
10001
00100
10001
01010
rahnema1
la source
5

Rétine , 147 102 octets

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

Essayez-le en ligne! Prend la saisie comme une planche de 8x8 :avec les chevaliers marqués avec Ns, avec un chiffre pour le nombre de tours sur la ligne suivante (cela n'a aucun sens d'avoir plus de 9 tours, mais si vous insistez, je peux le supporter pour un supplément octet). Notez que la sortie contient un espace blanc supplémentaire. Edit: 45 octets enregistrés grâce à @MartinEnder. Explication: La première étape convertit le nombre de tours en unaire, mais en utilisant des caractères de tabulation, afin qu'ils ne soient pas appariés plus tard par accident, tandis que la deuxième étape ajoute des espaces à droite du tableau pour empêcher les regex de s'enrouler le bord. La troisième étape remplace tous les Ns et :s qui sont à l'écart d'un chevalier Navec un ntandis que la quatrième étape supprime tout Ns restant , change lans à Ns et soustrait 1 du nombre de coups. Cela se répète jusqu'à ce que le nombre de coups soit nul.

Neil
la source
C'est très impressionnant. Certainement pas le bon outil pour le travail!
Adám
4

Gelée , 29 octets

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

Essayez-le en ligne!

Coordonnées indexées 0. Presque certain que ce n'est pas optimal.

-1 octet grâce à user202729

Explication

+þ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
la source
1
Gelée indexée 0?
Adám
1
@ Adám Rend le filtrage plus facile: P
HyperNeutrino
2
Je m'attends à ce que Jelly puisse le faire en moins de 15 octets, car le détenteur du record actuel dans APL le fait en 24 caractères.
Adám
Lorsque vous avez> = 3 $, il est probable que vous puissiez le déplacer vers le lien précédent et y revenir Ç.
user202729
@ user202729 Oh oui, merci.
HyperNeutrino
3

05AB1E , 27 25 octets

Merci à Emigna pour avoir économisé 2 octets!

Utilise des coordonnées indexées 1.

Code:

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

Utilise l' encodage 05AB1E . Essayez-le en ligne!

Explication:

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

Cela nous donne le tableau suivant:

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

Quels sont les deltas des mouvements du chevalier.

            δ+             #   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
la source
Vous pouvez utiliser •eĆ•SÍü‚au lieu de Ƶ‡4в2ô<D(«pour enregistrer 2 octets.
Emigna
@Emigna Ahh, c'est intelligent, merci!
Adnan
2

Python 3, 105 octets

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

Vous devez utiliser un lambda nommé pour la récursivité. Je ne sais pas si c'est disqualifiant. Passez dans les positions de départ en tant que liste de nombres carrés indexés 0. 0 compte comme aucun mouvement.

mypetlion
la source
2

Java (OpenJDK 8) , 124 octets

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

Essayez-le en ligne!

Format d'entrée / sortie

L'entrée / sortie est représentée sous forme de bits dans un long(64 bits): les bits définis signifient qu'un cheval est présent, les bits non définis signifient qu'il n'y a pas de cheval. Exemple:

// [[0, 0]]
0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000001L

Explications

(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édits

  • 19 octets économisés grâce à Nevay!
  • Réutilisé le (X-x)²+(Y-y)²==5tour d'Arnauld réponse JavaScript
  • 1 octet de plus enregistré grâce à Nevay dans le nouvel algorithme!
  • 7 octets de plus économisés grâce à Nevay à nouveau en passant de int[]à 64 bits long.
Olivier Grégoire
la source
1
169 octets:(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 octet:(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
Merci @Nevay! Ajouter du code pour supprimer les parenthèses / blocs est toujours bien! ;-)
Olivier Grégoire
1
-7 octets en remplaçant int[]par 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
A bientôt, je n'ai même pas pensé à faire ça! Beau travail, @Nevay ;-)
Olivier Grégoire
2

Gelée , 29 28 octets

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

Essayez-le en ligne!

Le nombre de tours passe par STDIN et les carrés sont un argument.

Cela lie la solution Jelly d'HyperNeutrino, mais avec une approche différente.

Battre maintenant @HyperNeutrino par 1 octet entier!

Toutes les suggestions pour supprimer certains octets sont souhaitées!

Lien 1 (l'échiquier)

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

Lien 2 (génération de déplacement)

“¦Ʋƈ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)

Lien 3 (vérification carrée)

ÇƓ¡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ý
la source
1

Husk , 18 octets

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

Utilise l'indexation 1 des carrés et des pas. Essayez-le en ligne!

Explication

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
la source
1

R , 145 183 134 octets

C'est le résultat de l'excellent golf de Giuseppe de mon algo initial pas trop golfique (voir commentaire ci-dessous)

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

Essayez-le en ligne!

L'entrée et la sortie sont basées sur 1 ... 64. Prend un vecteur de position en utilisant la notation 1 ... 64. Mappe à une notation 1: 576, c'est-à-dire une super-planche composée de neuf cartes. Dans cette notation, à chaque itération, chaque chevalier devrait pouvoir se déplacer de +/- 22,26,47,49 Retourner les positions futures dans la notation 1 ... 64, à l'exclusion de celles qui tombent du plateau central. L'exemple TIO affiche le résultat à l'aide d'une matrice 8x8.

NofP
la source
Cela semble échouer sur le premier cas de test (il renvoie 4 coordonnées au lieu de 2).
Zgarb
Merci de l'avoir signalé Zgarb, je pense que j'ai résolu le problème maintenant
NofP
154 octets
Giuseppe
ou 148 octets si vous le prenez en [0...63]notation à la place.
Giuseppe
1
134 octets , [1..64]pour entrée et sortie. +1, cependant, c'est une excellente réponse.
Giuseppe