Entkomme einem Schachbrett


23

Sie befinden sich auf einem Schachbrett, wie man es tut. Sie können den Ausgang sehen, aber er ist furchtbar weit weg und Sie möchten lieber nicht den ganzen Weg laufen. Zum Glück haben dir einige Einheimische eine Mitfahrgelegenheit angeboten. Ein Ritter, ein Turm, ein Bischof und ein König sind alle bereit, Sie an Ihr Ziel zu bringen, aber da dies ein Schachbrett ist, müssen sie sich auf dem Weg zu Ihrem Ziel an die Schachregeln halten. Sie möchten so schnell wie möglich hier raus, wessen Angebot nehmen Sie an?

Aufgabe

Wenn Sie ein beliebig geformtes und großes Schachbrett und zwei Punkte auf dem Schachbrett haben, geben Sie die Schachfigur aus, die sich in so wenigen Zügen wie möglich zwischen den beiden Positionen bewegen kann. Boards werden nicht unbedingt durchgehend sein, was bedeutet, dass es Lücken zwischen Abschnitten des Boards geben kann. Jede der vier Figuren (König, Turm, Ritter und Bischof) kann sich nach ihren Standardregeln im Schach bewegen. Die Dame und die Bauern wurden absichtlich aus dieser Herausforderung herausgenommen.

I / O

Sie können Eingaben in jedem vernünftigen Format und Ausgaben in jedem von Ihnen gewählten Format vornehmen. Ihre Eingabe und Ausgabe muss in sich konsistent sein. Wenn mehrere Teile in der gleichen Anzahl von Zügen zum Ziel gelangen können, müssen Sie alle Teile ausgeben, die in kürzester Zeit dort ankommen können. Wenn keines der vier Stücke es bis zum Ende schafft, können Sie etwas ausgeben, solange es sich von allen anderen möglichen Ausgaben unterscheidet. Dies kann das Ausgeben von nichts oder das Auslösen eines Fehlers beinhalten.

Testfälle

Ein Quadrat kennzeichnet den Startpunkt und ein Kreis kennzeichnet den Endpunkt.


Test 1

Bischof


Test 2

Ritter


Test 3

König


Test 4

Turm


Test 5

König, Ritter


Test 6

Keiner


Nett. Ich mag das, aber ist ein "beliebig geformtes und großes Schachbrett" nicht eine Einheit? Ich verstehe nicht wirklich, wie die Beispiele 2 und 6 dazu passen, da es sich anscheinend um zwei separate Bretter handelt, zwischen denen nur der Springer springen kann. Vielleicht fehlt mir etwas?
ElPedro

2
@ElPedro Sie sind immer noch ein einzelnes Board, es ist einfach kein durchgehendes Board. Teil beliebiger Form ist, dass die Platten nicht durchgehend sein können.
Wheat Wizard

Zum Beispiel 3, sollte es nicht "König, Königin" sein?
Kritixi Lithos

Danke @Wheat. Ich bin mir nicht sicher, ob das aus der Frage hervorgeht, aber ich verstehe es jetzt.
ElPedro

2
@KritixiLithos Um die Dinge interessant zu halten, gibt es keine Dame oder Bauer.
Wheat Wizard

Antworten:


8

Haskell , 447 439 437 432 Bytes

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

Rufen Sie mit g <board> <start> <end>dem <board> :: [(Int, Int)], <start> :: (Int, Int)und <end> :: (Int, Int). Gibt eine Liste zurück, die 1Ritter, 2Turm, 3Bischof und 4König enthält. Wenn keine Lösungen gefunden werden, läuft der Stapel ständig über (das zählt als Fehlerauslösung, oder?).

Inspiration aus Lyah die Kapitel über Monads- genommen (%)ist nur eine verallgemeinerte und golfed inMany, mit (&)entspricht (Control.Monad.<=<). Alles andere sollte mehr oder weniger selbsterklärend sein.

