private List<Board> solve(Board initial) { Board twin = initial.twin(); MinPQ<SearchNode> mainQueue = new MinPQ<>(); MinPQ<SearchNode> twinQueue = new MinPQ<>(); mainQueue.insert(new SearchNode(initial, 0, null)); twinQueue.insert(new SearchNode(twin, 0, null)); while (true) { SearchNode mainSearch = mainQueue.delMin(); SearchNode twinSearch = twinQueue.delMin(); if (mainSearch.board.isGoal()) { return retraceSteps(mainSearch); } if (twinSearch.board.isGoal()) { return null; } for (Board board : mainSearch.board.neighbors()) { SearchNode mainPrevious = mainSearch.previous; if (mainPrevious == null || !board.equals(mainPrevious.board)) { mainQueue.insert(new SearchNode(board, mainSearch.moves + 1, mainSearch)); } } for (Board board : twinSearch.board.neighbors()) { SearchNode twinPrevious = twinSearch.previous; if (twinPrevious == null || !board.equals(twinPrevious.board)) { twinQueue.insert(new SearchNode(board, twinSearch.moves + 1, twinSearch)); } } } }
public static void main(String[] args) { // unit tests (not graded) In in = new In(args[0]); // input file int N = in.readInt(); int[][] blocks = new int[N][N]; for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) blocks[i][j] = in.readInt(); Board bd = new Board(blocks); StdOut.println("dimension: " + bd.dimension()); StdOut.println("hamming: " + bd.hamming()); StdOut.println("Manhattan distances: " + bd.manhattan()); StdOut.println("is goal: " + bd.isGoal()); StdOut.print(bd); StdOut.print("twin: " + bd.twin()); StdOut.println("twin equal: " + bd.equals(bd.twin())); StdOut.println("twin twin equal: " + bd.equals(bd.twin().twin())); for (Board it : bd.neighbors()) StdOut.print(it); }
/** Tests the equals method by comparing 2 equals board and the different boards. */ @Test public final void testEquals() { board = new Board(2, 0, 0, false); Board board2 = new Board(2, 0, 0, false); Board board3 = new Board(3, 1, 2, false); assertEquals(board, board2); assertFalse(board.equals(board3)); }
// find a solution to the initial board (using the A* algorithm) public Solver(Board initial) { Board twin = initial.twin(); SearchNode minNode = null; boolean isTwinRound = false; MinPQ<SearchNode> currentPQ = null; minPQ.insert(new SearchNode(initial)); minPQForTwin.insert(new SearchNode(twin)); while (true) { // Searching solution in the initial board and and its twin board // simultaneously(alternating in loops). // It has been proven by Math theory that exactly one of the two // will lead to the goal board. If a solution is found in the twin // board, it immediately proves that the initial board is not solvable, // and the search will terminate there. // Otherwise, the initial board will reach a solution. if (isTwinRound) { currentPQ = minPQForTwin; } else { currentPQ = minPQ; } minNode = currentPQ.delMin(); if (minNode.getBoard().isGoal()) { break; } else { for (Board neighbor : minNode.getBoard().neighbors()) { // Insert the neighbors into the MinPQ if: // 1. Current node contains the initial board(has no prev node) // 2. The new neighbor is not the same as current node's previous search node. // This is a critical optimization used to reduce unnecessary // exploration of already visited search nodes. if (minNode.getPrev() == null || !neighbor.equals(minNode.getPrev().getBoard())) { currentPQ.insert(new SearchNode(neighbor, minNode)); } } // Flip the state of the isTwinRound flag isTwinRound = isTwinRound ? false : true; } } if (isTwinRound) { isSolvable = false; solution = null; } else { isSolvable = true; solution = minNode; moves = solution.getMoves(); } }
private void solveInternal(MinPQ<SearchNode> queue, boolean twin) { while (!queue.isEmpty() && solvable == null) { // StdOut.println("Queue size = "+queue.size()); SearchNode min = queue.delMin(); // StdOut.println("Manhatan + moves = "+(min.board.manhattan()+min.moves)); if (min.board.isGoal()) { if (twin) { solvable = false; } else { solution = min; solvable = true; } return; } else { for (Board n : min.board.neighbors()) { if (min.previous == null || (!n.equals(min.previous.board))) { queue.insert(new SearchNode(n, min, min.moves + 1)); } } } } }
@Override public boolean equals(Object obj) { final Entry other = (Entry) obj; return board.equals(other.board); }
public void play() { Scanner scanner = new Scanner(System.in); if (playAsBlack == false) { System.out.println("Playing as X (white)"); } else { System.out.println("Playing as O (black)"); } while (!curGame.TerminalState(curBoard)) { curBoard.display(); if (curBoard.turn == playAsBlack) { boolean found = false; System.out.print("X - coordinate of piece to move: "); int fromX = scanner.nextInt(); System.out.print("Y - coordinate of piece to move: "); int fromY = scanner.nextInt(); System.out.print("X - coordinate to move to: "); int toX = scanner.nextInt(); System.out.print("Y - coordinate to move to: "); int toY = scanner.nextInt(); Board cloned = curBoard.clone(); if (fromX < 0 || fromX > 5 || fromY < 0 || fromY > 5 || toX < 0 || toX > 5 || toY < 0 || toY > 5) { found = false; } else { int previousVal = cloned.gameBoard[fromX][fromY]; cloned.gameBoard[fromX][fromY] = 0; cloned.gameBoard[toX][toY] = previousVal; ArrayList<GameState> successors = curGame.Successors(curBoard); found = false; for (int i = 0; i < successors.size(); i++) { if (cloned.equals(successors.get(i))) { found = true; break; } } } if (found) { curBoard = cloned; System.out.println("Valid move"); } else { System.out.println("Not a valid move"); } } else { AlphaBeta alphaBeta = new AlphaBeta(curGame, maxDepth); curBoard = (Board) alphaBeta.search(curBoard, false); } } curBoard.display(); if (curBoard.winner < 0) { System.out.println("Black wins"); } else if (curBoard.winner > 0) { System.out.println("White wins"); } else { System.out.println("Its a tie"); } }