All Downloads are FREE. Search and download functionalities are using the official Maven repository.

simple.server.extension.d20.MazeGenerator Maven / Gradle / Ivy

The newest version!
package simple.server.extension.d20;

import java.util.Random;

/**
 * ***********************************************************************
 * Compilation: javac MazeGenerator.java Execution: java MazeGenerator.java N
 * Dependecies: StdDraw.java
 *
 * Generates a perfect N-by-N maze using depth-first search with a stack.
 *
 * % java MazeGenerator 62
 *
 * Note: this program generalizes nicely to finding a random tree in a graph.
 *
 ************************************************************************
 */
public class MazeGenerator {

    private int N;                 // dimension of maze
    private boolean[][] north;     // is there a wall to north of cell i, j
    private boolean[][] east;
    private boolean[][] south;
    private boolean[][] west;
    private boolean[][] visited;
    private double size;
    private boolean done = false;

    public MazeGenerator(int N) {
        this.N = N;
        StdDraw.setXscale(0, N + 2);
        StdDraw.setYscale(0, N + 2);
        init();
        generate();
    }

    private void init() {
        // initialize border cells as already visited
        visited = new boolean[N + 2][N + 2];
        for (int x = 0; x < N + 2; x++) {
            visited[x][0] = visited[x][N + 1] = true;
        }
        for (int y = 0; y < N + 2; y++) {
            visited[0][y] = visited[N + 1][y] = true;
        }


        // initialze all wells as present
        north = new boolean[N + 2][N + 2];
        east = new boolean[N + 2][N + 2];
        south = new boolean[N + 2][N + 2];
        west = new boolean[N + 2][N + 2];
        for (int x = 0; x < N + 2; x++) {
            for (int y = 0; y < N + 2; y++) {
                north[x][y] = east[x][y] = south[x][y] = west[x][y] = true;
            }
        }
    }

    // generate the maze
    private void generate(int x, int y) {
        visited[x][y] = true;

        // while there is an univisited neighbor
        while (!visited[x][y + 1] || !visited[x + 1][y] || !visited[x][y - 1] || !visited[x - 1][y]) {

            // pick random neighbor (could use Knuth's trick instead)
            while (true) {
                double r = Math.random();
                if (r < 0.25 && !visited[x][y + 1]) {
                    north[x][y] = south[x][y + 1] = false;
                    generate(x, y + 1);
                    break;
                } else if (r >= 0.25 && r < 0.50 && !visited[x + 1][y]) {
                    east[x][y] = west[x + 1][y] = false;
                    generate(x + 1, y);
                    break;
                } else if (r >= 0.5 && r < 0.75 && !visited[x][y - 1]) {
                    south[x][y] = north[x][y - 1] = false;
                    generate(x, y - 1);
                    break;
                } else if (r >= 0.75 && r < 1.00 && !visited[x - 1][y]) {
                    west[x][y] = east[x - 1][y] = false;
                    generate(x - 1, y);
                    break;
                }
            }
        }
    }

    // generate the maze starting from lower left
    private void generate() {
        generate(1, 1);

        /*
         * // delete some random walls for (int i = 0; i < N; i++) { int x =
         * (int) (1 + Math.random() * (N-1)); int y = (int) (1 + Math.random() *
         * (N-1)); north[x][y] = south[x][y+1] = false; }
         *
         * // add some random walls for (int i = 0; i < 10; i++) { int x = (int)
         * (N / 2 + Math.random() * (N / 2)); int y = (int) (N / 2 +
         * Math.random() * (N / 2)); east[x][y] = west[x+1][y] = true; }
         */

    }

    // solve the maze using depth first search
    private void solve(int x, int y) {
        if (x == 0 || y == 0 || x == N + 1 || y == N + 1) {
            return;
        }
        if (done || visited[x][y]) {
            return;
        }
        visited[x][y] = true;

        StdDraw.setPenColor(StdDraw.BLUE);
        StdDraw.filledCircle(x + 0.5, y + 0.5, 0.25);
        StdDraw.show(30);

        // reached middle
        if (x == N / 2 && y == N / 2) {
            done = true;
        }

        if (!north[x][y]) {
            solve(x, y + 1);
        }
        if (!east[x][y]) {
            solve(x + 1, y);
        }
        if (!south[x][y]) {
            solve(x, y - 1);
        }
        if (!west[x][y]) {
            solve(x - 1, y);
        }

        if (done) {
            return;
        }

        StdDraw.setPenColor(StdDraw.GRAY);
        StdDraw.filledCircle(x + 0.5, y + 0.5, 0.25);
        StdDraw.show(30);
    }

    // solve the maze starting from the start state
    public void solve() {
        for (int x = 1; x <= N; x++) {
            for (int y = 1; y <= N; y++) {
                visited[x][y] = false;
            }
        }
        done = false;
        solve(1, 1);
    }

    // display the maze in turtle graphics
    public void draw() {
        StdDraw.setPenColor(StdDraw.RED);
        StdDraw.filledCircle(0.5 * N + 0.5, 0.5 * N + 0.5, 0.375);
        StdDraw.filledCircle(1.5, 1.5, 0.375);

        StdDraw.setPenColor(StdDraw.BLACK);
        for (int x = 1; x <= N; x++) {
            for (int y = 1; y <= N; y++) {
                if (south[x][y]) {
                    StdDraw.line(x, y, x + 1, y);
                }
                if (north[x][y]) {
                    StdDraw.line(x, y + 1, x + 1, y + 1);
                }
                if (west[x][y]) {
                    StdDraw.line(x, y, x, y + 1);
                }
                if (east[x][y]) {
                    StdDraw.line(x + 1, y, x + 1, y + 1);
                }
            }
        }
        StdDraw.show(1000);
    }

    // a test client
    public static void main(String[] args) {
        int N = args.length==1?Integer.parseInt(args[0]):new Random().nextInt(100);
        MazeGenerator maze = new MazeGenerator(N);
        StdDraw.show(0);
        maze.draw();
        maze.solve();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy