Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I am practicing for my final for my AP Computer Science class. Anyways, I have just learned recursion and I need help simplifying several methods into one for the 8 queens problem.
I am needing to combine the rowOne-rowEight methods into one method in itself. The program works and prints all 92 solutions, but it just needs simplified..
public class NonAttacking
{
private static int [][] board = new int[8][8];
private static int count = 0;
public void rowOne(int y)
{
int x = 0;
if(onBoard(x, y) != -1)
{
if(validMove(x, y) == 0) //if the move is valid (0) then it puts a 1 at those coordinates and moves on to the next method (RowTwo)
{
board[x][y] = 1;
rowTwo(0);
}
board[x][y] = 0;
rowOne(y + 1);
}
}
public void rowTwo(int col)
{
int x = 1;
if(onBoard(x, col) != -1)
{
if(validMove(x, col) == 0)
{
board[x][col] = 1;
rowThree(0);
}
board[x][col] = 0;
rowTwo(col + 1);
}
}
public void rowThree(int col)
{
int x = 2;
if(onBoard(x, col) != -1)
{
if(validMove(x, col) == 0)
{
board[x][col] = 1;
rowFour(0);
}
board[x][col] = 0;
rowThree(col + 1);
}
}
public void rowFour(int col)
{
int x = 3;
if(onBoard(x, col) != -1)
{
if(validMove(x, col) == 0)
{
board[x][col] = 1;
rowFive(0);
}
board[x][col] = 0;
rowFour(col + 1);
}
}
public void rowFive(int col)
{
int x = 4;
if(onBoard(x, col) != -1)
{
if(validMove(x, col) == 0)
{
board[x][col] = 1;
rowSix(0);
}
board[x][col] = 0;
rowFive(col + 1);
}
}
public void rowSix(int col)
{
int row = 5;
if(onBoard(row, col) != -1)
{
if(validMove(row, col) == 0)
{
board[row][col] = 1;
rowSeven(0);
}
board[row][col] = 0;
rowSix(col + 1);
}
}
public void rowSeven(int col)
{
int row = 6;
if(onBoard(row, col) != -1)
{
if(validMove(row, col) == 0)
{
board[row][col] = 1;
rowEight(0);
}
board[row][col] = 0;
rowSeven(col + 1);
}
}
public void rowEight(int col)
{
int row = 7;
if(onBoard(row, col) != -1)
{
if(validMove(row, col) == 0)
{
board[row][col] = 1;
count++;
System.out.println(toString());
}
board[row][col] = 0;
rowEight(col + 1);
}
}
public static int validMove(int row, int col)
{
for (int i = 0; i < 8; i++)
{
if(onBoard(row, i) == 1) //checks side to side
{
return -1;
}
if(onBoard(i, col) == 1) //checks up and down
{
return -1;
}
}
//Check Diagonally
for(int i = 0; i < 8; i++)
{
if(onBoard(row - i, col - i) == 1) //checks up and left
{
return -1;
}
if(onBoard(row - i, col + i) == 1) //checks up and right
{
return -1;
}
if(onBoard(row + i, col - i) == 1) //checks down and left
{
return -1;
}
if(onBoard(row + i, col + i) == 1) //checks down and right
{
return -1;
}
}
return 0; //if it works
}
public static int onBoard(int row, int col)
{
if(row < 0 || col < 0 || row > 7 || col > 7) //checks if it is valid on the board
{
return -1;
}
return board[row][col]; //returns what the value is at the valid point
}
public String toString()
{
System.out.println(print());
String ans = "Solution: ";
ans += count;
return ans;
}
public static String print()
{
String sol = "Solution: " + count;
String result = "\n";
for (int row = 0; row < board.length; row++)
{
for(int column = 0; column < board[row].length; column++)
{
result += board[row][column] + "\t";
}
result += "\n";
}
return result;
}
}
Driver:
`
public class Driver
{
public static void main(String args[])
{
NonAttacking queen = new NonAttacking();
queen.rowOne(0);
System.out.println(queen.print());
}
}
`
If all you are looking to do is replace the 8 methods with one method then the following should do as required, using rowN(0, 0) to begin.
public void rowN(int n, int y)
{
if(onBoard(n, y) != -1)
{
if(validMove(n, y) == 0) //if the move is valid (0) then it puts a 1 at those coordinates and moves on to the next method (RowTwo)
{
board[n][y] = 1;
if(n<7) {
rowN(n+1, 0);
}
else {
count++;
System.out.println(toString());
}
}
board[n][y] = 0;
rowN(n, y + 1);
}
}
Related
This question already has answers here:
What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it?
(26 answers)
Closed 3 years ago.
My sudoku solver replaces "-" with zeros, then solves the puzzle. It works for most puzzles that I've tried, but throws an ArrayIndexOutOfBoundsException for puzzles with a full row of dashes. I've tried tweeking different things to get it to work, but I'm a little lost.
This is what the puzzle looks like.
public static int[][] theArray = new int [9][9];
public static int SIZE = 9;
private static boolean isCompletePuzzle() {
// checks for 0 in rows/cols
for (int i = 0; i <= SIZE; i++) {
for (int j = 0; j <= SIZE; j++) {
if (theArray[i][j] != 0) {
return true;
}
}
}
return false;
}
private static boolean isValidPuzzle(int row, int col, int number) {
// checks rows
for (int i = 0; i < SIZE; i++) {
if (theArray[row][i] == number) {
return true;
}
}
// checks columns
for (int i = 0; i < SIZE; i++) {
if (theArray[i][col] == number) {
return true;
}
}
// checks 3x3
int r = row - row % 3;
int c = col - col % 3;
for (int i = r; i < r + 3; i++)
for (int j = c; j < c + 3; j++)
if (theArray[i][j] == number)
return true;
return false;
}
private static boolean isSolvedPuzzle(int row, int col, int number) {
if (isValidPuzzle(row, col, number) == true && isCompletePuzzle() == true) {
return true;
}
return false;
}
public static boolean solvePuzzle() {
for (int row = 0; row < SIZE; row++) {
for (int col = 0; col < SIZE; col++) {
if (theArray[row][col] == 0) {
for (int number = 1; number <= SIZE; number++) {
if (!isSolvedPuzzle(row, col, number)) {
theArray[row][col] = number;
if (solvePuzzle()) {
return true;
}
else {
theArray[row][col] = 0;
}
}
}
return false;
}
}
}
return true;
}
in ur isCompletePuzzle() function ur loop conditions i <= SIZE and j <= SIZE cause ArrayIndexOutOfBoundsException
when i is 9 the if (theArray[i][j] != 0) throw ArrayIndexOutOfBoundsException
First time actually using the site so if I do anything wrong I apologize in advance and will work to correct it given guidance. I am currently working on my senior project. It is a game very similar to tic-tac-toe but the height and width of the board are of variable sizes and the amount in a row needed to win is also variable (all chosen by the user through jcomboboxes).
the problem is that the miniMax method will often select a tile that's already been chosen. I'm not entirely sure how to figure out the source of the problem, after having done quite a few hours of research. I just need to be pointed in the right direction on the means of finding the source but will gladly take any help I can get
attached below is the code. I provided all of the code for the program so that it can be compiled and tested, hopefully, with ease. If this is the wrong thing to do I apologize, let me know and I will correct.
I found various examples of the minimax algorithm being implemented and ended up using the one in the following link: simplest MiniMax algorithm for TicTacToe AI in Java
I also tried implementing the following: https://medium.com/#pelensky/unbeatable-tic-tac-toe-minimax-in-java-e1ad687ed821
but that led to numerous stackoverflow errors that I couldn't see how to reasonably mitigate without redoing the entire algorithm.
I am currently working with the former and it works to an extent but the AI doesn't appear to make intelligent decisions and will often try to choose a tile that's already been selected.
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import javax.swing.*;
public class Konnexion extends JPanel
{
ArrayList<JButton> buttons = new ArrayList<JButton>();
private static int totalButtons;
private JLabel winStat;
private JLabel lossStat;
protected JLabel drawStat;
JPanel gameBoard;
JButton exitButton;
int wins = 0;
int losses = 0;
int draws = 0;
Game game;
public Konnexion(int height, int width, int connects, String ai)
{
JPanel gameStats = new JPanel();
gameStats.setLayout(new GridLayout(1,3));
winStat = new JLabel("Wins: " + wins);
lossStat = new JLabel("Losses: " + losses + " ");
drawStat = new JLabel("Draws: " + draws);
gameStats.add(winStat);
gameStats.add(lossStat);
gameStats.add(drawStat);
add(gameStats);
totalButtons = (height * width) - 1;
gameBoard = new JPanel();
gameBoard.setLayout(new GridLayout(height,width));
initializebuttons();
add(gameBoard);
JPanel menuButtons = new JPanel();
menuButtons.setLayout(new GridLayout(1,1));
exitButton = new JButton();
exitButton.setText("Exit Game");
exitButton.addActionListener(new buttonListener());
menuButtons.add(exitButton);
add(menuButtons);
game = new Game(totalButtons, height, width, connects, ai);
}
public void initializebuttons()
{
for(int i = 0; i <= totalButtons; i++)
{
buttons.add(i, new JButton());
buttons.get(i).setText("");
buttons.get(i).setPreferredSize(new Dimension(75,75));
buttons.get(i).addActionListener(new buttonListener());
gameBoard.add(buttons.get(i));
}
}
public void resetButtons()
{
for(int i = 0; i <= totalButtons; i++)
{
buttons.get(i).setText("");
}
game.resetGameState();
}
private class buttonListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
JButton buttonClicked = (JButton)e.getSource(); //get the particular button that was clicked
if (buttonClicked.getText().equals(""))
{
buttonClicked.setText(Game.getSymbol(game.getCurrentPlayer()));
game.setMarker(buttons.indexOf(buttonClicked), game.getSymbol(game.getCurrentPlayer()));
if (Game.getSymbol(game.getCurrentPlayer()).equals("X"))
{
game.changeCurrentPlayer();
if (game.hasWon("X", Game.cells)) {
wins++;
winStat.setText("Wins: " + wins);
JOptionPane.showConfirmDialog(null, "Player X Wins!!!");
resetButtons();
game.resetGameState();
}
}
else
{
game.changeCurrentPlayer();
if (game.hasWon("O", Game.cells)) {
losses++;
lossStat.setText("Losses: " + losses + " ");
JOptionPane.showConfirmDialog(null, "Player O Wins!!!");
resetButtons();
game.resetGameState();
}
}
if (game.getCurrentPlayer() == 2) {
game.printArrays();
game.copyGameState();
//System.out.println(game.miniMax(game.getCurrentPlayer()));
buttons.get(game.miniMax(game.getCurrentPlayer())).doClick();
}
}
else if (buttonClicked.equals(exitButton))
{
Window window = SwingUtilities.getWindowAncestor(exitButton);
window.dispose();
try {
new MainMenu();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
else
{
JOptionPane.showMessageDialog(buttonClicked, "That tile has already been selected!");
}
if (game.checkDraw())
{
draws++;
drawStat.setText("Draws: " + draws);
JOptionPane.showConfirmDialog(null, "It was a Draw!!!");
resetButtons();
}
}
}
}
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class Game {
public static int ROWS;
public static int COLS;
public static int WIN_SIZE;
public static int currentPlayer;
public static String[][] cells; //Game state array
String[][] node; //copy of the game state used for minimax method
public Game(int totalButtons, int height, int width, int connects, String difficulty) {
ROWS = height;
COLS = width;
WIN_SIZE = connects;
currentPlayer = 1;
cells = new String[ROWS][COLS];
node = new String[ROWS][COLS];
resetGameState(cells);
resetGameState(node);
}
public void setMarker(int space, String marker) {
int col = space % COLS;
int rows = space / COLS;
cells[rows][col] = marker;
}
public void changeCurrentPlayer() {
if (currentPlayer == 1)
{
currentPlayer = 2;
}
else if (currentPlayer == 2)
{
currentPlayer = 1;
}
}
public int getCurrentPlayer() {
return currentPlayer;
}
public static String getSymbol(int playerNum) {
if (playerNum == 1)
return "X";
else
return "O";
}
public void resetGameState() {
currentPlayer = 1;
for (int i = 0; i < cells.length; i++) {
for (int j = 0; j < cells[i].length; j++) {
cells[i][j] = "-";
}
}
}
public static void resetGameState(String[][] gameState) {
for (int i = 0; i < gameState.length; i++) {
for (int j = 0; j < gameState[i].length; j++) {
gameState[i][j] = "-";
}
}
}
/**
*
* #param theSeed Value expected in each cell
* #param row Row index to check
* #param col Col index to check
* #param count Number of consecutive elements found in the line.
* #param rowIncrement Increment to the row index for the next evaluation
* #param colIncrement Increment to the col index for the next evaluation
* #return true if there is a winner combination in the line, otherwise false.
*/
private boolean checkLine(String theSeed, int row, int col, int count, int rowIncrement, int colIncrement, String[][] gameCheck) {
if (!areValidIndexes(row, col)) {
return false;
}
if (theSeed.equals(gameCheck[row][col])) {
count++;
if (count >= WIN_SIZE) {
return true;
} else {
return checkLine(theSeed, row + rowIncrement, col + colIncrement, count, rowIncrement, colIncrement, gameCheck);
}
} else {
return false;
}
}
private boolean areValidIndexes(int row, int col) {
if (row >= 0 && row < ROWS &&
col >= 0 && col < COLS) {
return true;
}
return false;
}
private boolean checkRow(String theSeed, int row, int col, String[][] gameCheck) {
return checkLine(theSeed, row, col, 0, 1, 0, gameCheck);
}
private boolean checkColumn(String theSeed, int row, int col, String[][] gameCheck) {
return checkLine(theSeed, row, col, 0, 0, 1, gameCheck);
}
private boolean checkForwardDiagonal(String theSeed, int row, int col, String[][] gameCheck) {
return checkLine(theSeed, row, col, 0, 1, 1, gameCheck);
}
private boolean checkBackwardDiagonal(String theSeed, int row, int col, String[][] gameCheck) {
return checkLine(theSeed, row, col, 0, -1, 1, gameCheck);
}
public boolean hasWon(String theSeed, String[][] gameCheck) {
for (int row = 0; row < ROWS; row++) {
for (int col = 0; col < COLS; col++) {
if (checkRow(theSeed, row, col, gameCheck) ||
checkColumn(theSeed, row, col, gameCheck) ||
checkForwardDiagonal(theSeed, row, col, gameCheck) ||
checkBackwardDiagonal(theSeed, row, col, gameCheck)) {
return true;
}
}
}
return false;
}
public boolean checkDraw()
{
String s = "";
for (String[] r : cells) {
for (String t : r) {
s += t;
}
}
if (!s.contains("-"))
{
return true;
}
return false;
}
public static boolean checkDraw(String[][] node)
{
String s = "";
for (String[] r : node) {
for (String t : r) {
s += t;
}
}
if (!s.contains("-"))
{
return true;
}
return false;
}
public int checkWin(String[][] gameState) {
if (hasWon("X", gameState))
{
return 1;
}
else if (hasWon("O", gameState))
{
return 2;
}
else
{
return 0;
}
}
public void copyGameState() {
for (int i = 0; i < cells.length; i++) {
for (int j = 0; j < cells[i].length; j++) {
node[i][j] = cells[i][j];
}
}
}
public static int[] getAvailableSpaces() {
String s = "";
for (int i = 0; i < cells.length; i++) {
for (int j = 0; j < cells[i].length; j++) {
if (cells[i][j].equals("-"))
s += ((j * COLS) + i) + ", ";
}
}
String[] split = s.split(", ");
int[] availableSpaces = new int[split.length];
for (int i = 0; i < split.length; i++)
availableSpaces[i] = Integer.parseInt(split[i]);
return availableSpaces;
}
public void resetSpace(int space) {
int col = space % COLS;
int rows = space / COLS;
cells[rows][col] = "-";
}
public int miniMax(int playerNum)
{
//printArrays();
int victor = checkWin(cells); // returns 0 if game is ongoing, 1 for p1, 2 for p2, 3 for tie.
if(victor != 0) //game over
{
return Score(victor);
}
if(playerNum == 2) //AI
{
int bestVal = Integer.MAX_VALUE;
int bestSpot = 0;
for(int i = 0; i < cells.length; i++)
for (int j = 0; j < cells[i].length; j++)
{
if(!cells[i][j].equals("-"))
continue;
cells[i][j] = getSymbol(playerNum);
int value = miniMax(1);
if(value < bestVal)
{
bestVal = value;
bestSpot = (j * COLS) + i;
System.out.println("Best Value: " + bestVal);
System.out.println("Best Spot: " + bestSpot);
}
cells[i][j] = "-";
}
return bestSpot;
}
else
{
int bestVal = Integer.MIN_VALUE;
int bestSpot = 0;
for(int i = 0; i < cells.length; i++)
for(int j = 0; j < cells[i].length; j++)
{
if(!cells[i][j].equals("-"))
continue;
cells[i][j] = getSymbol(playerNum);
int value = miniMax(2);
if(value > bestVal)
{
bestVal = value;
bestSpot = (j * COLS) + i;
}
cells[i][j] = "-";
}
return bestSpot;
}
}
private int Score(int gameState)
{
if(gameState ==2) //O wins.
return 10;
else if(gameState==1) //X wins
return -10;
return 0;
}
public void printArrays() {
String s = "cells: ";
String l = "node: ";
for (int i = 0; i < cells.length; i++) {
for (int j = 0; j <cells[i].length; j++) {
s += cells[i][j];
l += node[i][j];
}
}
System.out.println(s);
System.out.println(l);
}
}
I have written a program for an assignment where we had to write a simple Gomoku program. I thought I had it all, but when I compile and run, it sets off the win scenario even if I only have 4 of a kind and even if they're not next to each other. (It should only set off a win if there are five in a row of one kind...X's or O's). I feel like I should be resetting my counter back to 0 before each turn, but I'm not sure where I should be doing that. Any tips would be appreciated!
import java.util.Scanner;
public class Gomoku1
{
public static void main (String[] args)
{
Scanner input = new Scanner(System.in);
char[][] map = new char [19][19];
int row = 0;
int column = 0;
//fill game with dots
for (int i = 0; i < map.length; i++)
{
for (int j = 0; j < map[i].length; j++)
{
map[i][j] = '.';
}
}
printMap(map);
char player1Choice = 'X';
char player2Choice = 'O';
int [] place;
while (true)
{
System.out.println("Player 1's turn!");
place = userTurn(map, player1Choice);
if (isValidMove(map, place[0], place[1]) == false)
{
System.out.println("Invalid move! Try again!");
place = userTurn(map, player1Choice);
}
if (isValidMove(map, place[0], place[1])) {
map[place[0]][place[1]] = player1Choice;
printMap(map);
}
if (isBoardFull(map) == true)
{
System.out.println("Board is full. Tied game.");
break;
}
if (hasPlayerWon(map, player1Choice) == true)
{
System.out.println("Player 1 Wins!");
break;
}
else
{
System.out.println("Player 2's turn!: ");
place = userTurn(map, player2Choice);
//System.out.println(isValidMove(map, row, column));
if (isValidMove(map, place[0], place[1]) == false)
{
System.out.println("Invalid move! Try again!");
place = userTurn(map, player2Choice);
}
if (isValidMove(map, place[0], place[1])) {
map[place[0]][place[1]] = player2Choice;
printMap(map);
}
if (isBoardFull(map) == true)
{
System.out.println("Board is full. Tied game.");
break;
}
if (hasPlayerWon(map, player2Choice) == true)
{
System.out.println("Player 2 Wins!");
break;
}
}
}
}
public static void printMap (char[][] map)
{
for (int i = 0; i < map.length; i++)
{
for (int j = 0; j < map[i].length; j++)
{
System.out.printf("%2c", map[i][j]);
}
System.out.println();
}
}
public static int [] userTurn (char[][] map, char playerChoice)
{
Scanner input = new Scanner(System.in);
System.out.print("Enter row: ");
int row = input.nextInt();
System.out.print("Enter column: ");
int column = input.nextInt();
int place [] = {row, column};
return place;
}
public static boolean isValidMove (char[][] map, int row, int column)
{
//System.out.println ("n is valid move");
if (row < 0 || row > 18 || column < 0 || column > 18 || map[row][column]=='O' || map[row][column]=='X')
{
return false;
}
else
{
return true;
}
}
public static boolean isBoardFull (char[][] map)
{
int openSpots = 0;
for (int i = 0; i < map.length; i++)
{
for (int j = 0; j < map.length; j++)
{
if (!(map[i][j]=='.'))
openSpots++;
}
}
if (openSpots == 361)
{
return true;
}
return false;
}
public static boolean hasPlayerWon(char[][] map, int player)
{
if (isHorizontalWin(map, player) == true || isVerticalWin(map, player) == true || isDiagonalWin(map, player) == true)
{
return true;
}
return false;
}
public static boolean isHorizontalWin(char[][] map, int player)
{
int count = 0;
int r;
int c;
for (int i = 0; i < map.length; i++)
{
for (int j = 0; j < map.length; j++)
{
if (map[i][j]==(player))
{
r = i;
c = j;
while (r >= 0 && r <= 18 && c >= 0 && c <= 18 && map[r][c] == player)
{
count ++;
r += 0;
c += 1;
}
}
}
}
if (count == 5)
{
return true;
}
return false;
}
public static boolean isVerticalWin(char[][] map, int player)
{
int count = 0;
int r;
int c;
for (int i = 0; i < map.length; i++)
{
for (int j = 0; j < map.length; j++)
{
if (map[i][j]==(player))
{
r = i;
c = j;
while (r >= 0 && r <= 18 && c >= 0 && c <= 18 && map[r][c] == player)
{
count ++;
r += 1;
c += 0;
}
}
}
}
if (count == 5)
{
return true;
}
return false;
}
public static boolean isDiagonalWin(char[][] map, int player)
{
int count = 0;
int r;
int c;
for (int i = 0; i < map.length; i++)
{
for (int j = 0; j < map.length; j++)
{
if (map[i][j]==(player))
{
r = i;
c = j;
while (r >= 0 && r <= 18 && c >= 0 && c <= 18 && map[r][c] == player)
{
count++;
r += 1;
c += 1;
}
}
}
}
if (count == 5)
{
return true;
}
return false;
}
}
You have problems in all three of the function that check win conditions: isHorizontalWin, isVerticalWin, and isDiagonalWin. All three increment the variable count, but this variable is never set back to zero. Additionally, the check to see if count == 5 should be made inside the loop. Here is an example on how to fix isHorizontalWin:
public static boolean isHorizontalWin(char[][] map, int player)
{
int count = 0;
int r;
int c;
for (int i = 0; i < map.length; i++)
{
for (int j = 0; j < map.length; j++)
{
if (map[i][j]==(player))
{
r = i;
c = j;
while (r >= 0 && r <= 18 && c >= 0 && c <= 18 && map[r][c] == player)
{
count ++;
r += 0;
c += 1;
}
if (count == 5)
{
return true;
} else {
count = 0;
}
}
}
}
return false;
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I am told that A* implementation on following 8 puzzle Solver is wrong, can anybody please tell me where it's wrong and how to correct it?
Also: this throws Exception in thread "main" java.lang.OutOfMemoryError: Java heap space even though Build Process Heap size is set to 2048.
Here is Solver.java
import java.util.HashSet;
import java.util.Set;
import java.util.Stack;
import java.util.PriorityQueue;
public class Solver {
private int moves = 0;
private SearchNode finalNode;
private Stack<Board> boards;
public Solver(Board initial) {
if (!initial.isSolvable()) throw new IllegalArgumentException("Unsolvable puzzle");
// this.initial = initial;
PriorityQueue<SearchNode> minPQ = new PriorityQueue<SearchNode>(initial.size() + 10);
Set<Board> previouses = new HashSet<Board>(50);
Board dequeuedBoard = initial;
Board previous = null;
SearchNode dequeuedNode = new SearchNode(initial, 0, null);
Iterable<Board> boards;
while (!dequeuedBoard.isGoal()) {
boards = dequeuedBoard.neighbors();
moves++;
for (Board board : boards) {
if (!board.equals(previous) && !previouses.contains(board)) {
minPQ.add(new SearchNode(board, moves, dequeuedNode));
}
}
previouses.add(previous);
previous = dequeuedBoard;
dequeuedNode = minPQ.poll();
dequeuedBoard = dequeuedNode.current;
}
finalNode = dequeuedNode;
}
// min number of moves to solve initial board
public int moves() {
if (boards != null) return boards.size()-1;
solution();
return boards.size() - 1;
}
public Iterable<Board> solution() {
if (boards != null) return boards;
boards = new Stack<Board>();
SearchNode pointer = finalNode;
while (pointer != null) {
boards.push(pointer.current);
pointer = pointer.previous;
}
return boards;
}
private class SearchNode implements Comparable<SearchNode> {
private final int priority;
private final SearchNode previous;
private final Board current;
public SearchNode(Board current, int moves, SearchNode previous) {
this.current = current;
this.previous = previous;
this.priority = moves + current.manhattan();
}
#Override
public int compareTo(SearchNode that) {
int cmp = this.priority - that.priority;
return Integer.compare(cmp, 0);
}
}
public static void main(String[] args) {
int[][] tiles = {{4, 1, 3},
{0, 2, 6},
{7, 5, 8}};
double start = System.currentTimeMillis();
Board board = new Board(tiles);
Solver solve = new Solver(board);
System.out.printf("# of moves = %d && # of actual moves %d & time passed %f\n, ", solve.moves(), solve.moves, (System.currentTimeMillis() - start) / 1000);
}
}
And Board.java, just in case:
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
public final class Board {
private final int[][] tilesCopy;
private final int N;
// cache
private int hashCode = -1;
private int zeroRow = -1;
private int zeroCol = -1;
private Collection<Board> neighbors;
/*
* Rep Invariant
* tilesCopy.length > 0
* Abstraction Function
* represent single board of 8 puzzle game
* Safety Exposure
* all fields are private and final (except cache variables). In the constructor,
* defensive copy of tiles[][] (array that is received from the client)
* is done.
*/
public Board(int[][] tiles) {
//this.N = tiles.length;
this.N = 3;
this.tilesCopy = new int[N][N];
// defensive copy
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (tiles[i][j] >= 0 && tiles[i][j] < N*N) tilesCopy[i][j] = tiles[i][j];
else {
System.out.printf("Illegal tile value at (%d, %d): "
+ "should be between 0 and N^2 - 1.", i, j);
System.exit(1);
}
}
}
checkRep();
}
public int tileAt(int row, int col) {
if (row < 0 || row > N - 1) throw new IndexOutOfBoundsException
("row should be between 0 and N - 1");
if (col < 0 || col > N - 1) throw new IndexOutOfBoundsException
("col should be between 0 and N - 1");
return tilesCopy[row][col];
}
public int size() {
return N;
}
public int hamming() {
int hamming = 0;
for (int row = 0; row < this.size(); row++) {
for (int col = 0; col < this.size(); col++) {
if (tileAt(row, col) != 0 && tileAt(row, col) != (row*N + col + 1)) hamming++;
}
}
return hamming;
}
// sum of Manhattan distances between tiles and goal
public int manhattan() {
int manhattan = 0;
int expectedRow = 0, expectedCol = 0;
for (int row = 0; row < this.size(); row++) {
for (int col = 0; col < this.size(); col++) {
if (tileAt(row, col) != 0 && tileAt(row, col) != (row*N + col + 1)) {
expectedRow = (tileAt(row, col) - 1) / N;
expectedCol = (tileAt(row, col) - 1) % N;
manhattan += Math.abs(expectedRow - row) + Math.abs(expectedCol - col);
}
}
}
return manhattan;
}
public boolean isGoal() {
if (tileAt(N-1, N-1) != 0) return false; // prune
for (int i = 0; i < this.size(); i++) {
for (int j = 0; j < this.size(); j++) {
if (tileAt(i, j) != 0 && tileAt(i, j) != (i*N + j + 1)) return false;
}
}
return true;
}
// change i && j' s name
public boolean isSolvable() {
int inversions = 0;
for (int i = 0; i < this.size() * this.size(); i++) {
int currentRow = i / this.size();
int currentCol = i % this.size();
if (tileAt(currentRow, currentCol) == 0) {
this.zeroRow = currentRow;
this.zeroCol = currentCol;
}
for (int j = i; j < this.size() * this.size(); j++) {
int row = j / this.size();
int col = j % this.size();
if (tileAt(row, col) != 0 && tileAt(row, col) < tileAt(currentRow, currentCol)) {
inversions++;
}
}
}
if (tilesCopy.length % 2 != 0 && inversions % 2 != 0) return false;
if (tilesCopy.length % 2 == 0 && (inversions + this.zeroRow) % 2 == 0) return false;
return true;
}
#Override
public boolean equals(Object y) {
if (!(y instanceof Board)) return false;
Board that = (Board) y;
// why bother checking whole array, if last elements aren't equals
return this.tileAt(N - 1, N - 1) == that.tileAt(N - 1, N - 1) && this.size() == that.size() && Arrays.deepEquals(this.tilesCopy, that.tilesCopy);
}
#Override
public int hashCode() {
if (this.hashCode != -1) return hashCode;
// more optimized version(Arrays.hashCode is too slow)?
this.hashCode = Arrays.deepHashCode(tilesCopy);
return this.hashCode;
}
public Collection<Board> neighbors() {
if (neighbors != null) return neighbors;
if (this.zeroRow == -1 && this.zeroCol == -1) findZeroTile();
neighbors = new HashSet<>();
if (zeroRow - 1 >= 0) generateNeighbor(zeroRow - 1, true);
if (zeroCol - 1 >= 0) generateNeighbor(zeroCol - 1, false);
if (zeroRow + 1 < this.size()) generateNeighbor(zeroRow + 1, true);
if (zeroCol + 1 < this.size()) generateNeighbor(zeroCol + 1, false);
return neighbors;
}
private void findZeroTile() {
outerloop:
for (int i = 0; i < this.size(); i++) {
for (int j = 0; j < this.size(); j++) {
if (tileAt(i, j) == 0) {
this.zeroRow = i; // index starting from 0
this.zeroCol = j;
break outerloop;
}
}
}
}
private void generateNeighbor(int toPosition, boolean isRow) {
int[][] copy = Arrays.copyOf(this.tilesCopy, tilesCopy.length);
if (isRow) swapEntries(copy, zeroRow, zeroCol, toPosition, zeroCol);
else swapEntries(copy, zeroRow, zeroCol, zeroRow, toPosition);
neighbors.add(new Board(copy));
}
private void swapEntries(int[][] array, int fromRow, int fromCol, int toRow, int toCol) {
int i = array[fromRow][fromCol];
array[fromRow][fromCol] = array[toRow][toCol];
array[toRow][toCol] = i;
}
public String toString() {
StringBuilder s = new StringBuilder(4 * N * N); // optimization?
// s.append(N + "\n");
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
s.append(String.format("%2d ", tileAt(i, j)));
}
s.append("\n");
}
return s.toString();
}
private void checkRep() {
assert tilesCopy.length > 0;
}
}
The problem you have is at line
int[][] copy = Arrays.copyOf(this.tilesCopy, tilesCopy.length);
You assume here to have copied the matrix. But actually you've copied the array with references to arrays in the 2nd dimension.
In other words
copy == this.tolesCopy // false
copy[0] == this.tilesCopy[0] // true
copy[1] == this.tilesCopy[1] // true
copy[2] == this.tilesCopy[2] // true
what leads to have the same matrix changed multiple times, and even to an invalid/unsolvable state.
The easiest fix I see in your code would be to change the generateNeighbor method
private void generateNeighbor(int toPosition, boolean isRow) {
Board board = new Board(this.tilesCopy);
if (isRow) swapEntries(board.tilesCopy, zeroRow, zeroCol, toPosition, zeroCol);
else swapEntries(board.tilesCopy, zeroRow, zeroCol, zeroRow, toPosition);
neighbors.add(board);
}
Although the overal idea looks good. There are multiple other things that can be improved. I suggest you to have a look at this implementation
This project involves three classes. Star creates the stars, Starfield creates a matrix of stars, and StarfieldSimualation is the runner
When I omit row 0, it omits the bottom row, instead of the top one. But, it works for rows 1-4. Thanks in advance for the help.
Starfield Code
public class Starfield
{
private Star[][] Sky;
public Starfield(int rows, int cols)
{
if(rows < 0 || cols < 0)
{
rows = cols = 1;
}
Sky = new Star[rows][cols];
}
public String toString()
{
String S = "";
for (Star[] row: Sky)
{
for(Star X: row)
{
if(X != null)
{
S+= X.getImage() + "\t";
}
else
{
S += "- \t";
}
}
S += "\n";
}
return S;
}
public void addStar(String Image, String Constellation, int row, int col)
{
if(row < 0 || row >= Sky.length || col < 0 || col >= Sky[0].length)
{
return;
}
Sky[row][col] = new Star(Image, Constellation, row, col);
}
public Star[][] omitRow(int r)
{
int i, j, k;
k = 0;
Star[][] rowless = new Star[Sky.length - 1][Sky[0].length];
for(i = 0; i < Sky.length-1; i++)
{
for(j = 0; j < Sky[0].length; j++)
{
k++;
}
}
Star[] ans = new Star[k];
k = 0;
for(i = 0; i < Sky.length; i++)
{
for(j = 0; j < Sky[0].length; j++)
{
if(i != r)
{
ans[k] = Sky[i][j];
k++;
}
}
}
k = 0;
for(i = 0; i < rowless.length; i++)
{
for(j = 0; j < rowless[0].length; j++)
{
if(i != r)
{
rowless[i][j] = ans[k];
k++;
}
}
}
return rowless;
}
Star Code
public class Star
{
private Star[][] Sky;
private String Image, Constellation;
private int row, col;
public Star(String I, String C, int r, int c)
{
Image = I;
Constellation = C;
row = r;
col = c;
}
public String getImage()
{
return Image;
}
public String getConstellation()
{
return Constellation;
}
public int getRow()
{
return row;
}
public int getCol()
{
return col;
}
}
Starfield Simluation Code
public class StarFieldSimulation
{
public static void main(String[] args)
{
Starfield theSky = new Starfield(5,4);
theSky.addStar("*", "Orion", 2, 3);
theSky.addStar("*", "Orion", 2, 2);
theSky.addStar("*", "Orion", 2, 1);
theSky.addStar("*", "Orion", 2, 0);
theSky.addStar("*", "Orion", 1, 3);
System.out.println("IT'S THE SKY EVERYONE");
System.out.println(theSky.toString());
Star[][] minusrow = new Star[4][4];
minusrow = theSky.omitRow(4);
System.out.println("A row has been removed");
System.out.println();
for(Star[] row: minusrow)
{
for(Star X: row)
{
if(X != null)
{
System.out.print(X.getImage() + "\t");
}
else
{
System.out.print("-\t");
}
}
System.out.println();
}
System.out.println();
System.out.println("It's the sky again");
System.out.println(theSky.toString());
}