1
\$\begingroup\$

Intro

Still working on PathFinding.java. This time I concentrate on three private methods of GridModel that are responsible for generating random perfect mazes. A maze is perfect if for each two cells in the maze there is only and exactly one route between them.

How it looks like:

A random perfect maze in a 2D grid graph. Also, I have a short animation: https://youtu.be/IFwTL4puA9c?si=20r0yoliPI73XubY

Code

private void drawViaDFS(Random rnd) {
 int rows = height;
 int cols = width;
 if (height % 2 == 0) {
 rows--;
 }
 if (width % 2 == 0) {
 cols--;
 }
 int roomCols = (cols - 1) / 2; // Number of "rooms" horizontally.
 int roomRows = (rows - 1) / 2; // Number of "rooms" vertically.
 boolean[][] visited = new boolean[roomRows]
 [roomCols];
 // Pick a random room (mapped to grid coords: rr -> 2 * rr + 1):
 int rr = rnd.nextInt(roomRows); 
 int cc = rnd.nextInt(roomCols);
 // Carve the inital room from its wall:
 carveCell(cc, rr);
 // Initialize DFS stack:
 Deque<int[]> stack = new ArrayDeque<>();
 visited[rr][cc] = true;
 stack.push(new int[]{ cc, rr });
 // 4-neighbor moves in room space
 int[] deltaRowOffsets = { -1, 0, 1, 0 };
 int[] deltaColOffsets = { 0, 1, 0, -1 };
 int[] directionIndices = { 0, 1, 2, 3 };
 while (!stack.isEmpty()) {
 int[] cur = stack.peek();
 int c0 = cur[0];
 int r0 = cur[1];
 // Fisher–Yates shuffle:
 for (int i = 3; i > 0; i--) {
 int j = rnd.nextInt(i + 1);
 int t = directionIndices[i];
 directionIndices[i] = directionIndices[j];
 directionIndices[j] = t;
 }
 boolean moved = false;
 for (int directionIndex : directionIndices) {
 int r1 = r0 + deltaRowOffsets[directionIndex]; 
 int c1 = c0 + deltaColOffsets[directionIndex];
 if (0 <= r1 
 && r1 < roomRows 
 && 0 <= c1 
 && c1 < roomCols 
 && !visited[r1][c1]) {
 // Carve passage between rooms (r0, c0) and (r1, c1):
 carveBetween(c0, 
 r0,
 c1,
 r1);
 carveCell(c1, r1);
 visited[r1][c1] = true;
 stack.push(new int[]{ c1, r1 });
 moved = true;
 break;
 }
 }
 if (!moved) {
 stack.pop();
 }
 }
}
private void carveCell(int roomX, int roomY) {
 int x = 2 * roomX + 1;
 int y = 2 * roomY + 1;
 setCellType(x, y, CellType.FREE);
}
private void carveBetween(int roomX0,
 int roomY0,
 int roomX1,
 int roomY1) {
 int cellX0 = 2 * roomX0 + 1;
 int cellY0 = 2 * roomY0 + 1;
 int cellX1 = 2 * roomX1 + 1;
 int cellY1 = 2 * roomY1 + 1;
 int x = (cellX0 + cellX1) / 2;
 int y = (cellY0 + cellY1) / 2;
 setCellType(x, y, CellType.FREE);
}

Critique request

My primary concern this time is the code readability and variable naming.

asked Sep 12 at 10:27
\$\endgroup\$
3
  • 2
    \$\begingroup\$ You're using a two element array to represent a row-column coordinate. Don't be lazy, just create a record for that. You can reuse that in your Cell class instead of storing x and y (and there's an inconsistency, use x,y or row,col everywhere, don't mix). \$\endgroup\$ Commented Sep 15 at 11:17
  • \$\begingroup\$ @TorbenPutkonen Yes, Sir! \$\endgroup\$ Commented Sep 15 at 13:51
  • 2
    \$\begingroup\$ Not a review, but the maze demonstrated in the screenshot is not a perfect maze, ~4 tiles down-left of the red tile there is a cycle of floor tiles, this allows multiple routes between pairs of tiles (it's also in a completely isolated section of maze, meaning there are several pairs of tiles with no route between them). \$\endgroup\$ Commented Sep 16 at 1:54

0

Know someone who can answer? Share a link to this question via email, Twitter, or Facebook.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.