3

So I am working on this 3x3 game, where you are given a current state, for example:

1 5 6

3 7 b

2 8 4

and you want to reach the goal state of:

b 1 2

3 4 5

6 7 8

So I have written all the other methods in my code which I posted below. The problem I am having now is in my actual A* search. I want to use two heuristics, one which checks how many pieces are in the wrong location (so for instance the heuristic function would show that the current state has H=8 pieces in the wrong place) and another heuristic which will calculate how far away the total sum of pieces is (so for my current state, piece one is 1 move away, piece two is 3 moves away, etc. and the sum of all that will be my H value). So I am recording my gameBoard in an array of strings.

So now to my actual problem. Everything but my A* is working right now as seen below.

First I call setFinalGoalState() which makes the variable finalGoalState so I can compare my current state to the goal state.

Then I make a priorityQueue which should be an ArrayList of Nodes, where each node will have an G value (G being how far it is in the tree), H value, reference to parent, and the current state.

So first I call an initial huesticOneHValue() to get the H value of my first state. I then run an if statement for the "h1" (which is just my first heuristic method, as I said I'll add another one later). It should then make an initial node Root which will be my first node in the tree, and add this to the priority queue.

Then it should run through the priority queue. It will take the current node as the first element in the priorityQueue, and then remove it from the queue. It sets my actual gameBoard as the same state of the gameBoard that the current node is. Then it creates an ArrayList of possible moves (this calls isValidMoves(), which checks to see if you can actually move up,down,left,or right, and then puts it in a list). I then make a for loop to run through the size of my possible moves, and then I do the actual moving by calling the move() method (so the first call for int i = 0 would call move "up" since you can move b up in my current state) Then it should create a Node child containing the gValue of where I am (it should equal 1), the new H value (in some cases this might stay same, but it should be working towards lowering the H values), its parent (which I think should just be currentNode?), and then the state of the currentNode (what the board looks like).

Then the next for loop checks to see where it should place it in the priority queue. Nodes with lesser g+h values should go in the front of the queue because we want to check them first to see if they reach goal state. So I set an initial condition if the queue is empty to add it to the front, else it checks to see if the priorityQueue at j is a larger g+h than the childs, and if it is, the child gets added to the index of j (and everything else should shift over I think?) Lastly, after all the moves are done, it checks to see if the priorityQueue's front node's state is equal to our goal state, and if its not, it goes back to the front of the while loop and runs again.

I think ultimately I am screwing up something with my nodes. When I ran debugging I found that every time I make a child, the parent node's state gets updated to that of the childs, which shouldn't happen because the child should be a certain move of the parents (either up, down, left, or right). I think I messed up something making either my node class or the way that I am creating the nodes and adding them into a queue. I also get an indexOutOfBounds when I try adding my child into the priorityQueue at

else if((priorityQueue.get(j).getG()+priorityQueue.get(j).getH()) > (child.getG()+child.getH())){

The rest of my code is below:

EightPuzzle Class

public class EightPuzzle{

    static String[][] gameBoard = new String[3][3];
    static String[][] finalGoalState = new String[3][3];
    static int[] bLocation = new int[2];
    String board;
    String dir;

    /*public void ReadFromTxt(String file) throws FileNotFoundException, IOException {
        String read; 
        FileReader f = new FileReader(file);
        int i = 0;
        int j;
        BufferedReader b = new BufferedReader(f);
        System.out.println("Loading puzzle from file...");
        while((read = b.readLine())!=null){
            if(read.length()==3){
                for(j=0;j<3;j++){
                    board[i][j] = (int)(read.charAt(j)-48);
                }
            }
            i++;
        }
        b.close();
        System.out.println("Puzzle loaded!");
    }*/

    public void setState(String board){ 
        gameBoard[0][0] = board.substring(0,1);
        gameBoard[0][1] = board.substring(1,2);
        gameBoard[0][2] = board.substring(2,3);
        gameBoard[1][0] = board.substring(4,5);
        gameBoard[1][1] = board.substring(5,6);
        gameBoard[1][2] = board.substring(6,7);
        gameBoard[2][0] = board.substring(8,9);
        gameBoard[2][1] = board.substring(9,10);
        gameBoard[2][2] = board.substring(10,11);
        System.out.println(Arrays.deepToString(gameBoard));
    }

    public static void setFinalGoalState(){
        finalGoalState[0][0] = "b";
        finalGoalState[0][1] = "1";
        finalGoalState[0][2] = "2";
        finalGoalState[1][0] = "3";
        finalGoalState[1][1] = "4";
        finalGoalState[1][2] = "5";
        finalGoalState[2][0] = "6";
        finalGoalState[2][1] = "7";
        finalGoalState[2][2] = "8";
    }

    public static void setGoalState(){
        gameBoard[0][0] = "b";
        gameBoard[0][1] = "1";
        gameBoard[0][2] = "2";
        gameBoard[1][0] = "3";
        gameBoard[1][1] = "4";
        gameBoard[1][2] = "5";
        gameBoard[2][0] = "6";
        gameBoard[2][1] = "7";
        gameBoard[2][2] = "8";
        bLocation[0] = 0;
        bLocation[1] = 0;
    }

    public void randomizeState(int numMoves){
        setGoalState();
        for(int i=0;i<numMoves;i++){
            ArrayList<String> validMoves3 = isValidMove();
            Random r = new Random();
            int mIndex = r.nextInt(validMoves3.size());
            String choice = validMoves3.get(mIndex);
            move(choice);
            System.out.println(Arrays.deepToString(gameBoard));
        }   

    }

    public ArrayList<String> isValidMove(){
            ArrayList<String> validMoves = new ArrayList<String>();
            if(bLocation[0] != 0){
                //can move up
                validMoves.add("up");
            }
            if(bLocation[0] != 2){
                //can move down
                validMoves.add("down");
            }
            if(bLocation[1] != 0){
                //can move left
                validMoves.add("left");
            }
            if(bLocation[1] != 2){
                //can move right
                validMoves.add("right");
            }
            return validMoves;
        }

    public void move(String dir){
        ArrayList<String> validMoves2 = isValidMove();

        if(validMoves2.contains("up") && dir.equals("up")){
                String temp1 = new String();
                temp1 = gameBoard[bLocation[0]-1][bLocation[1]];
                gameBoard[bLocation[0]][bLocation[1]] = temp1;
                gameBoard[bLocation[0]-1][bLocation[1]] = "b";
                bLocation[0] = bLocation[0]-1;
            }
        else if(validMoves2.contains("down") && dir.equals("down")){
                String temp2 = new String();
                temp2 = gameBoard[bLocation[0]+1][bLocation[1]];
                gameBoard[bLocation[0]][bLocation[1]] = temp2;
                gameBoard[bLocation[0]+1][bLocation[1]] = "b";
                bLocation[0] = bLocation[0]+1;
        }
        else if(validMoves2.contains("left") && dir.equals("left")){
                String temp3 = new String();
                temp3 = gameBoard[bLocation[0]][bLocation[1]-1];
                gameBoard[bLocation[0]][bLocation[1]] = temp3;
                gameBoard[bLocation[0]][bLocation[1]-1] = "b";
                bLocation[1] = bLocation[1]-1;
            }
        else if(validMoves2.contains("right") && dir.equals("right")){
                String temp4 = new String(); 
                temp4 = gameBoard[bLocation[0]][bLocation[1]+1];
                gameBoard[bLocation[0]][bLocation[1]] = temp4;
                gameBoard[bLocation[0]][bLocation[1]+1] = "b";
                bLocation[1] = bLocation[1]+1;
            }
    }

    public static void printState(){
        System.out.println(Arrays.deepToString(gameBoard)); 
    }

    public void getbLocation(){
        for(int i=0; i<gameBoard.length; i++){
            for(int j=0; j<gameBoard[i].length; j++){
                if(gameBoard[i][j].equals("b"))
                {
                    bLocation[0] = i;
                    bLocation[1] = j;
                    break;
                }
            }
        }   
        System.out.println(Arrays.toString(bLocation));
    }

    public int heuristicOneHValue(){
        int hValue = 0;
        if(!gameBoard[0][0].equals("b")){
            hValue++;
        }
        if(!gameBoard[0][1].equals("1")){
            hValue++;
        }
        if(!gameBoard[0][2].equals("2")){
            hValue++;
        }
        if(!gameBoard[1][0].equals("3")){
            hValue++;
        }
        if(!gameBoard[1][1].equals("4")){
            hValue++;
        }
        if(!gameBoard[1][2].equals("5")){
            hValue++;
        }
        if(!gameBoard[2][0].equals("6")){
            hValue++;
        }
        if(!gameBoard[2][1].equals("7")){
            hValue++;
        }
        if(!gameBoard[2][2].equals("8")){
            hValue++;
        }
        return hValue;
    }


    public void solveAstar(String heuristic){
        setFinalGoalState();
        ArrayList<Node> priorityQueue = new ArrayList<Node>();
        int h = heuristicOneHValue();
        if(heuristic.equalsIgnoreCase("h1"))
        {
            Node root = new Node(0,h,null,gameBoard);
            priorityQueue.add(root);
            while(priorityQueue != null){
                Node currentNode = priorityQueue.get(0);
                priorityQueue.remove(0);
                gameBoard = currentNode.state;
                ArrayList<String> moves = isValidMove();
                for(int i = 0; i < moves.size(); i++){
                    move(moves.get(i));
                    Node child = new Node(currentNode.getG(),heuristicOneHValue(),currentNode,currentNode.getState());
                    for(int j = 0; j <= priorityQueue.size(); j++){
                        if(priorityQueue.size() == 0){
                            priorityQueue.add(0, child);
                        }
                        else if((priorityQueue.get(j).getG()+priorityQueue.get(j).getH()) > (child.getG()+child.getH())){
                            priorityQueue.add(j, child);
                        }
                    }
                }
                if(priorityQueue.get(0).getState() == finalGoalState){
                    priorityQueue = null;
                }
            }
        }
        //h2 here
    }

    public static void main (String[]args){
        EightPuzzle b1=new EightPuzzle();
        b1.setState("156 37b 284");
        b1.getbLocation();
        b1.solveAstar("h1");
    }
}

Node Class

class Node {

    public String[][] state;
    public Node parent;
    public int g;
    public int h;

    public Node(int g, int h, Node parent, String[][] state){
        this.g = g;
        this.h = h;
        this.parent = parent;
        this.state = state;
    }

    public String[][] getState(){
        return state;
    }
    public int getG(){;
        return g;
    }
    public int getH(){
        return h;
    }
    public Node getParent(){
        return parent;
    }
    public void setState(String[][] state){
        this.state = state;
    }
    public void setG(int g){
        this.g = g;
    }
    public void setH(int h){
        this.h = h;
    }
    public void setParent(Node parent){
        this.parent = parent;
    }
}
natanael
  • 230
  • 1
  • 7
  • This is a very complex explanation. Try to trim it down to the smallest version of the code that reproduces the problem - that will make people more likely to help (and might help you find the problem on your own). – nhouser9 Oct 04 '16 at 17:00

1 Answers1

0

First of all, I don't know if I've fully understood your problem, but if I'm right, your saying that the node states aren't different between them.

If that's the case, then your problem is in this line:

Node child = new Node(currentNode.getG(),heuristicOneHValue(),currentNode,currentNode.getState());

You're sharing the pointer to the state object among the different nodes, so you need to work with a copy of the state instead. The getState method in the Node class will be the best place to make the copy in my opinion, so you avoid any further problems when other objects modify the state.

Example:

public String[][] getState(){
    String[][] returnState = new String[this.state.length][this.state[0].length];
    for (int i = 0; i < this.state.length; i++) {
        for (int j = 0; j < this.state[0].length; j++) {
            returnState[i][j] = this.state[i][j];
        }
    }
    return returnState;
}
raven1981
  • 1,415
  • 1
  • 16
  • 20