Échapper à un échiquier


23

Vous vous retrouvez sur un échiquier, comme on le fait. Vous pouvez voir la sortie mais elle est terriblement loin et vous préférez ne pas marcher tout le chemin. Heureusement, certains habitants vous ont proposé un tour. Un chevalier, une tour, un évêque et un roi sont tous prêts à vous emmener à votre destination, mais voyant comment c'est un échiquier, ils doivent chacun respecter les règles des échecs sur le chemin de votre destination. Vous souhaitez sortir d'ici le plus tôt possible, quelle offre acceptez-vous?

Tâche

Étant donné un échiquier de forme et de taille arbitraires et deux points sur l'échiquier, sortez la pièce d'échecs qui peut se déplacer entre les deux emplacements en aussi peu de mouvements que possible. Les conseils ne seront pas nécessairement continus, ce qui signifie qu'il pourrait y avoir des écarts entre les sections du conseil. Chacune des quatre pièces (roi, tour, chevalier et évêque) peut se déplacer selon ses règles standard aux échecs. Les pièces de la Reine et du pion ont été intentionnellement exclues de ce défi.

E / S

Vous pouvez prendre des entrées dans n'importe quel format raisonnable et vous pouvez également produire dans n'importe quel format que vous choisissez. Vos entrées et sorties doivent être cohérentes. Si plusieurs pièces peuvent arriver à destination dans le même nombre de coups, vous devez sortir toutes les pièces qui peuvent y arriver en un minimum de temps. Si aucune des quatre pièces ne parvient à la fin, vous pouvez produire n'importe quoi tant qu'il est distinct de toutes les autres sorties possibles. Cela peut inclure la sortie de rien ou le lancement d'une erreur.

Cas de test

Un carré indique le point de départ et un cercle indique le point d'arrivée.


Test 1

Évêque


Test 2

Chevalier


Test 3

Roi


Test 4

Tour


Test 5

Roi, chevalier


Test 6

Aucun


Agréable. J'aime ça, mais un "échiquier de forme et de taille arbitraires" n'est-il pas une entité unique? Je ne vois pas vraiment comment les exemples 2 et 6 s'intègrent à cela, car il semble que ce soient deux planches distinctes que seul le chevalier peut sauter. Peut-être que je manque quelque chose?
ElPedro

2
@ElPedro Ils sont toujours une seule carte, ce n'est tout simplement pas une carte continue. Une partie de la forme arbitraire est que les planches peuvent être non continues.
Wheat Wizard

Par exemple 3, ne devrait-il pas s'agir de "roi, reine"?
Kritixi Lithos

Merci @Wheat. Je ne sais pas si cela ressortait clairement de la question, mais je comprends maintenant.
ElPedro

2
@KritixiLithos Pour garder les choses intéressantes, il n'y a ni reine ni pion.
Wheat Wizard

Réponses:


8

Haskell , 447 439 437 432 octets

