When I was teaching programming full time, I always tried to enable the students to think for themselves, and figure out how their own logic works, because it is quite difficult teaching people logic. With the introduction to programming exam (which was mostly theoretical), I included a scenario about a programmable mouse that needs to escape a maze so that it can eat a slice of cheese.
Inside this maze were electronic doors that needed to be tested whether or not they were open before continuing. The robotic mouse also understood a very basic set of instructions (such as move left, smell, and look), for it to navigate through the maze.
These tasks enable students to think critically to solve a problem with the instructions provided. This test has been in existence for almost 15 years, and ever since I made it, I wanted to create my own Maze game. Now, finally, with some time on my hands, I can finally show you how to create a Maze.
Welcome to Part 1, where we will create the gaming structure. This project can be done in either VB.NET or C#; I will provide code for both. Let’s start!
Practical
Create either a VB.NET or C# Windows Application, and add two classes named:
- clsGrid
- clsGame
Add the following to clsGrid:
C#
using System;
public class clsGrid
{
public struct Cell
{
public bool blnNorth;
public bool blnSouth;
public bool blnWest;
public bool blnEast;
public bool blnDirty;
public int intNorth;
public int intSouth;
public int intWest;
public int intEast;
}
public static Cell[][] Cells;
public static Cell[][] Solution;
public static Point ptStart;
public static Point ptEnd;
}
VB.NET
Public Class clsGrid
Public Structure Cell
Dim blnNorth As Boolean
Dim blnSouth As Boolean
Dim blnWest As Boolean
Dim blnEast As Boolean
Dim blnDirty As Boolean
Dim intNorth As Integer
Dim intSouth As Integer
Dim intWest As Integer
Dim intEast As Integer
End Structure
Public Shared Cells()() As Cell
Public Shared Solution()() As Cell
Public Shared ptStart As Point
Public Shared ptEnd As Point
End Class
There isn’t much in the class, but it does set the boundaries for the walls of the grid, as well as holding the Cell arrays and their various Starting and Ending points. Add the Generate code for clsGame.
C#
public void Generate(int intCols, Random rndRand)
{
for (int cell = 0; cell <= intCols - 1; cell++)
{
for (int r = 0; r <= intCols - 1; r++)
clsGrid.Cells(cell)(r) = new clsGrid.Cell();
}
for (int col = 0; col <= clsGrid.Cells.GetUpperBound(0);
col++)
{
for (int row = 0; row <=
clsGrid.Cells(0).GetUpperBound(0); row++)
{
clsGrid.Cells(col)(row).blnDirty = false;
clsGrid.Cells(col)(row).blnNorth = true;
clsGrid.Cells(col)(row).blnSouth = true;
clsGrid.Cells(col)(row).blnWest = true;
clsGrid.Cells(col)(row).blnEast = true;
}
}
List<Point> lstMaze = new List<Point>();
int intEmpty = Math.Pow(intCols, 2);
clsGrid.ptStart = new Point(rndRand.Next(0, intCols),
intCols - 1);
clsGrid.Cells(clsGrid.ptStart.X)(intCols - 1).blnSouth =
false;
lstMaze.Add(new Point(clsGrid.ptStart.X, intCols - 1));
intEmpty -= 1;
while (intEmpty > 0)
{
Point pPoint = lstMaze[rndRand.Next(0, lstMaze.Count)];
List<Point> lstChoice = new List<Point>();
if (pPoint.X > 0 & pPoint.X < intCols - 1)
{
if (pPoint.Y > 0 & pPoint.Y < intCols - 1)
// l,t,r,b
lstChoice.AddRange(new Point[] { new Point(pPoint.X
- 1, pPoint.Y), new Point(pPoint.X, pPoint.Y -
1), new Point(pPoint.X + 1, pPoint.Y), new
Point(pPoint.X, pPoint.Y + 1) });
else if (pPoint.Y == 0)
// l,r,b
lstChoice.AddRange(new Point[] { new Point(pPoint.X
- 1, pPoint.Y), new Point(pPoint.X + 1,
pPoint.Y), new Point(pPoint.X, pPoint.Y + 1) });
else if (pPoint.Y == intCols - 1)
// l,t,r
lstChoice.AddRange(new Point[] { new Point(pPoint.X
- 1, pPoint.Y), new Point(pPoint.X, pPoint.Y - 1),
new Point(pPoint.X + 1, pPoint.Y) });
}
else if (pPoint.X == 0)
{
if (pPoint.Y > 0 & pPoint.Y < intCols - 1)
// t,r,b
lstChoice.AddRange(new Point[] { new Point(pPoint.X,
pPoint.Y - 1), new Point(pPoint.X + 1, pPoint.Y),
new Point(pPoint.X, pPoint.Y + 1) });
else if (pPoint.Y == 0)
// r,b
lstChoice.AddRange(new Point[] { new Point(pPoint.X
+ 1, pPoint.Y), new Point(pPoint.X, pPoint.Y
+ 1) });
else if (pPoint.Y == intCols - 1)
// t,r
lstChoice.AddRange(new Point[] { new Point(pPoint.X,
pPoint.Y - 1), new Point(pPoint.X + 1,
pPoint.Y) });
}
else if (pPoint.X == intCols - 1)
{
if (pPoint.Y > 0 & pPoint.Y < intCols - 1)
// l,t,b
lstChoice.AddRange(new Point[] { new Point(pPoint.X
- 1, pPoint.Y), new Point(pPoint.X, pPoint.Y
- 1), new Point(pPoint.X, pPoint.Y + 1) });
else if (pPoint.Y == 0)
// l,b
lstChoice.AddRange(new Point[] { new Point(pPoint.X
- 1, pPoint.Y), new Point(pPoint.X, pPoint.Y
+ 1) });
else if (pPoint.Y == intCols - 1)
// l,t
lstChoice.AddRange(new Point[] { new Point(pPoint.X
- 1, pPoint.Y), new Point(pPoint.X, pPoint.Y
- 1) });
}
lstChoice.RemoveAll(pt => clsGrid.Cells(pt.X)(pt.Y)
.blnDirty);
if (lstChoice.Count == 0)
continue;
Point pPoint2 = lstChoice[rndRand.Next(0,
lstChoice.Count)];
if (pPoint.X == pPoint2.X & pPoint2.Y < pPoint.Y)
{
if (clsGrid.Cells(pPoint.X)(pPoint.Y).blnNorth)
{
clsGrid.Cells(pPoint.X)(pPoint.Y).blnNorth = false;
clsGrid.Cells(pPoint2.X)(pPoint2.Y).blnSouth =
false;
clsGrid.Cells(pPoint2.X)(pPoint2.Y).blnDirty = true;
intEmpty -= 1;
lstMaze.Add(new Point(pPoint2.X, pPoint2.Y));
}
else
continue;
}
else if (pPoint.X == pPoint2.X & pPoint2.Y > pPoint.Y)
{
if (clsGrid.Cells(pPoint.X)(pPoint.Y).blnSouth)
{
clsGrid.Cells(pPoint.X)(pPoint.Y).blnSouth = false;
clsGrid.Cells(pPoint2.X)(pPoint2.Y).blnNorth =
false;
clsGrid.Cells(pPoint2.X)(pPoint2.Y).blnDirty = true;
intEmpty -= 1;
lstMaze.Add(pPoint2);
}
else
continue;
}
else if (pPoint.X > pPoint2.X & pPoint2.Y == pPoint.Y)
{
if (clsGrid.Cells(pPoint.X)(pPoint.Y).blnWest)
{
clsGrid.Cells(pPoint.X)(pPoint.Y).blnWest = false;
clsGrid.Cells(pPoint2.X)(pPoint2.Y).blnEast =
false;
clsGrid.Cells(pPoint2.X)(pPoint2.Y).blnDirty = true;
intEmpty -= 1;
lstMaze.Add(pPoint2);
}
else
continue;
}
else if (pPoint.X < pPoint2.X & pPoint2.Y == pPoint.Y)
{
if (clsGrid.Cells(pPoint.X)(pPoint.Y).blnEast)
{
clsGrid.Cells(pPoint.X)(pPoint.Y).blnEast = false;
clsGrid.Cells(pPoint2.X)(pPoint2.Y).blnWest = false;
clsGrid.Cells(pPoint2.X)(pPoint2.Y).blnDirty = true;
intEmpty -= 1;
lstMaze.Add(pPoint2);
}
else
continue;
}
}
}
VB.NET
Public Sub Generate(ByVal intCols As Integer, ByVal rndRand _
As Random)
ReDim clsGrid.Cells(intCols - 1)
For cell As Integer = 0 To intCols - 1
ReDim clsGrid.Cells(cell)(intCols - 1)
For r As Integer = 0 To intCols - 1
clsGrid.Cells(cell)(r) = New clsGrid.Cell
Next
Next
For col As Integer = 0 To clsGrid.Cells.GetUpperBound(0)
For row As Integer = 0 To clsGrid.Cells(0) _
.GetUpperBound(0)
clsGrid.Cells(col)(row).blnDirty = False
clsGrid.Cells(col)(row).blnNorth = True
clsGrid.Cells(col)(row).blnSouth = True
clsGrid.Cells(col)(row).blnWest = True
clsGrid.Cells(col)(row).blnEast = True
Next
Next
Dim lstMaze As New List(Of Point)
Dim intEmpty As Integer = intCols ^ 2
clsGrid.ptStart = New Point(rndRand.Next(0, intCols), _
intCols - 1)
clsGrid.Cells(clsGrid.ptStart.X)(intCols - 1).blnSouth = _
False
lstMaze.Add(New Point(clsGrid.ptStart.X, intCols - 1))
intEmpty -= 1
While intEmpty > 0
Dim pPoint As Point = lstMaze(rndRand.Next(0, _
lstMaze.Count))
Dim lstChoice As New List(Of Point)
If pPoint.X > 0 And pPoint.X < intCols - 1 Then
If pPoint.Y > 0 And pPoint.Y < intCols - 1 Then
'l,t,r,b'
lstChoice.AddRange(New Point() {New Point(pPoint.X _
- 1, pPoint.Y), New Point(pPoint.X, pPoint.Y _
- 1), New Point(pPoint.X + 1, pPoint.Y), _
New Point(pPoint.X, pPoint.Y + 1)})
ElseIf pPoint.Y = 0 Then
'l,r,b'
lstChoice.AddRange(New Point() {New Point(pPoint.X _
- 1, pPoint.Y), New Point(pPoint.X + 1, _
pPoint.Y), New Point(pPoint.X, pPoint.Y + 1)})
ElseIf pPoint.Y = intCols - 1 Then
'l,t,r'
lstChoice.AddRange(New Point() {New Point(pPoint.X _
- 1, pPoint.Y), New Point(pPoint.X, pPoint.Y _
- 1), New Point(pPoint.X + 1, pPoint.Y)})
End If
ElseIf pPoint.X = 0 Then
If pPoint.Y > 0 And pPoint.Y < intCols - 1 Then
't,r,b'
lstChoice.AddRange(New Point() {New Point(pPoint.X, _
pPoint.Y - 1), New Point(pPoint.X + 1, _
pPoint.Y), New Point(pPoint.X, pPoint.Y + 1)})
ElseIf pPoint.Y = 0 Then
'r,b'
lstChoice.AddRange(New Point() {New Point(pPoint.X _
+ 1, pPoint.Y), New Point(pPoint.X, pPoint.Y _
+ 1)})
ElseIf pPoint.Y = intCols - 1 Then
't,r'
lstChoice.AddRange(New Point() {New Point(pPoint.X, _
pPoint.Y - 1), New Point(pPoint.X + 1, pPoint.Y)})
End If
ElseIf pPoint.X = intCols - 1 Then
If pPoint.Y > 0 And pPoint.Y < intCols - 1 Then
'l,t,b'
lstChoice.AddRange(New Point() {New Point(pPoint.X _
- 1, pPoint.Y), New Point(pPoint.X, pPoint.Y _
- 1), New Point(pPoint.X, pPoint.Y + 1)})
ElseIf pPoint.Y = 0 Then
'l,b'
lstChoice.AddRange(New Point() {New Point(pPoint.X _
- 1, pPoint.Y), New Point(pPoint.X, pPoint.Y _
+ 1)})
ElseIf pPoint.Y = intCols - 1 Then
'l,t'
lstChoice.AddRange(New Point() {New Point(pPoint.X _
- 1, pPoint.Y), New Point(pPoint.X, pPoint.Y _
- 1)})
End If
End If
lstChoice.RemoveAll(Function(pt) clsGrid.Cells(pt.X) _
(pt.Y).blnDirty)
If lstChoice.Count = 0 Then Continue While
Dim pPoint2 As Point = lstChoice(rndRand.Next(0, _
lstChoice.Count))
If pPoint.X = pPoint2.X And pPoint2.Y < pPoint.Y Then
If clsGrid.Cells(pPoint.X)(pPoint.Y).blnNorth Then
clsGrid.Cells(pPoint.X)(pPoint.Y).blnNorth = False
clsGrid.Cells(pPoint2.X)(pPoint2.Y).blnSouth = _
False
clsGrid.Cells(pPoint2.X)(pPoint2.Y).blnDirty = True
intEmpty -= 1
lstMaze.Add(New Point(pPoint2.X, pPoint2.Y))
Else
Continue While
End If
ElseIf pPoint.X = pPoint2.X And pPoint2.Y > pPoint.Y Then
If clsGrid.Cells(pPoint.X)(pPoint.Y).blnSouth Then
clsGrid.Cells(pPoint.X)(pPoint.Y).blnSouth = False
clsGrid.Cells(pPoint2.X)(pPoint2.Y).blnNorth = _
False
clsGrid.Cells(pPoint2.X)(pPoint2.Y).blnDirty = True
intEmpty -= 1
lstMaze.Add(pPoint2)
Else
Continue While
End If
ElseIf pPoint.X > pPoint2.X And pPoint2.Y = pPoint.Y Then
If clsGrid.Cells(pPoint.X)(pPoint.Y).blnWest Then
clsGrid.Cells(pPoint.X)(pPoint.Y).blnWest = False
clsGrid.Cells(pPoint2.X)(pPoint2.Y).blnEast = False
clsGrid.Cells(pPoint2.X)(pPoint2.Y).blnDirty = True
intEmpty -= 1
lstMaze.Add(pPoint2)
Else
Continue While
End If
ElseIf pPoint.X < pPoint2.X And pPoint2.Y = pPoint.Y Then
If clsGrid.Cells(pPoint.X)(pPoint.Y).blnEast Then
clsGrid.Cells(pPoint.X)(pPoint.Y).blnEast = False
clsGrid.Cells(pPoint2.X)(pPoint2.Y).blnWest = False
clsGrid.Cells(pPoint2.X)(pPoint2.Y).blnDirty = True
intEmpty -= 1
lstMaze.Add(pPoint2)
Else
Continue While
End If
End If
End While
End Sub
The Generate sub is responsible for creating the design of the Maze. This is done by generating random points and identifying if the current spot is already used. Then, it draws the connecting lines to the various points.
Add the Solve Function.
C#
public bool Solve(int intCol, int intX, int intY, bool[,]
blnScanned, List<Point> lstSol)
{
bool blnCorrect = false;
bool blnCheck = true;
if (intX >= intCol || intX < 0 || intY >= intCol
|| intY < 0)
blnCheck = false;
else
{
if (new Point(intX, intY) == clsGrid.ptEnd)
{
blnCorrect = true;
blnCheck = false;
}
if (blnScanned[intX, intY])
blnCheck = false;
}
if (blnCheck)
{
blnScanned[intX, intY] = true;
blnCorrect = blnCorrect | clsGrid.Cells(intX)(intY)
.blnEast == false ? Solve(intCol, intX + 1, intY,
blnScanned, lstSol) : false;
blnCorrect = blnCorrect | clsGrid.Cells(intX)(intY)
.blnSouth == false ? Solve(intCol, intX, intY + 1,
blnScanned, lstSol) : false;
blnCorrect = blnCorrect | clsGrid.Cells(intX)(intY)
.blnWest == false ? Solve(intCol, intX - 1, intY,
blnScanned, lstSol) : false;
blnCorrect = blnCorrect | clsGrid.Cells(intX)(intY)
.blnNorth == false ? Solve(intCol, intX, intY - 1,
blnScanned, lstSol) : false;
}
if (blnCorrect)
lstSol.Add(new Point(intX, intY));
return blnCorrect;
}
VB.NET
Public Function Solve(ByVal intCol As Integer, ByVal intX As -
Integer, ByVal intY As Integer, ByVal blnScanned(,) _
As Boolean, ByVal lstSol As List(Of Point)) As Boolean
Dim blnCorrect As Boolean = False
Dim blnCheck As Boolean = True
If intX >= intCol OrElse intX < 0 OrElse intY >= _
intCol OrElse intY < 0 Then
blnCheck = False
Else
If New Point(intX, intY) = clsGrid.ptEnd Then
blnCorrect = True
blnCheck = False
End If
If blnScanned(intX, intY) Then
blnCheck = False
End If
End If
If blnCheck Then
blnScanned(intX, intY) = True
blnCorrect = blnCorrect Or If(clsGrid.Cells(intX)(intY) _
.blnEast = False, Solve(intCol, intX + 1, intY, _
blnScanned, lstSol), False)
blnCorrect = blnCorrect Or If(clsGrid.Cells(intX)(intY) _
.blnSouth = False, Solve(intCol, intX, intY + 1, _
blnScanned, lstSol), False)
blnCorrect = blnCorrect Or If(clsGrid.Cells(intX)(intY) _
.blnWest = False, Solve(intCol, intX - 1, intY, _
blnScanned, lstSol), False)
blnCorrect = blnCorrect Or If(clsGrid.Cells(intX)(intY) _
.blnNorth = False, Solve(intCol, intX, intY - 1, _
blnScanned, lstSol), False)
End If
If blnCorrect Then
lstSol.Add(New Point(intX, intY))
End If
Return blnCorrect
End Function
Conclusion
Now that we have the structure, we can build the gaming logic into it in Part 2. I hope you look forward to it.