Maze Generator works partially, but gets stuck, or ends early

So I’m not sure why my maze generator isn’t working as expected. Sometimes it appears to be finished, but doesn’t break the loop, or that it seems to get stuck. I’m not too sure if this is on the algorithm’s side or not, but I thought I would give this a try. I included the entire code just in case the actual cause of the error was in the grid generating part, although the more relevant part(maze generator) is on line 110(…local function CreateMaze)
Maze_generator.rbxl (108.1 KB)
I based it off the algorithm from here: Buckblog: Maze Generation: Recursive Backtracking

local MazePart = script.MazePart:Clone() :: BasePart
local GeneratedCells = {}
local UnVisitedCells = {}
local MazeSize = 15
local Size = MazePart.Size.Y
local YSize =  0 or MazePart.Size.X - 2
local WallOffset = (Size + YSize) / 2
function f(a)
	return math.floor(a / Size) * (Size + YSize)
end
for X = -MazeSize, MazeSize do
	GeneratedCells[X] = {}
	for Y = -MazeSize, MazeSize do
		local Cell = MazePart:Clone()
		Cell.Position = Vector3.new(f(X * Size), 0, f(Y * Size))
		Cell.Parent = workspace.Cells
		local CellData = {}
		CellData.Cell = Cell
		CellData.Visited = false
		CellData.Pos = Vector2.new(X, Y)
		Cell.Name = ("(%s, %s)"):format(tostring(X), tostring(Y))
		GeneratedCells[X][Y] = CellData
	end
end
for X, Cells in pairs(GeneratedCells) do
	for Y, Cell in pairs(Cells) do
		local ActualCell = Cell.Cell :: BasePart
		local Position = ActualCell.Position
		local NorthCell = Cells[Y + 1]
		local EastCell
		if GeneratedCells[X + 1] then
			EastCell = GeneratedCells[X + 1][Y]
		end
		local SouthCell = Cells[Y - 1]
		local WestCell
		if GeneratedCells[X - 1] then
			WestCell = GeneratedCells[X - 1][Y]
		end
		Cell.North = {}
		Cell.East = {}
		Cell.South = {}
		Cell.West = {}
		Cell.North.Cell = NorthCell
		Cell.East.Cell = EastCell
		Cell.South.Cell = SouthCell
		Cell.West.Cell = WestCell
		local function CreateNorthBlock()
			local Block = script.Blockx:Clone()
			Block.Parent = ActualCell
			Block.Position = Vector3.new(Position.X, Position.Y + WallOffset, Position.Z + WallOffset)
			Cell.North.Block = Block
		end
		local function CreateSouthBlock()
			local Block = script.Blockx:Clone()
			Block.Parent = ActualCell
			Block.Position = Vector3.new(Position.X, Position.Y + WallOffset, Position.Z - WallOffset)
			Cell.South.Block = Block
		end
		local function CreateEastBlock()
			local Block = script.Blocky:Clone()
			Block.Parent = ActualCell
			Block.Position = Vector3.new(Position.X + WallOffset, Position.Y + WallOffset, Position.Z)
			Cell.East.Block = Block
		end
		local function CreateWestBlock()
			local Block = script.Blocky:Clone()
			Block.Parent = ActualCell
			Block.Position = Vector3.new(Position.X - WallOffset, Position.Y + WallOffset, Position.Z)
			Cell.West.Block = Block
		end
		if NorthCell then
			if NorthCell.South and NorthCell.South.Block then
				Cell.North.Block = NorthCell.South.Block
			else
				CreateNorthBlock()
			end
		else
			CreateNorthBlock()
		end
		if SouthCell then
			if SouthCell.North and SouthCell.North.Block then
				Cell.South.Block = SouthCell.North.Block
			else
				CreateSouthBlock()
			end
		else
			CreateSouthBlock()
		end
		if EastCell then
			if EastCell.West and EastCell.West.Block then
				Cell.East.Block = EastCell.West.Block
			else
				CreateEastBlock()
			end
		else
			CreateEastBlock()
		end
		if WestCell then
			if WestCell.East and WestCell.East.Block then
				Cell.West.Block = WestCell.East.Block
			else
				CreateWestBlock()
			end
		else
			CreateWestBlock()
		end
		task.wait()
	end
end
local function CreateMaze(StartingPoint)
	local StartingCell = GeneratedCells[StartingPoint.X][StartingPoint.Y]
	local CurrentCell = StartingCell
	StartingCell.IsStart = true
	local function getdir(Cell)
		local Directions = {"North", "East", "South", "West"}
		local Direction
		repeat
			local PossibleDirection = table.remove(Directions, math.random(#Directions))
			if Cell[PossibleDirection]["Cell"] then
				if Cell[PossibleDirection]["Cell"]["Visited"] ~= true then
					Cell[PossibleDirection]["Cell"]["Visited"] = true
					Direction = PossibleDirection
				end
			end
		until Direction or #Directions == 0

		return Direction
	end

	while true do
		local NextCell 
		local Direction = getdir(CurrentCell)
		if Direction then
			local NextCell = CurrentCell[Direction]["Cell"]
			if CurrentCell[Direction]["Block"] then
				CurrentCell[Direction]["Block"]:Destroy()
				CurrentCell[Direction]["Block"] = nil
			end
			if not NextCell["IsStart"] then
				NextCell["Last"] = CurrentCell
			end
			CurrentCell = NextCell
		elseif not Direction then
			if CurrentCell["Last"] then
				local LastCell = CurrentCell["Last"]
				if LastCell then
					CurrentCell = LastCell
				else
					print("finished?")
					break
				end
			end
		end
		task.wait()
	end
end
local StartingPoint = Vector2.new(math.random(-MazeSize, MazeSize), math.random(-MazeSize, MazeSize))
CreateMaze(StartingPoint)
1 Like

I found two issues. Basically this line if CurrentCell["Last"] then is causing the loop to never end just when the algorithm returns to the initial cell. It just doesn’t make sense because inside it is already checking to see if a previous cell exists (and terminating the algorithm if it doesn’t).

The algorithm sometimes seems to get stuck because on its way it encounters the initial cell and that cell is not marked as visited so it visits it. The algorithm continues on its way. When it is on its way back and encounters the initial cell, it will simply enter the infinite loop mentioned above before visiting all cells. The simplest solution is to mark the initial cell as visited.

	CurrentCell.Visited = true -- before loop
	while true do
		local NextCell 
		local Direction = getdir(CurrentCell)
		if Direction then
			local NextCell = CurrentCell[Direction]["Cell"]
			if CurrentCell[Direction]["Block"] then
				CurrentCell[Direction]["Block"]:Destroy()
				CurrentCell[Direction]["Block"] = nil
			end
			--if not NextCell["IsStart"] then
				NextCell["Last"] = CurrentCell
			--end
			CurrentCell = NextCell
		elseif not Direction then
			--if CurrentCell["Last"] then
				local LastCell = CurrentCell["Last"]
				if LastCell then
					CurrentCell = LastCell
				else
					print("finished?")
					break
				end
			--end
		end
		task.wait()
	end

I didn’t test deeper but I think it will work.

1 Like