import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Set; /** * PuzzleSolution searches the provided initial puzzle to find the shortest * solution. The solved puzzle and list of moves are available via accessors. * * @author Michael Leonhard (mleonhar) * @version 2005-10-30 * @version JDK 1.5.0.5, Eclipse 3.1.0, Windows XP * @version CS 340, Fall 2005, Instructor: Pat Troy, TA: Nitin Jindal */ public class PuzzleSolution { private Set existingPuzzles; // list of puzzles that have been found private Puzzle solvedPuzzle; // the solved puzzle private List solutionMoves; // the moves that constitute the solution private List puzzles; // queue of puzzle to be searched /** * Accessor for solution moves * * @return list of PieceMove objects */ public List getSolutionMoves() { return solutionMoves; } /** * Accessor for solved puzzle * * @return solved puzzle object */ public Puzzle getSolvedPuzzle() { return solvedPuzzle; } /** * Adds the puzzle to the search space, if it doesn't already exist there * * @param puzzle the puzzle to be added */ private void addPuzzle(Puzzle puzzle) { // get a string representation of the puzzle (all puzzles with the same // board configuration will have the same string) String puzzleString = puzzle.toString(); // try to add the string to the list of puzzles existing in the search boolean isNew = this.existingPuzzles.add(puzzleString); // the puzzle is not unique, so do nothing if (!isNew) { // MP4.dprint(this.puzzles.size() + " ALREADY EXISTS: // "+puzzleString); return; } // add the puzzle to the queue so it will be searched this.puzzles.add(puzzle); // MP4.dprint(this.puzzles.size() + " QUEUE <== " + puzzleString); } /** * Constructor: searches for a solution to the initial puzzle. * * @param initialPuzzle the starting puzzle */ public PuzzleSolution(Puzzle initialPuzzle) { // check parameter if (initialPuzzle == null) throw new IllegalArgumentException( "initialPuzzle may not be null)"); // initial puzzle is solved if (initialPuzzle.isSolved()) { // save it as the solution this.solvedPuzzle = initialPuzzle; // empty list of moves this.solutionMoves = new LinkedList(); // done searching before we even started! return; } // allocate data structures this.existingPuzzles = new HashSet(); this.puzzles = new LinkedList(); // start out with initial puzzle this.addPuzzle(initialPuzzle); // search the puzzles in the queue while (!this.puzzles.isEmpty()) { // get the puzzle from the front of the queue Puzzle puzzle = (Puzzle) this.puzzles.remove(0); // MP4.dprint("Searching puzzle:\r\n" + puzzle.prettyString()); // get all puzzle states that can result from a single move on the // puzzle Collection reachablePuzzles = puzzle.getSingleMovePuzzles(); // iterate over them for (Iterator iter = reachablePuzzles.iterator(); iter.hasNext();) { // get the new puzzle Puzzle newPuzzle = (Puzzle) iter.next(); // the puzzle is a solution if (newPuzzle.isSolved()) { // save the puzzle as the solution this.solvedPuzzle = newPuzzle; this.solutionMoves = newPuzzle.getMoveList(); // done searching, cleanup this.existingPuzzles = null; this.puzzles = null; // done! return; } // try to add it to the queue this.addPuzzle(newPuzzle); } } // queue is empty, so there is no solution this.existingPuzzles = null; this.puzzles = null; return; } }