Basically it's a problem with the GeneratePath method and the KnockDownWalls method. I used the DFS algorithm and a two dimensional array of UInt16 setting the bits for WSEN walls etc..
The Init appears to be fine but the code I've written seems to be resetting some walls.
Thanks for any help....
Here's Main.cs
using System;using System.Text.RegularExpressions;namespace Game{ /// <summary> /// Main Application Class for Game. /// </summary> class SimpleMazeApp { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static int Main(string[] args) { int ret_val = 0; sbyte rowSize = 0; sbyte colSize = 0; const string AppName = "JWWicks Maze Factory"; const string Version = "0.99.00"; Maze MyMaze; Console.Title = AppName + " - " + Version; do { ShowAppInfo( AppName, Version); GetMazeDimension( ref rowSize, "Rows (height)", 2, 50 ); GetMazeDimension( ref colSize, "Columns (width)", 2, 50 ); MyMaze = CreateMaze( (uint)rowSize, (uint)colSize ); MyMaze.GeneratePath(); MyMaze.Draw(); }while( !IsAppDone() ); return ret_val; } static void ShowAppInfo( string AppName, string Version ) { Console.WriteLine("{0} - {1}\n\n", AppName, Version); } static bool IsAppDone() { bool ret_val = false; string answer = null; do { Console.Write("Would you like to display another Maze: "); try { answer = Console.ReadLine(); } catch { Console.WriteLine("Error: Getting the answer, please try again..."); } }while( !IsValidAnswer( answer ) ); if (Regex.IsMatch(answer, @"^[Nn]$|^[Nn][Oo]$")) ret_val = true; else Console.Clear(); return ret_val; } static void GetMazeDimension( ref sbyte Size, string Dim, sbyte Min, sbyte Max ) { do { Console.Write("Number of {0} in Maze ( {1} to {2} ): ", Dim, Min, Max); try { Size = SByte.Parse(Console.ReadLine()); } catch { Console.WriteLine("Error: Please enter a number from {0} to {1} !", Min, Max); } }while( !IsValidSize( Size, Min, Max ) ); } static bool IsValidAnswer( string s ) { bool ret_val = false; ret_val = Regex.IsMatch( s , @"^[Nn]$|^[Nn][Oo]$|^[Yy]$|^[Yy][Ee][Ss]$"); if (!ret_val) Console.WriteLine("Please enter either y[es] or n[o]..."); return ret_val; } static bool IsValidSize( sbyte Val, sbyte Min, sbyte Max ) { bool ret_val = false; if( Val < Min | Val > Max ) Console.WriteLine("Error: Value must be from {0} to {1}.", Min, Max); else ret_val = true; return ret_val; } static Maze CreateMaze( uint r, uint c ) { Maze maze = new Maze(r, c); return maze; } }}
And here's the Maze.cs file...
using System;using System.Collections;using System.Threading;namespace Game{ public class Maze { public Maze() { this.m_columns = 3; this.m_rows = 3; Initialize(); } public Maze(uint rows, uint columns) { if( rows > 0 && columns > 0 ) { this.m_rows = rows; this.m_columns = columns; Initialize(); } else throw( new InvalidMazeDimensionException() ); } public void GeneratePath() { Stack cellStack = new Stack(); Random randCell = new Random(); uint cellsVisited = 0; UInt16 curCellRow = 0, curCellCol = 0, nextCellRow = 0, nextCellCol = 0; UInt16 curCellNo = (UInt16)randCell.Next((int)m_totalRooms); uint nextCellNo = 0; //If this isn't true something terribly wrong has happened if (FindRoomPos(curCellNo, ref curCellRow, ref curCellCol)) { this.m_startRoom = curCellNo; while (cellsVisited < m_totalRooms) { if (FindNeighborWithWallsUp(curCellNo, ref nextCellNo)) { FindRoomPos(nextCellNo, ref nextCellRow, ref nextCellCol); KnockDownWall(curCellRow, curCellCol, nextCellRow, nextCellCol); cellStack.Push(curCellNo); curCellNo = (UInt16)nextCellNo; cellsVisited++; } else { curCellNo = (UInt16)cellStack.Pop(); } } } else throw ( new InvalidRoomNoException()); } public bool HasWallsUp(UInt16 cRow, UInt16 cCol) { bool ret_val = false; if((m_rooms[cRow, cCol] & ANY_WALLS_UP) > 0) ret_val = true; return ret_val; } public void Draw() { int roomSet = 1; for (int r = 0; r < this.m_rows; r++) { for (int c = 0; c < this.m_columns; c++) { //Console.WriteLine("No: {0} Val: {1} or {1,9:X8}", roomSet - 1, this.m_rooms[r, c]); roomSet++; if ((this.m_rooms[r, c] & S_WALL_UP) != 0 || (r == this.m_rows - 1)) Console.Write("_"); else Console.Write(" "); if ((this.m_rooms[r, c] & E_WALL_UP) != 0 || (c == this.m_columns - 1)) Console.Write("|"); else Console.Write(" "); } Console.Write("\n"); } } public uint Rooms { get { return m_totalRooms; } } public uint Walls { get { return m_totalWalls; } } protected void Initialize() { this.m_totalRooms = this.m_rows * this.m_columns; this.m_totalWalls = this.m_totalRooms + ((this.m_rows - 1) * (this.m_columns - 1) - 1); this.m_rooms = new UInt16[this.m_rows, this.m_columns]; this.m_roomSet = new uint[this.m_totalRooms]; uint roomSet = 1; uint mask = 0; for (int r = 0; r < this.m_rows; r++) for (int c = 0; c < this.m_columns; c++) { mask = ALL_WALLS_UP; if (r == 0) mask ^= N_BORDER_UP | N_WALL_UP; if (c == 0) mask ^= W_BORDER_UP | W_WALL_UP; if (r == this.m_rows - 1) mask ^= S_BORDER_UP | S_WALL_UP; if (c == this.m_columns - 1) mask ^= E_BORDER_UP | E_WALL_UP; this.m_rooms[r,c] = (ushort)(mask); this.m_roomSet[roomSet -1] = roomSet++; } } protected void KnockDownWall(UInt16 cRow, UInt16 cCol, UInt16 nRow, UInt16 nCol) { switch (cRow == nRow) { case true: if (cCol > nCol) { this.m_rooms[cRow, cCol] ^= W_WALL_UP; this.m_rooms[nRow, nCol] ^= E_WALL_UP; } else { this.m_rooms[cRow, cCol] ^= E_WALL_UP; this.m_rooms[nRow, nCol] ^= W_WALL_UP; } break; default: switch (cCol == nCol) { case true: if (cRow > nRow) { this.m_rooms[cRow, cCol] ^= N_WALL_UP; this.m_rooms[nRow, nCol] ^= S_WALL_UP; } else { this.m_rooms[cRow, cCol] ^= S_WALL_UP; this.m_rooms[nRow, nCol] ^= N_WALL_UP; } break; default: break; } break; } } protected bool FindRoomNo(UInt16 cRow, UInt16 cCol, ref uint cRoomNo) { bool ret_val = false; cRoomNo = 0; if ((cRow >= 0 && cRow < this.m_rows) && (cCol >= 0 && cCol < this.m_columns)) { cRoomNo = (cRow * this.m_columns) + cCol; ret_val = true; } return ret_val; } protected bool FindRoomPos(uint roomNo, ref UInt16 row, ref UInt16 column) { bool ret_val = false; if (roomNo >= 0 && roomNo < this.m_totalRooms) { row = (UInt16)(roomNo / this.m_columns); column = (UInt16)(roomNo % this.m_columns); ret_val = true; } return ret_val; } protected bool FindNeighborWithWallsUp(uint cCellNo, ref uint nCellNo) { bool ret_val = false; uint rTemp = 0; UInt16 curCellRow = 0, curCellCol = 0, nextCellRow = 0, nextCellCol = 0; uint[] neighbors = new uint[4]; int x; if (cCellNo < this.m_totalRooms) { FindRoomPos(cCellNo, ref curCellRow, ref curCellCol); switch (rTemp = NumberOfNeighbors(curCellRow, curCellCol, ref neighbors)) { case 2: case 3: case 4: Random rand = new Random(); int i = (int)rand.Next((int)(rTemp - 1)); for (x = i; x < rTemp && !ret_val; x++) if (FindRoomPos(neighbors[x], ref nextCellRow, ref nextCellCol) && HasWallsUp(nextCellRow, nextCellCol)) { FindRoomNo(nextCellRow, nextCellCol, ref nCellNo); if (this.m_roomSet[nCellNo] != 0) { this.m_roomSet[nCellNo] = 0; ret_val = true; } } for (x = i - 1; x > -1 && !ret_val; x--) if (FindRoomPos(neighbors[x], ref nextCellRow, ref nextCellCol) && HasWallsUp(nextCellRow, nextCellCol)) { FindRoomNo(nextCellRow, nextCellCol, ref nCellNo); if (this.m_roomSet[nCellNo] != 0) { this.m_roomSet[nCellNo] = 0; ret_val = true; } } break; default: break; } } return ret_val; } protected uint NumberOfNeighbors(uint cRow, uint cCol, ref uint[] nArray) { uint ret_val = 0; uint c = 0; uint curRoomNo = 0; // Either top row or bottom row corners if (((cRow % (m_rows - 1)) == 0) && ((cCol % (m_columns - 1)) == 0)) ret_val = 2; // Outer edge middle cells else if (((cRow % (m_rows - 1)) == 0) || ((cCol % (m_columns - 1)) == 0)) ret_val = 3; else // Somewhere in the middle ret_val = 4; if (FindRoomNo((UInt16)(cRow - 1), (UInt16)cCol, ref curRoomNo)) nArray[c++] = curRoomNo; if (FindRoomNo((UInt16)(cRow + 1), (UInt16)cCol, ref curRoomNo)) nArray[c++] = curRoomNo; if (FindRoomNo((UInt16)cRow, (UInt16)(cCol - 1), ref curRoomNo)) nArray[c++] = curRoomNo; if (FindRoomNo((UInt16)cRow, (UInt16)(cCol + 1), ref curRoomNo)) nArray[c++] = curRoomNo; return ret_val; } protected uint m_totalRooms; protected uint m_totalWalls; protected uint m_rows; protected uint m_columns; protected UInt16[,] m_rooms; protected uint[] m_roomSet; protected uint m_startRoom, m_finishRoom; protected const UInt16 N_WALL_UP = 0x01; protected const UInt16 E_WALL_UP = N_WALL_UP << 1; protected const UInt16 S_WALL_UP = E_WALL_UP << 1; protected const UInt16 W_WALL_UP = S_WALL_UP << 1; protected const UInt16 ALL_WALLS_UP = N_WALL_UP | E_WALL_UP | S_WALL_UP | W_WALL_UP; protected const UInt16 ANY_WALLS_UP = ALL_WALLS_UP; protected const UInt16 N_BORDER_UP = N_WALL_UP << 4; protected const UInt16 E_BORDER_UP = N_BORDER_UP << 1; protected const UInt16 S_BORDER_UP = E_BORDER_UP << 1; protected const UInt16 W_BORDER_UP = S_BORDER_UP << 1; protected const UInt16 ANY_BORDERS_UP = N_BORDER_UP | E_BORDER_UP | S_BORDER_UP | W_BORDER_UP; } class InvalidMazeDimensionException : Exception { public InvalidMazeDimensionException(){} public InvalidMazeDimensionException( string msg ) : base( msg ){} public InvalidMazeDimensionException( string msg, Exception e ): base( msg, e ){} } class InvalidRoomNoException : Exception { public InvalidRoomNoException() { } public InvalidRoomNoException(string msg) : base(msg) { } public InvalidRoomNoException(string msg, Exception e) : base(msg, e) { } } }