Index

Part 3: The Maze Class

Now it is time to create the maze class. This class will be responsible for generating the maze as well as drawing it to the screen. First thing we will need is a place to store the grid of cells. We will use a two dimensional array for this purpose. We will also store the width and height of the maze in a couple of fields.

Type TMaze
	Field grid:TCell[,]
	Field Width:Int, Height:Int

Next we wil create a function called Create() where we pass in the dimentions of the maze we wish to create and it returns an object of TMaze type with the maze already generated.

	Function Create:TMaze(Width:Int, Height:Int)

The first thing we need to do in our function is to create an instance of the TMaze type. Then we will set the Width and Height fields to the values passed in.

		Local maze:TMaze = New TMaze
		maze.Width = Width
		maze.Height = Height

Next, we need to initialize the grid array and initialize each cell.

		maze.grid = New TCell[Width,Height]
		
		For Local y:Int = 0 Until Height
			For Local x:Int = 0 Until Width
				maze.grid[x,y] = New TCell
			Next
		Next

The next part will link each cell with its neighbor, first checking to make sure the cell is not on the border.

		For Local y:Int = 0 Until Height
			For Local x:Int = 0 Until Width
				If y > 0 Then maze.grid[x,y]._north = maze.grid[x,y-1]
				If x < Width-1 Then maze.grid[x,y]._east = maze.grid[x+1,y]
				If y < Height-1 Then maze.grid[x,y]._south = maze.grid[x,y+1]
				If x > 0 Then maze.grid[x,y]._west = maze.grid[x-1,y]
			Next
		Next

Next, we need to create a list, then add a random cell to it.

		Local list:TList = CreateList()
		list.AddLast(maze.grid[Rand(0,Width-1),Rand(0,Height-1)])

Next we will create a While loop, first testing that the list is not empty.

		While Not list.IsEmpty()

The first thing to do in our While loop is to pick a cell from the list.

For Recursive Backtracking, grab the last cell on the list.

			Local cell:TCell = TCell(list.Last()) 'Recursive Backtracking

For growing Tree, just pick any cell in the list at random

			'Local cell:TCell = TCell(list.ValueAtIndex(Rand(0,list.Count()-1))) 'Growing Tree

After we grab a cell from the list, we next need to get the directions to all the unvisited cells surrounding this one. We already created a method in the Cell class, so we can just easily call that.

			Local directions:Int[] = cell.getUnvisited()

If Null was returned by getUnvisited, then we know that no unvisited cells exist around this one, so we remove it from the list. Otherwise, we pick one of the directions at random and create a link to it. The cell returned by the link method is then added to the top of the list.

			If directions = Null
				list.Remove(cell)
			Else
				list.AddLast(cell.Link(directions[Rand(0,directions.length-1)]))
			End If

The While loop keeps looping as long as there is a cell in the list. Once the list is empty, we know the maze is complete. So we exit the loop, then return the completed maze.

		Wend
		Return maze
	End Function

The next thing we need to do is draw our maze. How you do that is up to you. In this tutorial, I'll keep everything simple and use DrawLine for the walls. Our Draw() method will be passed the width and height of each cell in pixels. Then we will loop through the grid and check the paths field. Check each direction, and if 0, then a wall is drawn.

	Method Draw(w:Int, h:Int)
		For Local y:Int = 0 Until Height
			For Local x:Int = 0 Until Width
				If grid[x,y].paths & TCell.North = 0 Then DrawLine x*w,y*h,x*w+w,y*h
				If grid[x,y].paths & TCell.East = 0 Then DrawLine x*w+w-1,y*h,x*w+w-1,y*h+h
				If grid[x,y].paths & TCell.South = 0 Then DrawLine x*w,y*h+h-1,x*w+w,y*h+h-1
				If grid[x,y].paths & TCell.West = 0 Then DrawLine x*w,y*h,x*w,y*h+h
			Next
		Next
	End Method

We will need to override the Delete method. The cells in the grid contain some circular references that must be removed before this object is garbage collected, otherwise you will end up with a memory leak. Just loop through each element of the grid and call the cell's Destroy() method.

	Method Delete()
		For Local x:Int = 0 Until Width
			For Local y:Int = 0 Until Height
				grid[x,y].Destroy()
			Next
		Next
	End Method
End Type

That's all we need for the maze class. The whole thing looks like this

Type TMaze
	Field grid:TCell[,]
	Field Width:Int, Height:Int
	
	Function Create:TMaze(Width:Int, Height:Int)
		Local maze:TMaze = New TMaze
		maze.Width = Width
		maze.Height = Height
		
		maze.grid = New TCell[Width,Height]
		
		For Local y:Int = 0 Until Height
			For Local x:Int = 0 Until Width
				maze.grid[x,y] = New TCell
			Next
		Next
		
		For Local y:Int = 0 Until Height
			For Local x:Int = 0 Until Width
				If y > 0 Then maze.grid[x,y]._north = maze.grid[x,y-1]
				If x < Width-1 Then maze.grid[x,y]._east = maze.grid[x+1,y]
				If y < Height-1 Then maze.grid[x,y]._south = maze.grid[x,y+1]
				If x > 0 Then maze.grid[x,y]._west = maze.grid[x-1,y]
			Next
		Next
		
		Local list:TList = CreateList()
		list.AddLast(maze.grid[Rand(0,Width-1),Rand(0,Height-1)])
		
		While Not list.IsEmpty()
			Local cell:TCell = TCell(list.Last()) 'Recursive Backtracking
			'Local cell:TCell = TCell(list.ValueAtIndex(Rand(0,list.Count()-1))) 'Growing Tree
			Local directions:Int[] = cell.getUnvisited()
			If directions = Null
				list.Remove(cell)
			Else
				list.AddLast(cell.Link(directions[Rand(0,directions.length-1)]))
			End If
		Wend
		Return maze
	End Function
	
	Method Draw(w:Int, h:Int)
		For Local y:Int = 0 Until Height
			For Local x:Int = 0 Until Width
				If grid[x,y].paths & TCell.North = 0 Then DrawLine x*w,y*h,x*w+w,y*h
				If grid[x,y].paths & TCell.East = 0 Then DrawLine x*w+w-1,y*h,x*w+w-1,y*h+h
				If grid[x,y].paths & TCell.South = 0 Then DrawLine x*w,y*h+h-1,x*w+w,y*h+h-1
				If grid[x,y].paths & TCell.West = 0 Then DrawLine x*w,y*h,x*w,y*h+h
			Next
		Next
	End Method
			
	Method Delete()
		For Local x:Int = 0 Until Width
			For Local y:Int = 0 Until Height
				grid[x,y].Destroy()
			Next
		Next
	End Method
End Type

Index

Created with Tutorial Markup (c)2018 James Chamblin