import javafx.application.Application; import javafx.application.Platform; import javafx.stage.Stage; import javafx.scene.Scene; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; /** * Creates a random maze, then solves it by finding a path from the * upper left corner to the lower right corner. After doing * one maze, it waits a while then starts over by creating a * new random maze. The point of the program is to visualize * the process. */ public class Maze extends Application implements Runnable { public static void main(String[] args) { launch(args); } //------------------------------------------------------------------------ int[][] maze; // Description of state of maze. The value of maze[i][j] // is one of the constants wallCode, pathcode, emptyCode, // or visitedCode. (Value can also be negative, temporarily, // inside createMaze().) // A maze is made up of walls and corridors. maze[i][j] // is either part of a wall or part of a corridor. A cell // that is part of a corridor is represented by pathCode // if it is part of the current path through the maze, by // visitedCode if it has already been explored without finding // a solution, and by emptyCode if it has not yet been explored. final static int backgroundCode = 0; final static int wallCode = 1; final static int pathCode = 2; final static int emptyCode = 3; final static int visitedCode = 4; Canvas canvas; // the canvas where the maze is drawn and which fills the whole window GraphicsContext g; // graphics context for drawing on the canvas Color[] color; // colors associated with the preceding 5 constants; int rows = 31; // number of rows of cells in maze, including a wall around edges int columns = 41; // number of columns of cells in maze, including a wall around edges int blockSize = 12; // size of each cell int sleepTime = 4000; // wait time after solving one maze before making another, in milliseconds int speedSleep = 20; // short delay between steps in making and solving maze public void start(Stage stage) { color = new Color[] { Color.rgb(200,0,0), Color.rgb(200,0,0), Color.rgb(128,128,255), Color.WHITE, Color.rgb(200,200,200) }; maze = new int[rows][columns]; canvas = new Canvas(columns*blockSize, rows*blockSize); g = canvas.getGraphicsContext2D(); g.setFill(color[backgroundCode]); g.fillRect(0,0,canvas.getWidth(),canvas.getHeight()); Pane root = new Pane(canvas); Scene scene = new Scene(root); stage.setScene(scene); stage.setResizable(false); stage.setTitle("Maze Generator/Solve"); stage.show(); Thread runner = new Thread(this); runner.setDaemon(true); // so thread won't stop program from ending runner.start(); } void drawSquare( int row, int column, int colorCode ) { // Fill specified square of the grid with the // color specified by colorCode, which has to be // one of the constants emptyCode, wallCode, etc. Platform.runLater( () -> { g.setFill( color[colorCode] ); int x = blockSize * column; int y = blockSize * row; g.fillRect(x,y,blockSize,blockSize); }); } public void run() { // Run method for thread repeatedly makes a maze and then solves it. // Note that all access to the canvas by the thread is done using // Platform.runLater(), so that all drawing to the canvas actually // takes place on the application thread. while (true) { try { Thread.sleep(1000); } // wait a bit before starting catch (InterruptedException e) { } makeMaze(); solveMaze(1,1); synchronized(this) { try { wait(sleepTime); } catch (InterruptedException e) { } } Platform.runLater( () -> { g.setFill(color[backgroundCode]); g.fillRect(0,0,canvas.getWidth(),canvas.getHeight()); }); } } void makeMaze() { // Create a random maze. The strategy is to start with // a grid of disconnected "rooms" separated by walls, // then look at each of the separating walls, in a random // order. If tearing down a wall would not create a loop // in the maze, then tear it down. Otherwise, leave it in place. int i,j; int emptyCt = 0; // number of rooms int wallCt = 0; // number of walls int[] wallrow = new int[(rows*columns)/2]; // position of walls between rooms int[] wallcol = new int[(rows*columns)/2]; for (i = 0; i { g.setFill( color[emptyCode] ); for (int r = 0; r < rows; r++) { for (int c = 0; c < columns; c++) { if (maze[r][c] < 0) g.fillRect( c*blockSize, r*blockSize, blockSize, blockSize ); } } }); synchronized(this) { try { wait(1000); } catch (InterruptedException e) { } } int r; for (i=wallCt-1; i>0; i--) { r = (int)(Math.random() * i); // choose a wall randomly and maybe tear it down tearDown(wallrow[r],wallcol[r]); wallrow[r] = wallrow[i]; wallcol[r] = wallcol[i]; } for (i=1; i