-
Notifications
You must be signed in to change notification settings - Fork 0
/
RecursiveBacktracker.cs
134 lines (102 loc) · 3.9 KB
/
RecursiveBacktracker.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
namespace MazeGen;
using System.Collections.Generic;
public class RecursiveBacktracker : IMazeGenerator, IMazeWalker
{
private RecursiveBacktracker () { }
public static Maze GenerateMaze (int width, int height)
{
Maze maze = new(width, height);
bool[,] visited = new bool[width, height];
CarvePassages((Random.Shared.Next(maze.Width - 1), Random.Shared.Next(maze.Height - 1)), ref maze, ref visited);
return maze;
}
private static void CarvePassages ((int x, int y) cell, ref Maze maze, ref bool[,] visited)
{
visited[cell.x, cell.y] = true;
byte[] dirs = [0b1000, 0b0100, 0b0010, 0b0001];
Random.Shared.Shuffle(dirs);
foreach (byte dir in dirs)
{
switch (dir)
{
case 0b1000:
if (cell.y == 0 || visited[cell.x, cell.y - 1])
continue;
maze[cell] |= 0b10;
CarvePassages((cell.x, cell.y - 1), ref maze, ref visited);
break;
case 0b0100:
if (cell.x == maze.Width - 1 || visited[cell.x + 1, cell.y])
continue;
maze[cell.x + 1, cell.y] |= 0b01;
CarvePassages((cell.x + 1, cell.y), ref maze, ref visited);
break;
case 0b0010:
if (cell.y == maze.Height - 1 || visited[cell.x, cell.y + 1])
continue;
maze[cell.x, cell.y + 1] |= 0b10;
CarvePassages((cell.x, cell.y + 1), ref maze, ref visited);
break;
case 0b0001:
if (cell.x == 0 || visited[cell.x - 1, cell.y])
continue;
maze[cell] |= 0b01;
CarvePassages((cell.x - 1, cell.y), ref maze, ref visited);
break;
}
}
}
public static byte[] WalkMaze (Maze maze)
{
List<byte> path = [];
_ = WalkMaze((0, 0), -1, (maze.Width - 1, maze.Height - 1), maze, ref path);
path.Reverse();
return path.ToArray();
}
private static bool WalkMaze ((int x, int y) cell, int invalidDir, (int x, int y) targetCell, Maze maze, ref List<byte> path)
{
byte[] dirs = [0b1000, 0b0100, 0b0010, 0b0001];
if (invalidDir != -1)
dirs[invalidDir] = 0;
(int x, int y) nextCell = (-1, -1);
int reverseDir = -1;
foreach (byte dir in dirs)
{
switch (dir)
{
case 0:
continue;
case 0b1000:
if ((maze[cell] & 0b10) == 0)
continue;
reverseDir = 2;
nextCell = (cell.x, cell.y - 1);
break;
case 0b0100:
if (cell.x == maze.Width - 1 || (maze[cell.x + 1, cell.y] & 0b01) == 0)
continue;
reverseDir = 3;
nextCell = (cell.x + 1, cell.y);
break;
case 0b0010:
if (cell.y == maze.Height - 1 || (maze[cell.x, cell.y + 1] & 0b10) == 0)
continue;
reverseDir = 0;
nextCell = (cell.x, cell.y + 1);
break;
case 0b0001:
if (cell.x == 0 || (maze[cell] & 0b01) == 0)
continue;
reverseDir = 1;
nextCell = (cell.x - 1, cell.y);
break;
}
if (nextCell == targetCell || WalkMaze(nextCell, reverseDir, targetCell, maze, ref path))
{
path.Add(dir);
return true;
}
}
return false;
}
}