CSC 205 – Java Programming II Lecture 23 March 4, 2002
Backtracking Backtracking is the strategy of trying to reach a goal by a sequence of chosen positions with re-tracing in reverse order of position that cannot lead to the goal. a sequence of chosen positions next positions in a predefined order retracing in reverse order
Illustration P13 P4 P12 P7 P3 P11 P6 P5 P2 Pi P10 P9 P8 P1 Position P0 P14 (GOAL) P13 P4 P12 P7 P3 P11 P6 P5 P2 P10 P9 P8 P1 P0 1st Attempt 2nd Attempt retracing Pi Position retracing (ORIG.)
Marking Visited Positions When a position is visited, it is marked as (potentially) being on a path to the goal code 9 If we discover otherwise, the marking must be undone, so that position will never again be visited. code 2
A Standard Solution A general-purpose BackTrack class is available User needs to supply An Application class A Position class to define an application-specific position An Iterator class to enumerate next position from the current position
The Application Interface import java.util.*; public interface Application { // Postcondition: true has been returned if pos could be on a //path to a goal position. Otherwise, false has been returned. public boolean valid (Position pos); // Postcondition: the position specified by pos has been //marked as being on a path to a goal position. public void record (Position pos); // Postcondition: true has been returned if pos is a goal //position. Otherwise, false has been returned. public boolean done (Position pos);
The Application Interface // Postcondition: the position specified by pos has been //marked as not being on a path to a goal position. public void undo (Position pos); // Postcondition: a string representation of this Application has //been returned. public String toString(); // Postcondition: an iterator over the positions directly //accessible from pos has been returned. public Iterator iterator (Position pos); } // interface Application
The BackTrack Class import java.util.*; public class BackTrack { public class BackTrack { Application app; // Postcondition: this BackTrack has been initialized from app. public BackTrack (Application app) { this.app = app; } // constructor // Postcondition: a solution going through pos has been attempted. public boolean tryToSolve (Position pos) { … … } // method tryToSolve } // class BackTrack
The tryToSolve Method boolean success = false; Iterator itr = app.iterator (pos); while (!success && itr.hasNext()) { pos = (Position)itr.next(); if (app.valid (pos)) { app.record (pos); if (app.done (pos)) success = true; else { success = tryToSolve (pos); if (!success) app.undo (pos); } // not done } // a valid position } // while return success;
Possible Moves Possible moves from pos in tryToSolve: Success, if one of those moves is a goal position Hopeful, if one of those moves is valid but not a goal position. Recursive call! Failure, if none of those moves is on a path to goal
Important When a return is made, the pre-call value of pos is restored. So the previously visited positions are available, to be printed as part of the path to the goal, to be undone, ...
An A-Maze-ing Application start 1 1 1 0 1 1 0 0 0 1 1 1 1 1 0 1 1 1 0 1 1 1 1 1 0 1 1 0 0 0 1 0 1 0 1 0 1 0 1 1 0 0 0 1 1 1 0 1 0 1 1 1 1 1 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 finish Maze notation 0: corridor 1: wall Iterator choices: north, east, south, west (in that order)
The Position Class public class Position { protected int row, column; public Position () { row = 0; column = 0; } // constructor public Position (int row, int column) { this.row = row; this.column = 0; public int row () { return row; } public int column () { return column ; } }
The Maze Class public class Maze implements Application { protected final byte WALL = 0; protected final byte CORRIDOR = 1; protected final byte PATH = 9; protected final byte TRIED = 2; protected Position finish; protected byte[ ][ ] grid; public boolean valid (Position pos) { if (pos.row() >= 0 && pos.row() < grid.length && pos.column() >= 0 && pos.column() < grid [0].length && grid [pos.row()][pos.column()] == CORRIDOR) return true; return false; } // method valid
The Maze Class public void record (Position pos) { grid [pos.row()][pos.column()] = PATH; } // method record public boolean done (Position pos) { return pos.row() == finish.row() && pos.column() == finish.column(); } // method done private class MazeIterator implements Iterator { … … } // class MazeIterator } // class Maze
The MazeIterator Class private class MazeIterator implements Iterator { int row, column, int count = 0; public MazeIterator (Position pos) { row = pos.row(); column = pos.column(); } // constructor public boolean hasNext() { return count < 4; } // method hasNext
The MazeIterator Class // Precondition: 0 <= count <= 3. // Postcondition: the choice for the next Position has been //returned. public Object next() { Position nextPosition = new Position(); switch (count++) { case 0: nextPosition = new Position (row-1, column); break; // NORTH case 1: nextPosition = new Position (row, column+1); break; // EAST case 2: nextPosition = new Position (row+1, column); break; // SOUTH case 3: nextPosition = new Position (row, column-1); } // switch; return nextPosition; } // method next } // class MazeIterator
An Example 0-north X 3-west 1-east X X 2-south
Try Another Case start 1 1 1 0 1 1 0 0 0 1 1 1 1 1 0 1 1 1 0 1 1 1 1 1 0 1 1 0 0 0 1 0 1 0 1 0 1 0 1 1 0 0 0 1 1 1 0 1 0 1 1 1 1 1 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 finish Maze notation 0: corridor 1: wall Iterator choices: north, south, east, west (in that order)