t=[1,2]
p=[(+),(-)]
f=filter
a=abs
(#)=elem
x?y=[min x y..max x y]
f&g=(\x->g x>>=f)
(b!1)(c,r)=f(#b)[(c!d,r#s)|(!)<-p,(#)<-p,d<-t,s<-t,d/=s]
(b!2)(c,r)=f(\(d,s)->(c==d&&all(#b)[(c,z)|z<-r?s])||r==s&&all(#b)[(z,r)|z<-c?d])b
(b!3)(c,r)=f(\(d,s)->a(c-d)==a(r-s)&&all(#b)(zip(c?d)$r?s))b
(b!4)(c,r)=f(\(d,s)->a(c-d)<2&&a(r-s)<2)b
(b%p)n s=[s]>>=foldr(&)(:[])(replicate n$b!p)
g b s e=head$f(not.null)[[p|p<-[1..4],e#(b%p)n s]|n<-[0..]]

Appel à l' aide g <board> <start> <end><board> :: [(Int, Int)], <start> :: (Int, Int)et <end> :: (Int, Int). Renvoie une liste contenant 1Knight, 2Rook, 3Bishop et 4King. Si aucune solution n'est trouvée, elle déborde systématiquement la pile (cela compte comme une erreur, non?).

L'inspiration tirée des chapitres de LYAH sur les monades - (%)est juste un généralisé et golfé inMany, avec l' (&)équivalent de (Control.Monad.<=<). Tout le reste devrait être plus ou moins explicite.

Cela peut probablement être joué beaucoup plus, mais je me suis assez amusé pour l'instant.

Non golfé:

data Piece = Knight | Rook | Bishop | King deriving (Show)
type Place = (Int, Int)
type Board = [Place]

x `to` y = [min x y..max x y]

f <=< g = (\x -> g x >>= f)

moves
    :: Board    -- available spaces
    -> Piece    -- type of piece
    -> Place    -- starting place
    -> [Place]  -- places available in one move
moves b Knight (c,r) =
    filter (`elem` b) [(c!d, r#s) |
                       (!) <- [(+),(-)], (#) <- [(+),(-)],
                       d <- [1,2], s <- [1,2], d/=s]
moves b Rook   (c,r) =
    filter (\(d,s) -> (c == d && all (`elem` b) [(c,z) | z <- r `to` s])
                    || r == s && all (`elem` b) [(z,r) | z <- c `to` d]) b
moves b Bishop (c,r) =
    filter (\(d,s) -> abs(c-d) == abs(r-s)
                && all (`elem` b) (zip (c `to` d) (r `to` s))) b
moves b King   (c,r) =
    filter (\(d,s) -> abs(c-d) <= 1 && abs(r-s) <= 1) b

canGoIn
    :: Board    -- available spaces
    -> Piece    -- type of piece
    -> Int      -- number of moves
    -> Place    -- starting place
    -> [Place]  -- places available in the specified number of moves
canGoIn b p n s =
    return s >>= foldr (<=<) return (replicate n (moves b p))

quickestPieces
    :: Board    -- available spaces
    -> Place    -- starting place
    -> Place    -- ending place
    -> [Piece]  -- quickest pieces
quickestPieces b s e =
        head $ filter (not.null)
            [[p | p <- [Knight, Rook, Bishop, King], elem e (canGoIn b p n s)] |
                n<-[0..]]

Belle utilisation de la programmation fonctionnelle!
Wheat Wizard

5

Mathematica, 326 325 octets

Merci à masterX224 pour avoir souligné une économie d'octets!

f[g_,w_,x_]:=(c={{1,1},{-1,1}};s=c.c/2;e=#<->#2&@@@#&;j=Join;h=FindShortestPath;t=#~Tuples~2&;a@d_:=e@Select[t@g,#-#2&@@#==d&];y@k=j@@(a/@j[s,c]);y@n=j@@(a/@{{1,2},{2,1},{-2,1},{-1,2}});v=Flatten[e@t@#&/@ConnectedComponents@a@#&/@#]&;y@r=v@s;y@b=v@c;Pick[p={b,k,n,r},z=Length[h[y@#,w,x]/.h@__->0]&/@p,Min[z~Complement~{0}]]);

Définit une fonction fprenant trois arguments: gest une liste de paires ordonnées d'entiers représentant la carte et wet de xpaires ordonnées représentant les carrés de début et de fin. La sortie est le sous-ensemble de {b, k, n, r}(représentant l'évêque, le roi, le chevalier et la tour, respectivement) qui a un chemin de mouvements minimaux entre les deux carrés. Par exemple, le troisième cas de test est invoqué par f[{{0, 0}, {1, 1}, {1, 2}, {0, 3}}, {0, 0}, {0, 3}]et retourne {k}; les deux derniers cas de test renvoient {k, n}et {}, respectivement.

La stratégie consiste à traduire les carrés de la planche en sommets d'un graphique, où les bords sont déterminés par les mouvements de chaque pièce, puis à utiliser des routines graphiques intégrées.

Version plus conviviale du code:

 1  f[g_, w_, x_] := ( c = {{1, 1}, {-1, 1}}; s = c.c/2;
 2    e = # <-> #2 & @@@ # &; j = Join; h = FindShortestPath; t = #~Tuples~2 &; 
 3    a@d_ := e@Select[t@g, # - #2 & @@ # == d &]; 
 4    y@k = j @@ (a /@ j[s, c]); 
 5    y@n = j @@ (a /@ {{1, 2}, {2, 1}, {-2, 1}, {-1, 2}}); 
 6    v = Flatten[e@t@# & /@
 7         ConnectedComponents@a@# & /@ #] &;
 8    y@r = v@s; y@b = v@c; 
 9    Pick[p = {b, k, n, r}, 
10      z = Length[h[y@#, w, x] /. h@__ -> 0] & /@ p, 
11      Min[z~Complement~{0}]]
12  );

À la ligne 3, Select[g~Tuples~2, # - #2 & @@ # == dtrouve toutes les paires de sommets ordonnés dont la différence est le vecteur d; etransforme ensuite chacune de ces paires ordonnées en un bord de graphe non orienté. Il en ava de même pour une fonction qui crée des arêtes entre tous les sommets qui diffèrent par un vecteur fixe.

Cela suffit à définir, dans les lignes 4 et 5, le graphe du roi y@k(qui prend l'union des bords générés par les vecteurs {1, 1}, {-1, 1}, {0, 1}et {-1, 0}) et le graphique du chevalier y@n(qui fait la même chose avec {1, 2}, {2, 1}, {-2, 1}et {-1, 2}).

À la ligne 7, ConnectedComponents@a@#prend l'un de ces graphiques voisins et trouve ensuite ses composants connectés; cela correspond au regroupement de tous les segments de ligne des sommets dans la direction donnée (de sorte qu'une tour ou un évêque n'a pas à les parcourir un par un). La e@t@#ligne 6 place ensuite les arêtes entre chaque paire de sommets dans le même composant connecté, qui sont ensuite Flattenéditées dans un seul graphique. Ainsi, les lignes 6 à 8 définissent le graphique de la tour y@ret le graphique de l'évêque y@b.

Enfin, les lignes 9 à 11 choisissent les éléments {b, k, n, r}qui donnent le chemin le plus court entre les deux sommets cibles. FindShortestPathrenverra une erreur et retournera non évalué si un sommet cible n'apparaît pas dans le graphique (ce qui se produira si aucun bord n'en émane), nous utilisons h@__ -> 0donc 0plutôt le retour dans ces cas. Et l'absence de chemin entre les sommets valides renvoie une liste de longueur 0, donc Min[z~Complement~{0}]calcule la longueur du plus petit chemin qui existe réellement, en ignorant les mauvais cas ci-dessus.


une raison pour le double f dans le nom de la fonction? ou est-ce une limite mathématique?
masterX244

oh, haha, non c'est une limite mentale de ma part :) J'en avais déjà une fdans cette session, mais j'aurais dû la changer avant la soumission!
Greg Martin
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.