Mein Roguelike erzeugt eine Reihe von runden Räumen. Ich mag die aktuellen Ergebnisse, die ungefähr so aussehen:
Es wird erzeugt, indem zufällige Kreise in einem gefüllten Raum herausgeschnitten werden.
Ich habe ein Hauptproblem damit: Mehrere Kreise sind völlig unverbunden. Ich kann nicht genau herausfinden, welchen Algorithmus ich verwenden soll, um sie zu verbinden.
Ich habe versucht, "für jeden Kreis den nächsten Kreis zu finden und in seine Mitte zu tunneln (horizontal und dann vertikal)", aber ich bekomme stattdessen etwas Schreckliches (dieselbe Karte wie oben):
Was die richtige Passform zu sein scheint, ist so etwas wie "Finden Sie für jeden geschlossenen Raum den nächsten leeren Raum und tunneln Sie ihn an." Das scheint jedoch komplex zu sein (berechnen Sie für jeden kreisförmigen geschlossenen Raum die Entfernung zu jedem anderen Raum) und wird wahrscheinlich langsam sein (läuft auch auf Ruby)
Gibt es eine einfache Lösung für dieses Problem?
quelle
Antworten:
In Ordung. Für dieses Problem gibt es eine recht rechnerisch kostengünstige Lösung. Verwenden Sie zuerst Union Find , um Räume zu verfolgen, die noch nicht verbunden sind.
Jedes Quadrat gehört jetzt zu einem Satz mit einem eindeutigen Index.
epsilon
0,0001. Alle anderen Räume (leere Räume) werden mit einer freien Kante mit einem virtuellen Zielknoten verbunden.quelle
Arthurs Antwort scheint Ihr Problem zu lösen, aber hier ist ein einfacher Ansatz:
Beachten Sie, dass Sie bei jeder Wiederholung nur das vorherige BFS fortsetzen müssen. Ich meine, ein Neustart des Algorithmus von Anfang an verringert nur Ihre Leistung und führt zu keinen besseren Ergebnissen.
quelle
bfs
und nur von den aktuellen Außenwänden des Perimeters aus neu starten, garantiert dies nicht, dass die kürzesten Wege zwischen offenen Bereichen genommen werden. Davon abgesehen sollte es ziemlich gleich funktionieren und die Lösung und ihre Komplexität vereinfachen.Wenn Sie noch eine einfachere Lösung wünschen, da die Räume einfach und kreisförmig sind, können Sie dies stattdessen tun:
visited
Räume hinzu.unvisited
Räume enthält, und suchen Sie den nächstgelegenenunvisited
Raum. Wenn der Abstand zwischen ihnen kleiner als die Summe ihrer Radien ist, gibt es wahrscheinlich keinen Grund, sie zu verbinden, aber auf jeden Fall einen Korridor mit einer nicht geraden Linie zwischen ihren Zentren zu "zeichnen" (ich werde den Algorithmus später beschreiben).unvisted
und finden Sie dasjenige, das einem von denen amvisited
nächsten ist.min [(xu-xv)^2 + (yu-yv)^2]
.visited
, entfernen Sie ihn aus demunvisited
und wiederholen Sie den Vorgang, bis alle Räumevisited
erfolgreich sind.Dies sollte mit einer Karte funktionieren, die weniger als hundert Räume hat, aber in vielerlei Hinsicht in der Recheneffizienz verbessert werden könnte (die für die Frage irrelevant sind).
Verwenden Sie den folgenden Pseudo-Algorithmus, um eine nicht gerade Linie zu zeichnen:
Der Code wurde von hier übernommen
quelle
Leider erwiesen sich beide Lösungen von Arthur für mich nicht als brauchbar. Es kam zu einem Problem, das lösbar ist, aber nicht schnell genug lief (es dauerte eine Größenordnung von Sekunden, bis es lief; ich brauche etwas fast augenblickliches).
Dies ist vielleicht meine Schuld, weil ich nicht alles genau so implementiert habe, wie er es vorgeschlagen hatte, sondern stattdessen einfacheren Code (über schnelleren Code) gewählt habe.
Trotzdem habe ich eine einfache Lösung gefunden, die schnell ausgeführt und einfach zu codieren ist. Die Hauptschritte sind:
Dies ist kein minimaler Spanning Tree, daher gibt es Fälle, in denen die Reihenfolge wichtig ist. Ich iteriere Räume in der falschen Reihenfolge und verbinde sie am Ende auf längere Weise anstatt auf kürzere Weise.
Für mein Spiel und meine Anforderungen hat dies funktioniert. In Zukunft kann ich es erweitern, indem ich stattdessen einen minimalen Spannbaum verwende.
Für die Nachwelt ist hier derselbe Boden, der mit meiner Lösung erzeugt wurde.
Sie können einen Schnappschuss des Kerncodes auf GitHub sehen, beginnend hier .
quelle