Mathematica: True Labyrinth (827 caratteri)
Inizialmente, ho prodotto un percorso da {1,1,1} a {5,5,5} ma poiché non c'erano possibili svolte sbagliate da fare, ho introdotto forchette o "punti di decisione" (vertici di grado> 2) in cui bisognerebbe decidere da che parte andare. Il risultato è un vero labirinto o labirinto.
I "vicoli ciechi" erano molto più difficili da risolvere che trovare un percorso semplice e diretto. La cosa più difficile è stata l'eliminazione dei cicli all'interno del percorso consentendo al contempo i cicli fuori dal percorso della soluzione.
Le seguenti due righe di codice vengono utilizzate solo per il rendering dei grafici disegnati, quindi il codice non conta, poiché non viene utilizzato nella soluzione.
o = Sequence[VertexLabels -> "Name", ImagePadding -> 10, GraphHighlightStyle -> "Thick",
ImageSize -> 600];
o2 = Sequence[ImagePadding -> 10, GraphHighlightStyle -> "Thick", ImageSize -> 600];
Codice utilizzato:
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]
Uscita campione
{{"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 "}}
Sotto il cappuccio
L'immagine seguente mostra il labirinto o labirinto che corrisponde alla soluzione ({{"ooxoo",...}}
visualizzata sopra:
Ecco lo stesso labirinto inserito in un 5x5x5 GridGraph
. I vertici numerati sono nodi sul percorso più breve fuori dal labirinto. Nota le forcelle oi punti di decisione in 34, 64 e 114. Includerò il codice utilizzato per il rendering del grafico anche se non fa parte della soluzione:
HighlightGraph[gg = GridGraph[ConstantArray[5, 3]], g,
GraphHighlightStyle ->"DehighlightFade",
VertexLabels -> Rule @@@ Transpose[{s, s}] ]
E questo grafico mostra solo la soluzione al labirinto:
HighlightGraph[gg = GridGraph[ConstantArray[5, 3]],
Join[s, e[s]], GraphHighlightStyle -> "DehighlightFade", VertexLabels -> Rule @@@ Transpose[{s, s}] ]
Infine, alcune definizioni che possono aiutare a leggere il codice:
Soluzione originale (432 caratteri, prodotto un percorso ma non un vero labirinto o labirinto)
Immagina un cubo solido 5x5x5 composto da cubi unità distinti. Quanto segue inizia senza cubetti unitari a {1,1,1} e {5,5,5}, poiché sappiamo che devono far parte della soluzione. Quindi rimuove i cubi casuali fino a quando non c'è un percorso senza ostacoli da {1,1,1} a {5,5,5}.
Il "labirinto" è il percorso più breve (se è possibile più di uno) dati i cubi unità che sono stati rimossi.
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]
Esempio:
{{"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"}}
Tecnicamente questo non è ancora un vero labirinto, poiché non ci sono svolte sbagliate che si possano fare. Ma ho pensato che fosse interessante come inizio poiché si basa sulla teoria dei grafi.
La routine in realtà crea un labirinto ma ho inserito tutte le posizioni vuote che potrebbero dare origine a cicli. Se trovo un modo per rimuovere i cicli, includerò questo codice qui.