web-dev-qa-db-ja.com

行き止まりのない迷路生成のアルゴリズム?

行き止まりがなく、開始と終了のみの迷路を生成できる迷路生成アルゴリズムを探しています。このような:

maze

http://www.astrolog.org/labyrnth/maze/unicursl.gif からの画像

そのような迷路生成アルゴリズムをどこで見つけたり、構築したりできますか?

35
Fejuto

疑似ランダム空間充填曲線が必要なようです(たとえば、コンテキストベースの空間充填曲線-EUROGRAPHICS '20(PDF形式、 1.1 MB))

空間充填曲線を見てください。

これらのいずれかの構築にランダム性を適用して、目的を達成できると思います。

17
Ian Mercer

私は完全に黒い(完全な)正方形から始めて、道を掘ろうとすると思います。掘削中は、行き止まりがないことを簡単に確認できます。続行するだけです。バックトラッキング、深さ優先探索アルゴリズムを使用します。 「ランダムウォーク」を実行します。各ステップで、方向を維持するか変更するかをランダムに決定します。行き止まりの状態を確認します。行き詰まった場合は、「まあ、完了しました。終了しました」と言うか、迷路がまだ十分に掘られていないと考える場合は、バックトラックします。以前に行ったことを常に覚えて、他のアクションをランダムに試してください。おそらく、ヒューリスティックを使用して特定の方向を優先します。たとえば、壁をかわす前に常に空きスペースを確保し、最初に壁を歩き回ってみてください。このようにして、すべての正方形をはるかにすばやく埋める目的のソリューションを見つけることができます。

5
TMS

私は別の方法を見つけたと思いますが、まだ広範囲にテストしていません。

https://Twitter.com/tdhooper/status/340853820584230915/photo/1 を参照してください。

左から右へ:

  • ここで説明されているように、非ユニカーサル迷路を生成します https://en.wikipedia.org/wiki/File:Prim_Maze.svg 、これはプリムのアルゴリズムだと思います

  • 出口を密閉する

  • 迷路のすべてのポイントを訪れるパスを描きます(つまり、それを解決しようとします)

  • この道を壁にする

4
Thomas Hooper

ああ-私は一筆書きの迷路を生成するはるかに簡単な方法を見つけました。

空白のグリッドから始めて、小さな2x2ループで埋めます。グリッドが奇数×偶数の場合は、2x3のループをいくつか混ぜる必要があり、奇数×奇数の場合は、1つの正方形を空けておく必要があります。通常、コーナーは埋められません。

次に、ループを任意に結合して、より大きなループを形成します。たとえば、2つの2x2ループが1つの4x2ループになります。ループに参加して自分自身に戻らないように注意しながら、これを続けてください。

最終的には、ループの元のファームによって占有されているすべてのセルを使い果たす単一のループになります。このループを任意の位置で壊すと、開始位置と終了位置が隣り合っている一筆書きの迷路ができます。

これで、小さなループを形成して分割することにより、グリッドの周りで端点を移動できます-端を迷路の別の点に引っ掛けてから、反対側のTジャンクションを切断して、単一のストリングを新しいもので再形成します終了位置。

奇妙な迷路で作業している場合は、この最後のテクニックを使用して、片方の端を塗りつぶされていないコーナーにワームして、迷路を完成させます。

2
Nick

私はこれを考え抜いたことはなく、ただのアイデアです。

  • 道ではなく壁に集中する
  • 黒い外側の正方形だけから始めます
  • 壁のブロックを既存の壁のブロックに隣接する任意の位置に徐々に追加し、最初から最後までパスが残っている状態を維持します
  • パスセルに3つ以上のパスネイバーがない場合は、これで完了です。

壁の新しいビットの「任意の」選択プロセスは、外壁に垂直な直線部分を「成長」させようとすることから始まり、ある段階で可能な限り塗りつぶしに切り替えることができます。

行き詰まった場合は、おそらくバックトラックする機能が必要になります。

おそらくそれはあまり効率的ではありません。

2
AakashM

与えた例では、最初から最後までの実際のパスは1つだけです。それがあなたが望むすべてであるならば、私はあなたがランダムウォークを使うことができると思っています!

概念は単純です。迷路、開始点、および終了点の外側の境界が与えられた場合、開始点からランダムウォークを生成し、最終的には終了点で終了する関数を記述します。条件は、「ランダムウォーカー」が前の正方形から上、下、右、または左にしか移動できず、以前に通過した正方形の1つの正方形内に入ることができないことです(これにより壁が作成されます)。

私が見ているように、ここには2つのアルゴリズム上の課題があります。 1つ目は、以前にトラバースした正方形(衝突)の1つの正方形内にいるかどうかを確認することです。おそらく、通過した正方形(それらの座標)と迷路の境界のリストを維持し、新しい正方形ごとに、リスト内のすべての正方形からの距離を評価することができます。ただし、これはあまり効率的ではありません。

もう1つの課題は、ランダムウォークで実際に終点に到達することです。以前に通過した正方形との衝突が問題にならない場合、最終的には終点に到達することになりますが、それらを使用すると、終点から壁を外すことができるという問題があります。これを回避する方法は、ループの入力をチェックして回避することです。トラバースされたパスや迷路の境界によって形成されたループに入らないようにすると、エンドポイントへの可能なパスが維持されます。私たちがループに入っているかどうかを実際に把握している限り...まあ、それはちょっと難しいです。

迷路解決アルゴリズムがすでにある場合は、衝突の可能性があるときはいつでもそれを実行して、現在の正方形から端点までのパスが存在するかどうかを確認できます。あなたがそれを実行するとき、それまでに横断したすべての正方形が壁であり、それらの境界であると考えさせてください。

2
inlinestyle

現在、これに取り組んでいます...エッジから始めて、正方形の配列をランダムに歩き、セルを通過するときにパスの長さでセルにマークを付けます。

行き詰まったら(そして行き詰まったら)、あなたに隣接する最新のパスでループを形成するTジャンクションを作成します(ただし、以下を参照)。次に、既存のパスに沿ってTジャンクションの反対側に戻り、そこでループを解除します。このぶら下がっている尾は、ランダムウォークの新しい「頭」を形成し(パスソースからパスの長さを再計算することを忘れないでください)、続行できます。

実験によると、これを行うことによって、新しい「尾」がトラップされている限り、新しい尾を作成するループに陥ることはありません(またはまだです-以下を参照)。最新の場合は、切り離したばかりのセルとのリンク-その場合は2番目に新しいセルを選択します。

終了するケースは、Edge要素で「スタック」し、配列を埋めた場合です(パスの長さは配列の領域と同じです)-これで完了です。あなたの始点はあなたの終点につながります。

これには2つの非効率性と潜在的な問題があるようです(私は現在アルゴリズムで遊んでいます)-時々あなたはコーナーに足を踏み入れ、続行する唯一の方法はループリンクを1つで再形成することですあなたはちょうど壊れました。次に、シーケンスは、以前に作成したすべてのループを、最初にスタックしたポイントまでバックトラックします。 thatが他の場所に移動できない場合(別のコーナー)、2つの間でバウンスします。それを回避する方法はありますが、それはループしたセルのある種のリストを保持し、実際に新しいパスを配置したときにのみそれをクリアすることを意味します。

もう1つは、特に配列が奇数ごとの場合、奇数の正方形が塗りつぶされないままになる傾向があることです。なぜこれが当てはまるのかを十分に調査していません。これが発生したときに、前のコーナーの問題が特に蔓延しているように見えます。作業は続きます...

1
Nick

「歩く」ときは、各ステップで行った変更をスタックに保持します。そうすることで、xステップ先を見てから、各ステージでそれ以上のステップを実行できないようにすることができます(コーナーに歩いた、または歩くようなスパイラル)pop実行可能なウォーキングパスができるまでスタックをスタックし、スタックが空になるまでそこから歩き続けます(つまり、前の各ステップで実行可能なネイバーがなかったため、スタックを最後までポップします)。次に、変換を迷路データ構造に適用します。

1