Mathematica, 326 325 bajtów
Dzięki masterX224 za wskazanie oszczędności bajtów!
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}]]);
Definiuje funkcję f
przyjmującą trzy argumenty: g
jest listą uporządkowanych par liczb całkowitych reprezentujących tablicę w
oraz x
uporządkowanych par reprezentujących kwadraty początkowy i końcowy. Wyjściem jest podzbiór {b, k, n, r}
(reprezentujący odpowiednio biskupa, króla, rycerza i wieżę), które mają ścieżkę minimalnego ruchu między dwoma kwadratami. Na przykład trzeci przypadek testowy jest wywoływany przez f[{{0, 0}, {1, 1}, {1, 2}, {0, 3}}, {0, 0}, {0, 3}]
i zwraca {k}
; dwa ostatnie przypadki testowe wrócić {k, n}
i {}
odpowiednio.
Strategią jest przełożenie kwadratów planszy na wierzchołki wykresu, gdzie krawędzie są określane przez ruchy każdego elementu, a następnie użycie wbudowanych procedur graficznych.
Bardziej przyjazna dla użytkownika wersja kodu:
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 );
W linii 3 Select[g~Tuples~2, # - #2 & @@ # == d
znajduje wszystkie uporządkowane pary wierzchołków, których różnicą jest wektor d
; e
następnie przekształca każdą taką uporządkowaną parę w niekierowaną krawędź wykresu. Tak więc a
jest funkcja, która tworzy krawędzie między wszystkimi wierzchołkami, które różnią się stałym wektorem.
To wystarcza do zdefiniowania, w linii 4 i 5, wykres króla y@k
(co ma związek krawędzi uzyskanych przez wektory {1, 1}
, {-1, 1}
, {0, 1}
i {-1, 0}
) oraz wykresu rycerskiej y@n
(która ma to samo z {1, 2}
, {2, 1}
, {-2, 1}
i {-1, 2}
).
W linii 7 ConnectedComponents@a@#
pobiera jeden z tych sąsiednich wykresów, a następnie wyszukuje połączone elementy; odpowiada to zgrupowaniu wszystkich segmentów linii wierzchołków w danym kierunku (tak, aby wieża lub biskup nie musieli się przez nie przemieszczać jeden po drugim). Następnie e@t@#
w linii 6 umieszcza krawędzie między każdą parą wierzchołków w tym samym połączonym składniku, które są następnie Flatten
edytowane w pojedynczy wykres. Zatem linie od 6 do 8 definiują wykres wieży i wykres y@r
biskupa y@b
.
Wreszcie linie od 9 do 11 wybierają elementy, {b, k, n, r}
które dają najkrótszą ścieżkę między dwoma docelowymi wierzchołkami. FindShortestPath
wyrzuci błąd i zwróci nieoceniony, jeśli wierzchołek docelowy nie pojawi się na wykresie (co się stanie, jeśli z niego nie wyprowadzą się żadne krawędzie), więc zamiast tego używamy h@__ -> 0
powrotu 0
. Brak ścieżki między prawidłowymi wierzchołkami zwraca listę długości 0
, więc Min[z~Complement~{0}]
oblicza długość najmniejszej ścieżki, która faktycznie istnieje, ignorując powyższe niepoprawne przypadki.