Mathematica: True Labyrinth (827 znaków)
Początkowo stworzyłem ścieżkę od {1,1,1} do {5,5,5}, ale ponieważ nie było żadnych możliwych złych zwrotów, wprowadziłem widelce lub „punkty decyzyjne” (wierzchołki stopnia> 2), w których trzeba by zdecydować, którą drogą iść. Rezultatem jest prawdziwy labirynt lub labirynt.
„Ślepe zaułki” były o wiele trudniejsze do rozwiązania niż znalezienie prostej, bezpośredniej ścieżki. Najtrudniejszą rzeczą było wyeliminowanie cykli na ścieżce, jednocześnie umożliwiając cykle poza ścieżką rozwiązania.
Poniższe dwa wiersze kodu są używane tylko do renderowania narysowanych wykresów, więc kod się nie liczy, ponieważ nie jest wykorzystywany w rozwiązaniu.
o = Sequence[VertexLabels -> "Name", ImagePadding -> 10, GraphHighlightStyle -> "Thick",
ImageSize -> 600];
o2 = Sequence[ImagePadding -> 10, GraphHighlightStyle -> "Thick", ImageSize -> 600];
Zastosowany kod:
e[c_] := Cases[EdgeList[GridGraph[ConstantArray[5, 3]]], j_ \[UndirectedEdge] k_ /; (MemberQ[c, j] && MemberQ[c, k])]
m[] :=
Module[{d = 5, v = {1, 125}},
While[\[Not] MatchQ[FindShortestPath[Graph[e[v]], 1, 125], {1, __, 125}],
v = Join[v, RandomSample[Complement[Range[125], v], 1]]];
Graph[e[Select[ConnectedComponents[Graph[e[v]]], MemberQ[#, 1] &][[1]]]]]
w[gr_, p_] := EdgeDelete[gr, EdgeList[PathGraph[p]]]
y[p_, u_] := Select[Intersection[#, p] & /@ ConnectedComponents[u], Length[#] > 1 &]
g = HighlightGraph[lab = m[], PathGraph[s = FindShortestPath[lab, 1, 125]],o]
u = w[g, s]
q = y[s, u]
While[y[s, u] != {}, u = EdgeDelete[u, Take[FindShortestPath[u, q[[1, r = RandomInteger[Length@q[[1]] - 2] + 1]],
q[[1, r + 1]]], 2] /. {{a_, b_} :> a \[UndirectedEdge] b}];
q = y[s, u]]
g = EdgeAdd[u, EdgeList@PathGraph[s]];
Partition[StringJoin /@ Partition[ReplacePart[Table["x", {125}],
Transpose[{VertexList[g], Table["o", {Length[VertexList@g]}]}]/. {{a_, b_} :> a -> b}], {5}], 5]
Próbka wyjściowa
{{„oxooo”, „xxooo”, „xoxxo”, „xoxxo”, „xxoox”}, {„ooxoo”, „xoooo”, „ooxox”, „oooxx”, „xooxx”}, {„oooxx”, „ooxxo”, „ooxox”, „xoxoo”, „xxxoo”}, {„oxxxx”, „oooox”, „xooox”, „xoxxx”, „oooxx”}, {„xxxxx”, „ooxox”, „oooox ”,„ xoxoo ”,„ oooxo ”}}
Pod maską
Poniższy obrazek pokazuje labirynt lub labirynt, który odpowiada rozwiązaniu ({{"ooxoo",...}}
przedstawionemu powyżej:
Oto ten sam labirynt wstawiony w 5x5x5 GridGraph
. Ponumerowane wierzchołki są węzłami na najkrótszej drodze z labiryntu. Zwróć uwagę na rozwidlenia lub punkty decyzyjne na 34, 64 i 114. Dołączę kod użyty do renderowania wykresu, nawet jeśli nie jest on częścią rozwiązania:
HighlightGraph[gg = GridGraph[ConstantArray[5, 3]], g,
GraphHighlightStyle ->"DehighlightFade",
VertexLabels -> Rule @@@ Transpose[{s, s}] ]
A ten wykres pokazuje tylko rozwiązanie labiryntu:
HighlightGraph[gg = GridGraph[ConstantArray[5, 3]],
Join[s, e[s]], GraphHighlightStyle -> "DehighlightFade", VertexLabels -> Rule @@@ Transpose[{s, s}] ]
Na koniec kilka definicji, które mogą pomóc w odczytaniu kodu:
Oryginalne rozwiązanie (432 znaków, wyprodukowano ścieżkę, ale nie prawdziwy labirynt lub labirynt)
Wyobraź sobie dużą solidną kostkę 5 x 5 x 5 złożoną z odrębnych kostek jednostkowych. Poniższe rozpoczyna się bez kostek jednostkowych w {1,1,1} i {5,5,5}, ponieważ wiemy, że muszą być częścią rozwiązania. Następnie usuwa losowe kostki, aż do uzyskania niezakłóconej ścieżki od {1,1,1} do {5,5,5}.
„Labirynt” jest najkrótszą ścieżką (jeśli możliwa jest więcej niż jedna), biorąc pod uwagę usunięte kostki jednostek.
d=5
v={1,d^3}
edges[g_,c_]:=Cases[g,j_\[UndirectedEdge] k_/;(MemberQ[c,j]&&MemberQ[c,k])]
g:=Graph[v,edges[EdgeList[GridGraph[ConstantArray[d,d]]],v]];
While[\[Not]FindShortestPath[g,1,d^3]!={},
v=Join[v,RandomSample[Complement[Range[d^3],v],1]]]
Partition[Partition[ReplacePart[
Table["x",{d^3}],Transpose[{FindShortestPath[g,1,d^3],Table["o",{Length[s]}]}]
/.{{a_,b_}:> a->b}],{d}]/.{a_,b_,c_,d_,e_}:> StringJoin[a,b,c,d,e],5]
Przykład:
{{"ooxxx", "xxxxx", "xxxxx", "xxxxx", "xxxxx"},
{"xoxxx", "xoooo", "xxxxo", "xxxxo", "xxxxo"},
{"xxxxx", "xxxxx", "xxxxx", "xxxxx", "xxxxo"},
{"xxxxx", "xxxxx", "xxxxx", "xxxxx", "xxxxo"},
{"xxxxx", "xxxxx", "xxxxx", "xxxxx", "xxxxo"}}
Technicznie nie jest to jeszcze prawdziwy labirynt, ponieważ nie ma żadnych złych zwrotów, które można wykonać. Ale pomyślałem, że to interesujące na początek, ponieważ opiera się na teorii grafów.
Rutyna faktycznie tworzy labirynt, ale podłączyłem wszystkie puste miejsca, które mogłyby powodować cykle. Jeśli znajdę sposób na usunięcie cykli, dołączę ten kod tutaj.