Skip to content

Commit b4a0dde

Browse files
committed
24: Generating maze using depth-first
1 parent 570e337 commit b4a0dde

File tree

1 file changed

+180
-61
lines changed

1 file changed

+180
-61
lines changed

challenges/24_Maze/Maze.cs

Lines changed: 180 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,35 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Reflection;
4+
using System.Threading;
35

46
class Maze {
7+
private const string WallWithLeftSideEmpty = " ";
8+
9+
private delegate void Go();
10+
11+
private const string WallWithLeftSideEmptyAndCursor = " ■ ";
12+
13+
private const string WallWithLeftSideFull = "| ";
14+
15+
private const string WallWithLeftSideFullAndCursor = "| ■ ";
516

6-
private const string WallWithLeftSideEmpty = "= ";
7-
private const string WallWithLeftSideFull = "| ";
817
private const string FloorWithHole = "+ ";
18+
919
private const string FloorWithoutHole = "+---";
20+
1021
private const string WallEnd = "|\n";
11-
private const string WallEndWithExit = "=\n";
22+
23+
private const string WallEndWithExit = " \n";
24+
1225
private const string FloorCorner = "+\n";
26+
1327
private static Cell[][] _maze;
1428

15-
static void Main(string[] args){
29+
private static (int, int) _cursor;
30+
31+
32+
static void Main(string[] args) {
1633
Console.ForegroundColor = ConsoleColor.Green;
1734
Console.CursorVisible = false;
1835
Console.Title = "Maze";
@@ -68,39 +85,174 @@ private static void GenerateMaze(bool showAnimation) {
6885
Console.WriteLine("Generating maze " + width + "x" + height);
6986
GenerateEmptyMaze(width, height);
7087

71-
MazeGeneratingAlgorithm();
88+
MazeGeneratingAlgorithm(showAnimation);
7289

73-
PrintMaze();
90+
PrintMaze(false);
91+
Console.WriteLine("Press any key to Quit");
7492
Console.ReadKey();
7593
}
7694

77-
private static void MazeGeneratingAlgorithm() {
95+
private static void MazeGeneratingAlgorithm(bool showAnimation) {
96+
var random = new Random();
7897
// Starting point at (0, 0)
7998
_maze[0][0].Left = true;
80-
var cursor = (0, 0);
99+
100+
// Pick random place (why not?)
101+
_cursor = (random.Next(0, _maze.Length), random.Next(0, _maze[0].Length));
102+
_maze[_cursor.Item1][_cursor.Item2].Visited = true;
103+
104+
// Add first item to stack
81105
var logStack = new Stack<(int, int)>();
106+
logStack.Push(_cursor);
107+
108+
// Delegate to store method. I just wanted to try it...
109+
Go go = null;
110+
82111
// Depth-first search algorithm
83112

84113
do {
85-
_maze[cursor.Item1][cursor.Item2].Visited = true;
86-
logStack.Push(cursor);
87-
88-
if (IsDeadEnd(cursor)) {
114+
if (IsDeadEnd(_cursor)) {
115+
if (logStack.Count <= 1) break;
89116
logStack.Pop();
90-
if(logStack.Count == 0) break;
117+
_cursor = logStack.Peek();
118+
if (showAnimation) {
119+
Thread.Sleep(100);
120+
PrintMaze(true);
121+
}
122+
continue;
91123
}
92124

125+
if (IsBottomCellNotVisited(_cursor))
126+
go += GoBottom;
127+
128+
if (IsTopCellNotVisited(_cursor))
129+
go += GoTop;
130+
131+
if (IsLeftCellNotVisited(_cursor))
132+
go += GoLeft;
133+
134+
if (IsRightCellNotVisited(_cursor))
135+
go += GoRight;
136+
137+
go = (Go) go.GetInvocationList()[random.Next(0, go.GetInvocationList().Length)];
138+
go();
139+
go = null;
140+
logStack.Push(_cursor);
141+
if (showAnimation) {
142+
Thread.Sleep(300);
143+
PrintMaze(true);
144+
}
93145

146+
} while (logStack.Count > 0);
94147

95-
} while (cursor.Equals((0, 0)));
148+
// Exit at bottom right corner
149+
_maze[_maze.Length - 1][_maze[0].Length - 1].Right = true;
150+
}
151+
private static void GoBottom() {
152+
_maze[_cursor.Item1][_cursor.Item2].Bottom = true;
153+
_cursor.Item1 += 1;
154+
_cursor.Item2 += 0;
155+
_maze[_cursor.Item1][_cursor.Item2].Visited = true;
156+
_maze[_cursor.Item1][_cursor.Item2].Top = true;
157+
}
158+
159+
private static void GoTop() {
160+
_maze[_cursor.Item1][_cursor.Item2].Top = true;
161+
_cursor.Item1 += -1;
162+
_cursor.Item2 += 0;
163+
_maze[_cursor.Item1][_cursor.Item2].Visited = true;
164+
_maze[_cursor.Item1][_cursor.Item2].Bottom = true;
165+
}
96166

167+
private static void GoLeft() {
168+
_maze[_cursor.Item1][_cursor.Item2].Left = true;
169+
_cursor.Item1 += 0;
170+
_cursor.Item2 += -1;
171+
_maze[_cursor.Item1][_cursor.Item2].Visited = true;
172+
_maze[_cursor.Item1][_cursor.Item2].Right = true;
173+
}
97174

98-
// Exit at bottom right corner
99-
_maze[_maze.Length-1][_maze[0].Length-1].Right = true;
175+
private static void GoRight() {
176+
_maze[_cursor.Item1][_cursor.Item2].Right = true;
177+
_cursor.Item1 += 0;
178+
_cursor.Item2 += 1;
179+
_maze[_cursor.Item1][_cursor.Item2].Visited = true;
180+
_maze[_cursor.Item1][_cursor.Item2].Left = true;
100181
}
101182

102-
private static bool IsDeadEnd((int, int) cursor) {
183+
private static void PrintMaze(bool printCursor) {
184+
Console.Clear();
185+
PrintTitle();
186+
187+
//+---+
188+
//| | 1x1 block
189+
//+---+
190+
191+
var board = "";
192+
// Add first line
193+
board = AddOneLine(board);
194+
195+
// Crate one maze in one string
196+
for (var row = 0; row < _maze.Length; row++) {
197+
for (var k = 1; k <= 2; k++) {
198+
for (var column = 0; column < _maze[row].Length; column++) {
199+
board = AddMazeFragment(printCursor, board, row, k, column);
200+
}
201+
board = AddEndLines(board, k, row);
202+
}
203+
}
204+
205+
// Print maze
206+
Console.WriteLine(board);
207+
}
208+
209+
private static string AddMazeFragment(bool printCursor, string board, int row, int k, int column) {
210+
if (ShouldPrintVertical(k)) {
211+
board = AddWall(printCursor, board, row, column);
212+
} else {
213+
board = AddFloor(board, row, column);
214+
}
215+
216+
return board;
217+
}
218+
219+
private static string AddWall(bool printCursor, string board, int row, int column) {
220+
if (ShouldPrintWall(row, column))
221+
board = AddWallWithFullSideAndCursor(printCursor, board, row, column);
222+
else {
223+
board = AddWallWithFullSide(printCursor, board, row, column);
224+
}
103225

226+
return board;
227+
}
228+
229+
private static string AddFloor(string board, int row, int column) {
230+
if (ShouldPrintFloor(row, column))
231+
board += FloorWithoutHole;
232+
else {
233+
board += FloorWithHole;
234+
}
235+
236+
return board;
237+
}
238+
239+
private static string AddWallWithFullSide(bool printCursor, string board, int row, int column) {
240+
if (printCursor && CursorIsAtPosition(row, column))
241+
board += WallWithLeftSideEmptyAndCursor;
242+
else
243+
board += WallWithLeftSideEmpty;
244+
return board;
245+
}
246+
247+
private static string AddWallWithFullSideAndCursor(bool printCursor, string board, int row, int column) {
248+
if (printCursor && CursorIsAtPosition(row, column))
249+
board += WallWithLeftSideFullAndCursor;
250+
else
251+
board += WallWithLeftSideFull;
252+
return board;
253+
}
254+
255+
private static bool IsDeadEnd((int, int) cursor) {
104256
// Cell that has no unvisited neighbors being considered a dead-end ~ Wikipedia
105257

106258
// cursor.Item1 - Row (Y)
@@ -117,7 +269,7 @@ private static bool IsDeadEnd((int, int) cursor) {
117269
}
118270

119271
// Left
120-
if (IsLeftCellNotVisisted(cursor)) {
272+
if (IsLeftCellNotVisited(cursor)) {
121273
return false;
122274
}
123275

@@ -133,7 +285,7 @@ private static bool IsRightCellNotVisited((int, int) cursor) {
133285
return IsCellOnRight(cursor) && !_maze[cursor.Item1][cursor.Item2 + 1].Visited;
134286
}
135287

136-
private static bool IsLeftCellNotVisisted((int, int) cursor) {
288+
private static bool IsLeftCellNotVisited((int, int) cursor) {
137289
return IsCellOnLeft(cursor) && !_maze[cursor.Item1][cursor.Item2 - 1].Visited;
138290
}
139291

@@ -146,19 +298,19 @@ private static bool IsTopCellNotVisited((int, int) cursor) {
146298
}
147299

148300
private static bool IsCellOnRight((int, int) cursor) {
149-
return cursor.Item2 + 1 <= _maze[0].Length;
301+
return cursor.Item2 + 1 < _maze[0].Length;
150302
}
151303

152304
private static bool IsCellOnLeft((int, int) cursor) {
153-
return cursor.Item2 - 1 > 0;
305+
return cursor.Item2 - 1 >= 0;
154306
}
155307

156308
private static bool IsCellBelowCursor((int, int) cursor) {
157-
return cursor.Item1 + 1 <= _maze.Length;
309+
return cursor.Item1 + 1 < _maze.Length;
158310
}
159311

160312
private static bool IsCellAboveCursor((int, int) cursor) {
161-
return cursor.Item1 - 1 > 0;
313+
return cursor.Item1 - 1 >= 0;
162314
}
163315

164316
private static bool CursorIsCorrect((int, int) cursor) {
@@ -168,41 +320,8 @@ private static bool CursorIsCorrect((int, int) cursor) {
168320
cursor.Item2 + 1 < _maze[0].Length;
169321
}
170322

171-
private static void PrintMaze() {
172-
Console.Clear();
173-
PrintTitle();
174-
175-
//+---+
176-
//| | 1x1 block
177-
//+---+
178-
179-
var board = "";
180-
// Add first line
181-
board = AddOneLine(board);
182-
183-
// Add all maze
184-
for (var row = 0; row < _maze.Length; row++) {
185-
for (var k = 1; k <= 2; k++) {
186-
for (var column = 0; column < _maze[row].Length; column++) {
187-
if (ShouldPrintVertical(k)) {
188-
if (ShouldPrintWall(row, column))
189-
board += WallWithLeftSideFull;
190-
else {
191-
board += WallWithLeftSideEmpty;
192-
}
193-
} else {
194-
if (ShouldPrintFloor(row, column))
195-
board += FloorWithoutHole;
196-
else {
197-
board += FloorWithHole;
198-
}
199-
}
200-
}
201-
board = AddEndLines(board, k, row);
202-
}
203-
}
204-
// Print maze
205-
Console.WriteLine(board);
323+
private static bool CursorIsAtPosition(int row, int column) {
324+
return _cursor.Item1 == row && _cursor.Item2 == column;
206325
}
207326

208327
private static bool ShouldPrintFloor(int row, int column) {
@@ -215,7 +334,7 @@ private static bool ShouldPrintWall(int row, int column) {
215334

216335
private static string AddEndLines(string board, int k, int row) {
217336
if (ShouldPrintVertical(k)) {
218-
if (_maze[row][_maze.Length-1].Right) {
337+
if (_maze[row][_maze[0].Length - 1].Right) {
219338
board += WallEndWithExit;
220339
} else {
221340
board += WallEnd;
@@ -253,7 +372,7 @@ private static void GenerateEmptyMaze(int width, int height) {
253372
private static int GetWidthFromPlayer() {
254373
int width;
255374
Console.Write("\bEnter width: ");
256-
while (!int.TryParse(Console.ReadLine(), out width) || width < 2 || width > 100) {
375+
while (!int.TryParse(Console.ReadLine(), out width) || width < 1 || width > 100) {
257376
Console.WriteLine("Wrong value");
258377
Console.Write("\bEnter width: ");
259378
}
@@ -264,7 +383,7 @@ private static int GetWidthFromPlayer() {
264383
private static int GetHeightFromPlayer() {
265384
int height;
266385
Console.Write("\bEnter height: ");
267-
while (!int.TryParse(Console.ReadLine(), out height) || height < 2 || height > 100) {
386+
while (!int.TryParse(Console.ReadLine(), out height) || height < 1 || height > 100) {
268387
Console.WriteLine("Wrong value");
269388
Console.Write("\bEnter height: ");
270389
}

0 commit comments

Comments
 (0)