C语言生成随即迷宫原理prim,使用Prim算法实现随机生成的迷宫

本文解释了如何改进维基百科上关于随机化Prim算法在生成二维迷宫时的描述,通过明确数据结构(单元格类型和边界操作),并提供了一个F#实现示例。作者分享了自己的实现方法和清晰化的算法流程,帮助读者理解复杂概念。
摘要由CSDN通过智能技术生成

BitTickler..

9

维基百科文章中的描述确实值得改进.

本文的第一个令人困惑的部分是,随机化Prim算法的描述没有详细说明算法使用的假设数据结构.因此,像"对立细胞"这样的短语变得令人困惑.

基本上有两种主要方法"迷宫发生器程序员"可以选择:

细胞有4个邻居的墙壁或通道.存储和操纵有关墙/通道的信息.

单元可以是阻塞(墙)或通道,而不存储任何额外的连接信息.

根据读者在阅读算法描述时所考虑的模型(1)或(2),他们要么理解要么不理解.

我,我个人更喜欢使用细胞作为墙壁或通道,而不是摆弄专用的通道/墙壁信息.

然后,"边界"贴片与通道的距离为2(而不是1).选择来自边界斑块列表的随机边界斑块并通过使边界斑块和相邻通道之间的细胞成为通道而连接到随机相邻通道(距离2).

这是我的F#实现方式:

let rng = new System.Random()

type Cell = | Blocked | Passage

type Maze =

{

Grid : Cell[,]

Width : int

Height : int

}

let initMaze dx dy =

let six,siy = (1,1)

let eix,eiy = (dx-2,dy-2)

{

Grid = Array2D.init dx dy

(fun _ _ -> Blocked

)

Width = dx

Height = dy

}

let generate (maze : Maze) : Maze =

let isLegal (x,y) =

x>0 && x < maze.Width-1 && y>0 && y

let frontier (x,y) =

[x-2,y;x+2,y; x,y-2; x, y+2]

|> List.filter (fun (x,y) -> isLegal (x,y) && maze.Grid.[x,y] = Blocked)

let neighbor (x,y) =

[x-2,y;x+2,y; x,y-2; x, y+2]

|> List.filter (fun (x,y) -> isLegal (x,y) && maze.Grid.[x,y] = Passage)

let randomCell () = rng.Next(maze.Width),rng.Next(maze.Height)

let removeAt index (lst : (int * int) list) : (int * int) list =

let x,y = lst.[index]

lst |> List.filter (fun (a,b) -> not (a = x && b = y) )

let between p1 p2 =

let x =

match (fst p2 - fst p1) with

| 0 -> fst p1

| 2 -> 1 + fst p1

| -2 -> -1 + fst p1

| _ -> failwith "Invalid arguments for between()"

let y =

match (snd p2 - snd p1) with

| 0 -> snd p1

| 2 -> 1 + snd p1

| -2 -> -1 + snd p1

| _ -> failwith "Invalid arguments for between()"

(x,y)

let connectRandomNeighbor (x,y) =

let neighbors = neighbor (x,y)

let pickedIndex = rng.Next(neighbors.Length)

let xn,yn = neighbors.[pickedIndex]

let xb,yb = between (x,y) (xn,yn)

maze.Grid.[xb,yb]

()

let rec extend front =

match front with

| [] -> ()

| _ ->

let pickedIndex = rng.Next(front.Length)

let xf,yf = front.[pickedIndex]

maze.Grid.[xf,yf]

connectRandomNeighbor (xf,yf)

extend ((front |> removeAt pickedIndex) @ frontier (xf,yf))

let x,y = randomCell()

maze.Grid.[x,y]

extend (frontier (x,y))

maze

let show maze =

printfn "%A" maze

maze.Grid |> Array2D.iteri

(fun y x cell ->

if x = 0 && y > 0 then

printfn "|"

let c =

match cell with

| Blocked -> "X"

| Passage -> " "

printf "%s" c

)

maze

let render maze =

let cellWidth = 10;

let cellHeight = 10;

let pw = maze.Width * cellWidth

let ph = maze.Height * cellHeight

let passageBrush = System.Drawing.Brushes.White

let wallBrush = System.Drawing.Brushes.Black

let bmp = new System.Drawing.Bitmap(pw,ph)

let g = System.Drawing.Graphics.FromImage(bmp);

maze.Grid

|> Array2D.iteri

(fun y x cell ->

let brush =

match cell with

| Passage -> passageBrush

| Blocked -> wallBrush

g.FillRectangle(brush,x*cellWidth,y*cellHeight,cellWidth,cellHeight)

)

g.Flush()

bmp.Save("""E:\temp\maze.bmp""")

initMaze 50 50 |> generate |> show |> render

结果迷宫然后可以看起来像这样:

D5QgT.png

这里试图用维基百科"算法"风格来描述我的解决方案:

网格由2维单元格组成.

Cell有2种状态:Blocked或Passage.

从状态为Blocked的Grid充满Grid.

选择一个随机单元格,将其设置为状态Passage并计算其边界单元格.Cell的边界单元是具有距离2处于阻塞状态且在网格内的单元.

边界单元格列表不为空:

从边界单元列表中选择一个随机前沿单元格.

让邻居(frontierCell)=状态Passage中距离2的所有单元格.选择一个随机邻居并通过将其间的单元格设置为状态Passage来将边界单元与邻居连接.计算所选前沿单元格的边界单元格并将它们添加到前沿列表中.从边界单元列表中删除选定的前沿单元格.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值