Creating a Maze Game in .NET, Part 1: Structure

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.

Hannes DuPreez
Hannes DuPreez
Ockert J. du Preez is a passionate coder and always willing to learn. He has written hundreds of developer articles over the years detailing his programming quests and adventures. He has written the following books: Visual Studio 2019 In-Depth (BpB Publications) JavaScript for Gurus (BpB Publications) He was the Technical Editor for Professional C++, 5th Edition (Wiley) He was a Microsoft Most Valuable Professional for .NET (2008–2017).

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read