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.