-
Notifications
You must be signed in to change notification settings - Fork 0
/
DeadEndFillingSolver.cs
192 lines (171 loc) · 7.63 KB
/
DeadEndFillingSolver.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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
using BWolf.MazeGeneration;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace BWolf.MazeSolving
{
public class DeadEndFillingSolver : MazeSolver
{
/// <summary>
/// Solves the maze by creating a solution path using the DeadEndFilling Algorithm
/// </summary>
/// <param name="service"></param>
public override void SolveMaze(MazeSolvingService service)
{
//fill dead ends of the maze until junktions are found
IEnumerable<MazeCell> deadEnds = service.Cells.Cast<MazeCell>().Where(cell => cell.IsDeadEnd);
foreach (MazeCell deadEnd in deadEnds)
{
CheckUntilJunction(deadEnd, service);
}
//start walking from the entrance
MazeCell walker = service.EntranceCell;
walker.MarkAsPartOfSolution();
//loop until the walker is at the exit
MazeCell exitCell = service.ExitCell;
while (walker != exitCell)
{
//get the next cell that is on the path towards the exit
List<MazeCell> nextCellsInPath = service.GetNextCellsInPath(walker);
if (nextCellsInPath.Count == 1)
{
//make the cell part of the path solution
MazeCell nextCellInPath = nextCellsInPath[0];
nextCellInPath.MarkAsPartOfSolution();
//mark its walls as part of the solution aswell
walker.MarkWallAsPartOfSolution(nextCellInPath);
nextCellInPath.MarkWallAsPartOfSolution(walker);
//the next cell in the solution path is now the walker
walker = nextCellInPath;
}
else
{
throw new System.InvalidOperationException($"The solution path could not be created from {walker.name} with {nextCellsInPath.Count} next cells in path :: this is unintended behaviour!");
}
}
}
/// <summary>
/// Marks the maze as checked from given walker cell until a junction is met
/// </summary>
/// <param name="walker"></param>
/// <param name="service"></param>
/// <returns></returns>
private void CheckUntilJunction(MazeCell walker, MazeSolvingService service)
{
walker.MarkAsChecked();
//loop until a junction is found and is borken out of the loop
while (true)
{
//get the next cell in the current path
List<MazeCell> cellsNextInPath = service.GetNextCellsInPath(walker);
if (cellsNextInPath.Count == 1)
{
//save it is a junction
MazeCell nextCellInPath = cellsNextInPath[0];
bool isJunction = nextCellInPath.IsJunction;
//mark the walls as checked
walker.MarkWallAsChecked(nextCellInPath);
nextCellInPath.MarkWallAsChecked(walker);
if (isJunction)
{
//if the cell was a junction, break out of the loop
break;
}
else
{
//if the cell wasn't a junction, mark the cell as checked and continue from it
nextCellInPath.MarkAsChecked();
walker = nextCellInPath;
}
}
else
{
throw new System.InvalidOperationException($"Filling in until junktion failed :: there should be one next cell in {walker}'s path each time");
}
}
}
/// <summary>
/// Returns an enumerator that solves the maze by creating a solution path using the DeadEndFilling Algorithm
/// </summary>
/// <param name="service"></param>
public override IEnumerator SolveMazeRoutine(MazeSolvingService service)
{
//fill dead ends of the maze until junktions are found
IEnumerable<MazeCell> deadEnds = service.Cells.Cast<MazeCell>().Where(cell => cell.IsDeadEnd);
foreach (MazeCell deadEnd in deadEnds)
{
yield return CheckUntilJunctionRoutine(deadEnd, service);
}
//start walking from the entrance
MazeCell walker = service.EntranceCell;
walker.MarkAsPartOfSolution();
yield return null;
//loop until the walker is at the exit
MazeCell exitCell = service.ExitCell;
while (walker != exitCell)
{
//get the next cell that is on current path
List<MazeCell> nextCellsInPath = service.GetNextCellsInPath(walker);
if (nextCellsInPath.Count == 1)
{
//make the cell part of the path solution
MazeCell nextCellInPath = nextCellsInPath[0];
nextCellInPath.MarkAsPartOfSolution();
//mark its walls as part of the solution aswell
walker.MarkWallAsPartOfSolution(nextCellInPath);
nextCellInPath.MarkWallAsPartOfSolution(walker);
//the next cell in the path is now the walker
walker = nextCellInPath;
}
else
{
throw new System.InvalidOperationException($"The solution path could not be created from {walker.name} with {nextCellsInPath.Count} next cells in path :: this is unintended behaviour!");
}
yield return null;
}
CompletedRoutine();
}
/// <summary>
/// Returns an enumerator that marks the maze as checked from given walker cell until a junction is met
/// </summary>
/// <param name="walker"></param>
/// <param name="service"></param>
/// <returns></returns>
private IEnumerator CheckUntilJunctionRoutine(MazeCell walker, MazeSolvingService service)
{
walker.MarkAsChecked();
yield return null;
//loop until a junction is found and is borken out of the loop
while (true)
{
//get the next cell in the current path
List<MazeCell> cellsNextInPath = service.GetNextCellsInPath(walker);
if (cellsNextInPath.Count == 1)
{
//save it is a junction
MazeCell nextCellInPath = cellsNextInPath[0];
bool isJunction = nextCellInPath.IsJunction;
//mark the walls as checked
walker.MarkWallAsChecked(nextCellInPath);
nextCellInPath.MarkWallAsChecked(walker);
if (isJunction)
{
//if the cell was a junction, break out of the loop
break;
}
else
{
//if the cell wasn't a junction, mark the cell as checked and continue from it
nextCellInPath.MarkAsChecked();
walker = nextCellInPath;
}
}
else
{
throw new System.InvalidOperationException($"Filling in until junktion failed :: there should be one next cell in {walker}'s path each time");
}
yield return null;
}
}
}
}