import javax.swing.JTextArea; import structure.*; /** * @author kim Created on Mar 9, 2004 * * Thread to provide animated solution to a Maze using a stack * */ public class MazeSolver extends Thread implements MazeSolverInterface { protected static final int SLEEP_TIME = 1000; // delay for animation protected MazeGrid grid; // grid holding the maze protected Position start; // starting position in maze protected Position finish; // ending position in maze protected GraphicsMaze gm; // Applet program is running in protected int sleepTime; // How long to sleep between steps protected JTextArea stackDisplay; // Area displaying path so far // Initialize variables so ready to run solver as a separate thread. public MazeSolver( GraphicsMaze gm, MazeGrid grid, Position start, Position finish, int speed, JTextArea stackDisplay) { this.grid = grid; this.start = start; this.finish = finish; this.gm = gm; gm.showStatus("Starting to solve"); this.setSpeed(speed); this.stackDisplay = stackDisplay; } /** * Pre: Maze loaded into data and displayed on grid. Post: Tried to solve * the maze. Success is true iff successed in solving. */ public void run() { boolean success = false; // No solution yet Position current = start; // Initialize current to start Stack path = new StackVector(); // Create new path grid.visit(current); // visit the current position and save on stack path.push(current); stackDisplay.append("\n" + current.toString()); try { while (!path.empty() && !success) { // Search until success or no empty cells sleep(sleepTime); // Pause to give better animation current = nextUnvisited(current); // Find new cell to visit if (current != null) { // If found cell to visit, visit it grid.visit(current); gm.showStatus( "Now at (" + current.getRow() + "," + current.getCol() + ")."); path.push(current); // push new position onto path stackDisplay.append("\n" + current.toString()); success = current.equals(finish); // success if at the finish } else { // No neighbors unvisited so must back up current = (Position) path.pop(); // Pop off last cell visited removeLastOnStackDisplay(); grid.fail(current); // indicate no solution from here if (!path.empty()) { // If still cells on path // take last visited as new current current = (Position) path.peek(); } } } if (success) { // succeeded in solving maze // set color of finish cell back to finishColor grid.setFinish(finish); gm.showStatus("success!"); } else { // No solution to maze gm.showStatus("failure"); } // print maze System.out.println(gm.toString()); } catch (InterruptedException exc) { } } /** * post: Return next adjacent open and unvisited cell if there is one. Order * attempted is north, east, south, west */ protected Position nextUnvisited(Position current) { Position nextTry = current.getNorth(); // Try north if (!grid.canVisit(nextTry)) { // If not a good cell to visit ... nextTry = current.getEast(); // Try east if (!grid.canVisit(nextTry)) { // If not a good cell to visit ... nextTry = current.getSouth(); // Try south if (!grid.canVisit(nextTry)) { // If not a good cell to visit ... nextTry = current.getWest(); // Try west if (!grid.canVisit(nextTry)) { // If not a good cell to visit ... nextTry = null; // No unvisited neighbors available } } } } return nextTry; } // post: Remove last line on stackDisplay as not on path to finish protected void removeLastOnStackDisplay() { String text = stackDisplay.getText(); int newLast = text.lastIndexOf('\n'); stackDisplay.setText(text.substring(0, newLast)); } // Adjust sleep time to reflect desired speed // Post: Solver is set to move faster or slower depending on speed public void setSpeed(int speed) { sleepTime = SLEEP_TIME / speed; } }