Dies kann wahrscheinlich viel mehr Golf gespielt werden, aber ich hatte jetzt genug Spaß.

Ungolfed:

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

Gute Verwendung der funktionalen Programmierung!
Wheat Wizard

5

Mathematica, 326 325 Bytes

Vielen Dank an masterX224 für den Hinweis auf eine Byte-Ersparnis!

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

Definiert eine Funktion fmit drei Argumenten: gist eine Liste von geordneten Paaren von Ganzzahlen, die die Karte darstellen, wund xgeordneten Paaren, die die Start- und Endquadrate darstellen. Die Ausgabe ist die Teilmenge von {b, k, n, r}(die jeweils Bischof, König, Ritter und Turm darstellt), die einen Pfad mit minimalen Bewegungen zwischen den beiden Feldern aufweist. Beispielsweise wird der dritte Testfall von aufgerufen f[{{0, 0}, {1, 1}, {1, 2}, {0, 3}}, {0, 0}, {0, 3}]und kehrt zurück {k}. Die letzten beiden Testfälle geben jeweils {k, n}und {}zurück.

Die Strategie besteht darin, die Quadrate der Tafel in Eckpunkte eines Graphen zu übersetzen, wobei die Kanten durch die Bewegungen der einzelnen Teile bestimmt werden, und dann integrierte Graphenroutinen zu verwenden.

Benutzerfreundlichere Version des Codes:

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

Select[g~Tuples~2, # - #2 & @@ # == dFindet in Zeile 3 alle geordneten Knotenpaare, deren Differenz der Vektor ist d; etransformiert dann jedes dieser geordneten Paare in eine ungerichtete Graphenkante. Dies aist eine Funktion, die Kanten zwischen allen Scheitelpunkten erstellt, die sich durch einen festen Vektor unterscheiden.

Das reicht zu definieren, in den Zeilen 4 und 5, die Königs Graph y@k(die die Vereinigung der Kanten durch die Vektoren erzeugt nimmt {1, 1}, {-1, 1}, {0, 1}, und {-1, 0}) und der Ritter des Diagramms y@n(was tut das gleiche mit {1, 2}, {2, 1}, {-2, 1}, und {-1, 2}).

Nimmt in Zeile 7 ConnectedComponents@a@#einen dieser Nachbargraphen und findet dann seine verbundenen Komponenten; Dies entspricht einer Gruppierung aller Liniensegmente von Scheitelpunkten in der angegebenen Richtung (damit ein Turm oder Läufer sie nicht einzeln durchlaufen muss). In e@t@#Zeile 6 werden dann Kanten zwischen jedes Paar von Scheitelpunkten in derselben verbundenen Komponente eingefügt, die dann Flattenzu einem einzelnen Diagramm zusammengefasst werden. Somit definieren die Linien 6 bis 8 den Turmgraphen y@rund den Bischofsgraphen y@b.

Schließlich wählen die Linien 9 bis 11 die Elemente aus {b, k, n, r}, die den kürzesten Weg zwischen den beiden Zielscheitelpunkten ergeben. FindShortestPathwird einen Fehler auslösen und unbewertet zurückgeben, wenn ein Zielscheitelpunkt nicht im Diagramm angezeigt wird (was passiert, wenn keine Kanten von ihm ausgehen). In diesen Fällen verwenden wir stattdessen die h@__ -> 0Rückgabe 0. Und das Fehlen eines Pfads zwischen gültigen Scheitelpunkten gibt eine Liste mit Längenangaben zurück 0. Min[z~Complement~{0}]Berechnet daher die Länge des kleinsten Pfads, der tatsächlich existiert, und ignoriert dabei die oben genannten fehlerhaften Fälle.


Gibt es einen Grund für ein doppeltes f im Funktionsnamen? oder ist es ein mathematica limit?
masterX244

oh, haha, nein, es ist eine mentale Grenze für mich :) Ich hatte bereits eine fin dieser Sitzung, aber ich hätte sie vor der Einreichung ändern sollen!
Greg Martin
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.