Skip to content

Commit 70e8e9a

Browse files
committed
added MazeUtils for new recipe w/@mballin
1 parent 5a5c9c0 commit 70e8e9a

4 files changed

Lines changed: 2835 additions & 0 deletions

File tree

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
package org.teachingextensions.logo.shapes.MazeUtils;
2+
3+
/******************************************************************************
4+
* Compilation: javac Maze.java
5+
* Execution: java Maze.java N
6+
* Dependencies: StdDraw.java
7+
*
8+
* Generates a perfect N-by-N maze using depth-first search with a stack.
9+
*
10+
* % java Maze 62
11+
*
12+
* % java Maze 61
13+
*
14+
* Note: this program generalizes nicely to finding a random tree
15+
* in a graph.
16+
*
17+
******************************************************************************/
18+
public class Maze
19+
{
20+
private int N; // dimension of maze
21+
private boolean[][] north; // is there a wall to north of cell i, j
22+
private boolean[][] east;
23+
private boolean[][] south;
24+
private boolean[][] west;
25+
private boolean[][] visited;
26+
private boolean done = false;
27+
public Maze(int N)
28+
{
29+
this.N = N;
30+
StdDraw.setXscale(0, N + 2);
31+
StdDraw.setYscale(0, N + 2);
32+
init();
33+
generate();
34+
}
35+
private void init()
36+
{
37+
// initialize border cells as already visited
38+
visited = new boolean[N + 2][N + 2];
39+
for (int x = 0; x < N + 2; x++)
40+
{
41+
visited[x][0] = true;
42+
visited[x][N + 1] = true;
43+
}
44+
for (int y = 0; y < N + 2; y++)
45+
{
46+
visited[0][y] = true;
47+
visited[N + 1][y] = true;
48+
}
49+
// initialze all walls as present
50+
north = new boolean[N + 2][N + 2];
51+
east = new boolean[N + 2][N + 2];
52+
south = new boolean[N + 2][N + 2];
53+
west = new boolean[N + 2][N + 2];
54+
for (int x = 0; x < N + 2; x++)
55+
{
56+
for (int y = 0; y < N + 2; y++)
57+
{
58+
north[x][y] = true;
59+
east[x][y] = true;
60+
south[x][y] = true;
61+
west[x][y] = true;
62+
}
63+
}
64+
}
65+
// generate the maze
66+
private void generate(int x, int y)
67+
{
68+
visited[x][y] = true;
69+
// while there is an unvisited neighbor
70+
while (!visited[x][y + 1] || !visited[x + 1][y] || !visited[x][y - 1] || !visited[x - 1][y])
71+
{
72+
// pick random neighbor (could use Knuth's trick instead)
73+
while (true)
74+
{
75+
double r = StdRandom.uniform(4);
76+
if (r == 0 && !visited[x][y + 1])
77+
{
78+
north[x][y] = false;
79+
south[x][y + 1] = false;
80+
generate(x, y + 1);
81+
break;
82+
}
83+
else if (r == 1 && !visited[x + 1][y])
84+
{
85+
east[x][y] = false;
86+
west[x + 1][y] = false;
87+
generate(x + 1, y);
88+
break;
89+
}
90+
else if (r == 2 && !visited[x][y - 1])
91+
{
92+
south[x][y] = false;
93+
north[x][y - 1] = false;
94+
generate(x, y - 1);
95+
break;
96+
}
97+
else if (r == 3 && !visited[x - 1][y])
98+
{
99+
west[x][y] = false;
100+
east[x - 1][y] = false;
101+
generate(x - 1, y);
102+
break;
103+
}
104+
}
105+
}
106+
}
107+
// generate the maze starting from lower left
108+
private void generate()
109+
{
110+
generate(1, 1);
111+
/*
112+
// delete some random walls
113+
for (int i = 0; i < N; i++) {
114+
int x = 1 + StdRandom.uniform(N-1);
115+
int y = 1 + StdRandom.uniform(N-1);
116+
north[x][y] = south[x][y+1] = false;
117+
}
118+
119+
// add some random walls
120+
for (int i = 0; i < 10; i++) {
121+
int x = N/2 + StdRandom.uniform(N/2);
122+
int y = N/2 + StdRandom.uniform(N/2);
123+
east[x][y] = west[x+1][y] = true;
124+
}
125+
*/
126+
}
127+
// solve the maze using depth-first search
128+
private void solve(int x, int y)
129+
{
130+
if (x == 0 || y == 0 || x == N + 1 || y == N + 1)
131+
return;
132+
if (done || visited[x][y])
133+
return;
134+
visited[x][y] = true;
135+
StdDraw.setPenColor(StdDraw.BLUE);
136+
StdDraw.filledCircle(x + 0.5, y + 0.5, 0.25);
137+
StdDraw.show(30);
138+
// reached middle
139+
if (x == N / 2 && y == N / 2)
140+
done = true;
141+
if (!north[x][y])
142+
solve(x, y + 1);
143+
if (!east[x][y])
144+
solve(x + 1, y);
145+
if (!south[x][y])
146+
solve(x, y - 1);
147+
if (!west[x][y])
148+
solve(x - 1, y);
149+
if (done)
150+
return;
151+
StdDraw.setPenColor(StdDraw.GRAY);
152+
StdDraw.filledCircle(x + 0.5, y + 0.5, 0.25);
153+
StdDraw.show(30);
154+
}
155+
// solve the maze starting from the start state
156+
public void solve()
157+
{
158+
for (int x = 1; x <= N; x++)
159+
for (int y = 1; y <= N; y++)
160+
visited[x][y] = false;
161+
done = false;
162+
solve(1, 1);
163+
}
164+
// draw the maze
165+
public void draw()
166+
{
167+
StdDraw.setPenColor(StdDraw.RED);
168+
StdDraw.filledCircle(N / 2.0 + 0.5, N / 2.0 + 0.5, 0.375);
169+
StdDraw.filledCircle(1.5, 1.5, 0.375);
170+
StdDraw.setPenColor(StdDraw.BLACK);
171+
for (int x = 1; x <= N; x++)
172+
{
173+
for (int y = 1; y <= N; y++)
174+
{
175+
if (south[x][y])
176+
StdDraw.line(x, y, x + 1, y);
177+
if (north[x][y])
178+
StdDraw.line(x, y + 1, x + 1, y + 1);
179+
if (west[x][y])
180+
StdDraw.line(x, y, x, y + 1);
181+
if (east[x][y])
182+
StdDraw.line(x + 1, y, x + 1, y + 1);
183+
}
184+
}
185+
StdDraw.show(1000);
186+
}
187+
// a test client
188+
public static void main(String[] args)
189+
{
190+
// This line throws an index out bounds with any value in args ???
191+
//int N = Integer.parseInt(args[0]);
192+
//TODO: change this value to increase the complexity of the Maze
193+
int N = 10;
194+
Maze maze = new Maze(N);
195+
StdDraw.show(0);
196+
maze.draw();
197+
maze.solve();
198+
}
199+
}

0 commit comments

Comments
 (0)