Comment detail
必ず解ける迷路 (Nested Flatten)壁伸ばし法の変種ですね。
> ちなみに棒倒し法なんかだと、例えば次のようなものを生成できません。
棒倒し法では生成方向に逆行する経路が出来ないという意味でしょうか?
棒倒し方では, 格子状に壁を生成し, それを起点に周 囲に1つ以上の壁を生成していきます. そのため, 必ず格子状に壁が存在し, かつその周辺に 1つ以上壁が存在することになり, 一部の構造の迷路 が生成できないということなんだと思います.
棒倒し法の問題点は以下のようです。 1. 一行目に壁が少なくなってしまう。 2. 閉じた領域が出来てしまう。 3. 全ての道と連絡する抜け道ができてしまう。 4. 隙間だらけになってしまう。 5. 生成方向に逆行する経路ができない。 1~4の問題を克服した発散棒倒し法が紹介されていますが、 放射状に迷路を作るのでO(n)で実装するのは無理かもしれません。 参考 迷路自動生成アルゴリズム「発散棒倒し法」 http://aoyzsas.hp.infoseek.co.jp/maze/maze_hpillar.html
> 壁伸ばし法の変種 やってることはグラフの最小全域木を求めるPrimのアルゴリズムと同じですね。 壁が枝に対応します。 > 棒倒し法では生成方向に逆行する経路が出来ないという意味でしょうか? 生成方向に逆行するような棒の倒し方ができないので、 4方向全てに倒す必要のある迷路は、どの方向から始めても 無理なのではないかと考えました。
>グラフの最小全域木を求めるPrimのアルゴリズムと同じ
たしかに「ループがない」「たどり着けない場所がない」という条件はまさに全域木!
えーと、木に見たててるのは壁の方なのですが、 確かに通路の全域木を作る方が素直ですね(笑)
というわけで、通路の最小全域木を作るものを実装してみました。穴掘りです。
Pentium4/2.8GHzで1分半ほど。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | class Maze
WALL, VAC = '#', ' '
DIRS = [[+1, 0], [-1, 0], [0, +1], [0, -1]]
def initialize(m, n)
@rows = m
@cols = n
@field = Array.new(2*@rows+1) { WALL*(2*@cols+1) }
end
def gen
conn = Array.new(@rows) { Array.new(@cols, false) }
cand = [[rand(@rows), rand(@cols), 0, 0]] # (0,0) is dummy
until cand.empty?
y, x, dy, dx = cand.slice!(rand(cand.size))
next if conn[y][x]
conn[y][x] = true
@field[2*y+1-dy][2*x+1-dx] = VAC
@field[2*y+1][2*x+1] = VAC
DIRS.each do |mv|
y_, x_ = y+mv[0], x+mv[1]
if (0...@rows) === y_ &&
(0...@cols) === x_ &&
!conn[y_][x_]
cand << [y_, x_, mv[0], mv[1]]
end
end
end
self
end
def p
puts @field
end
end
M, N = 10, 10
maze = Maze.new(M, N)
maze.gen.p
|





minke
#5304()
[
Ruby
]
Rating2/2=1.00
Rating2/2=1.00-0+
1 reply [ reply ]