The description on the Wikipedia article really deserves improvement.
The first confusing part of the article is that the description of the randomized Prim algorithm does not clarify the intended data structure used by the algorithm. Thus, phrases such as βopposite cellβ get confused.
Basically, there are two main approaches: "labyrinth programmers-generators" can choose:
- Cells have walls or walkways to their 4 neighbors. Wall / walkway information is stored and processed.
- Cells can be blocked (walls) or walkways without saving additional connection information.
Depending on which model (1) or (2) the reader has in mind when reading the description of the algorithm, they either understand or do not understand.
Personally, I prefer to use the cells as walls or walkways, rather than messing around with highlighted pass / wall information.
Then the "border" sections have a distance of 2 (and not 1) from the passage. A random border patch from the list of border patches is selected and connected to a random neighboring passage (at a distance of 2), also making a cell between the border patch and the neighboring passage.
Here is my F # implementation, what it looks like:
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<maze.Height-1 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] <- Passage () let rec extend front = match front with | [] -> () | _ -> let pickedIndex = rng.Next(front.Length) let xf,yf = front.[pickedIndex] maze.Grid.[xf,yf] <- Passage connectRandomNeighbor (xf,yf) extend ((front |> removeAt pickedIndex) @ frontier (xf,yf)) let x,y = randomCell() maze.Grid.[x,y] <- Passage extend (frontier (x,y)) maze let show maze = printfn "%A" maze maze.Grid |> Array2D.iteri (fun yx 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 yx 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
The resulting maze may look like this:

Here's an attempt to describe my solution in the "algorithm" style of Wikipedia:
- The grid consists of a 2-dimensional array of cells.
- A cell has 2 states: blocked or passing.
- Start with a grid full of cells in the Locked state.
- Select a random cell, set it to Pass and Calculate Your Border Cells. A border cell of a cell is a cell with a distance of 2 in the "Blocked" state and inside the grid.
- While the list of border cells is not empty:
- Select a random border cell from the list of border cells.
- Let adjacent (frontierCell) = all cells at a distance of 2 in the Passage state. Select a random neighbor and connect the border cell to the neighbor by setting the gateway to Passage. Calculate the border cells of the selected border cell and add them to the list of borders. Remove the selected border cell from the list of border cells.