简体   繁体   English

带有子节点的Java 8拼图深度优先搜索问题

[英]Java 8-puzzle Depth first search issue with children nodes

I am creating a depth first search algorithm which will ultimately be able to solve a simple 8 puzzle. 我正在创建深度优先搜索算法,该算法最终将能够解决一个简单的8难题。 I am able to read in a file and a goal state and set these variables accordingly. 我能够读取文件和目标状态,并相应地设置这些变量。

The main issue i am receiving is that when i get the children of the current node being evaluated, i am getting 2 "empty" values in my 8 puzzle, and i am also getting an index out of bounds exception. 我收到的主要问题是,当我得到要评估的当前节点的子代时,我在8个难题中得到了2个“空”值,而且我也得到了索引超出范围的异常。

In order to get a child node for a given parent, i first must make a valid move then update the state of the child node to reflect the results of the valid move. 为了获得给定父级的子节点,我首先必须进行有效的移动,然后更新子节点的状态以反映有效移动的结果。

In order to perform a move, i check if it is do-able(if i move left will it still be within the bounds of the puzzle), see posted code. 为了执行移动,我检查它是否可行(如果我向左移动,它将仍然在拼图的范围之内),请参见发布的代码。

It functions correctly for the first 2 moves, left and down as it correctly print the expected result. 对于前2个动作,它在向左和向下移动时均正确运行,因为它正确打印了预期结果。

Below is the output of my current codes execution, you can see it correctly moves left and down, then it starts encountering errors. 下面是我当前代码执行的输出,您可以看到它正确地左右移动,然后开始遇到错误。

 Start state:
 120
 345
 678

 after moving left
 102
 345
 678

 Parent: [[C@1b845568
 after moving down
 125
 340
 678

 Parent: [[C@d032cf5
 after moving left
 102
 340
 678

 Parent: [[C@d032cf5
 after moving down
 125
 348
 670

 Parent:
 125
 340
 678

 after moving up
 125
 348
 670

 Parent: [[C@4b7c8f7f
 after moving left
 125
 304
 670

 Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
 at dcs.aber.ac.uk.puzzle.PuzzleBoard.swapValues(PuzzleBoard.java:193)
 at dcs.aber.ac.uk.puzzle.PuzzleBoard.moveUp(PuzzleBoard.java:142)
 at dcs.aber.ac.uk.puzzle.DFSSolver.addChildren(DFSSolver.java:155)
 at dcs.aber.ac.uk.puzzle.DFSSolver.search(DFSSolver.java:85)
 at dcs.aber.ac.uk.puzzle.DFSSolver.<init>(DFSSolver.java:27)
     at dcs.aber.ac.uk.puzzle.Driver.main(Driver.java:86)

As you can see, after the first two the rest of the printed states are incorrect. 如您所见,在前两个之后,其余的打印状态都不正确。 I will post my code to show how i handle the swapping and updating of the board to see if you can identify where the complication arises. 我将发布我的代码,以显示如何处理板的交换和更新,以查看是否可以确定出现问题的位置。

    public class Node  {



private Node parent;
private char[][] state = new char[3][3];
private double cost; 
private double heurCost; 
private double funcCost; 
private int depth;

public Node() {
    parent = null;
    }

public Node(Node parent) {
    this.parent = parent;

     for(int i = 0; i < 3; i++){
        for(int j = 0; j< 3; j++){
            state[i][j] = parent.getState()[i][j];

        }   

    } 
} 


public void setParent(Node parent) {

    this.parent = parent;


 }


public char[][] getState() {

    return state;
}

public char[][] copyState(){
    char[][] a = new char[3][3];

    for(int i = 0; i < 3; i++){
         for(int j = 0; j< 3; j++){
             a[i][j] = state[i][j];

        }    

    } 

 return a;
}

 } 

 public class PuzzleBoard {

private  char[][] goalState;
private char[][] currentBoard;
private int emptyRow, emptyCol;
private int outOfPlace;

public PuzzleBoard(char[][] currentState, char[][] goal ){


    this.setCurrentState(currentState);
    this.setGoalState(goal);
    trackEmptySqaure();

}

public void setGoalState(char[][] goalState){

    this.goalState = goalState;

}


public void setCurrentState(char[][] currentState){

    this.currentBoard = currentState;

}



public char[][] getCurrentBoard() {

    return currentBoard;

}

public boolean checkIsGoal(char[][] board){

    for(int i = 0; i < 9; i ++){
        for(int j = 0; j < 3; j ++){
            if(!(goalState[i][j] != (board[i][j]))){

                return false;
            }
        }
    }
    return true;
}

public void trackEmptySqaure() {

    for(int i = 0; i < 3; i ++){
        for (int j = 0; j < 3; j ++){
            if(currentBoard[i][j] == '0'){
                emptyCol = j;
                emptyRow = i;
            }

        }
    }

}

public int getemptyRow() {
    return emptyRow;

}

public int getemptyCol() {
    return emptyCol;

}



public Node moveLeft(Node parent){
    currentBoard = parent.copyState();

    Node result = new Node(parent);

    /* check you can move 'empty' left one space*/
    if(getemptyCol()  > 0){


        swapValues(result.getState(),emptyRow, emptyCol, 1);


        return result;
    }

    return null;
}
public Node moveDown(Node parent){
    currentBoard = parent.copyState();

    Node result = new Node(parent);

    /* check you can move 'empty' down one space*/
    if(getemptyRow()  < 2){


        swapValues(result.getState(),emptyRow, emptyCol,2);

        return result;
    }

    return null;
}

public Node moveUp(Node parent){
    currentBoard = parent.getState();
    Node result = new Node(parent);


    /* check you can move 'empty' up one space*/
    if(getemptyRow() > 0){


        swapValues(result.getState(),emptyRow, emptyCol,2);



        return result;
    }

    return null;
}

public Node moveRight(Node parent){
    currentBoard = parent.getState();
    Node result = new Node(parent);


    /* check you can move 'empty' right one space*/
    if(getemptyCol()  < 2){


        swapValues(result.getState(),emptyRow, emptyCol,2);



        return result;
    }

    return null;
}

   public void swapValues (char[][] c,int x, int y, int method){

    char empty = '0';
    char swapValue = '0'; // should never be kept as 0

    if(method == 1){ // left

        swapValue= c[emptyRow][emptyCol -1];
        c[emptyRow][emptyCol] = swapValue;
        c[emptyRow][emptyCol -1] = empty;
        trackEmptySqaure();


    }
    else if(method == 2){ // down

        swapValue = c[emptyRow + 1][emptyCol];
        c[emptyRow][emptyCol] = swapValue;
        c[emptyRow + 1][emptyCol] = empty;
        trackEmptySqaure();


    }
    else if(method == 3){ // up
        swapValue = c[emptyRow -1][emptyCol];
        c[emptyRow][emptyCol] = swapValue;
        c[emptyRow -1][emptyCol] = empty;
        trackEmptySqaure();


    }
    else if(method == 4){// right
        swapValue = c[emptyRow][emptyCol + 1];
        c[emptyRow][emptyCol] = swapValue;
        c[emptyRow ][emptyCol + 1] = empty;
        trackEmptySqaure();


    }




}
public class DFSSolver {

private ArrayList<Node> closed = new ArrayList<Node>();

private Stack<Node> open = new Stack<Node>();

private PuzzleBoard pb;

private boolean solved;

private int numberOfSteps;

public DFSSolver(PuzzleBoard puzzle) {

    pb = puzzle;
    numberOfSteps = 0;
    solved = false;
    Node root = new Node();
    root.setState(pb.getCurrentBoard());
    addToOpen(root);
    checkIfSolved(root);
    search();

}

public boolean inOpenList(Node n){

    for(Node node: open){
        if(node.equals(n)){
            return true;
        }

    }
    return false;

}

public boolean inClosedList(Node n){

    for(Node node: closed){
        if(node.equals(n)){
            return true;
        }

    }
    return false;

}


public void addToOpen(Node n){
    open.push(n);
}

public void addToClosed(Node n){
    closed.add(n);

}

public Node popOpen(){
    return open.pop();
}

public void removeFromClosed(Node n){

    closed.remove(n);

}



public void search(){

    while(!solved){

        Node current = popOpen();
        if(current != null){
            if(!(inClosedList(current))){ // is it previously explored?
                checkIfSolved(current);
                addChildren(current);
                numberOfSteps++;

            }

            addToClosed(current);
        }
    }
    System.out.println("No of steps: " + numberOfSteps);
}

public void checkIfSolved(Node curr) {
    char[][] goal = pb.getGoal();
    char[][] current = curr.getState();
    for(int i = 0; i < 3; i ++){
        for(int j = 0; j < 3; j ++){
            char c = current[i][j];
            char x = goal[i][j];
            if(c != x){
                return;
            }
        }
    }

    solved = true;
}


public void addChildren(Node parent){


    Node newNode = new Node(parent);



    newNode = pb.moveLeft(parent);

    if(newNode != null){
        System.out.println("Parent: " + parent.getState().toString());
        System.out.println("atfer moving left");
        System.out.println(newNode.toString());
        addToOpen(newNode);


    }

    newNode = pb.moveDown(parent);

    if(newNode != null){
        System.out.println("Parent: " + parent.getState().toString());
        System.out.println("atfer moving down");
        System.out.println(newNode.toString());
        addToOpen(newNode);


    }


    newNode = pb.moveRight(parent);

    if(newNode != null){
        System.out.println("Parent: " + parent.getState().toString());
        System.out.println("atfer moving right");
        System.out.println(newNode.toString());
        addToOpen(newNode);


    }


    newNode = pb.moveUp(parent);

    if(newNode != null){
        System.out.println("Parent:\n " + parent.toString());
        System.out.println("atfer moving up");
        System.out.println(newNode.toString());
        addToOpen(newNode);


    }
}

in move up method you call swap values like this : 在上move up方法中,您可以这样调用swap values

swapValues(result.getState(),emptyRow, emptyCol,2);

but i guess it should be : 但我想应该是:

swapValues(result.getState(),emptyRow, emptyCol,3);

also you'll want to call : 您也想致电:

swapValues(result.getState(),emptyRow, emptyCol,4);

in your moveRight method 在你的moveRight方法中

I believe the other problem you reported is because the code's notion of where the empty square is doesn't always match the node you are currently processing. 我相信您报告的另一个问题是因为代码中关于空正方形位置的概念并不总是与您当前正在处理的节点匹配。 You call trackEmptySquare after each swap, but a better place would be to call it at before moveLeft, moveRight, etc., so that it will match the node you are currently looking at. 您可以在每次交换之后调用trackEmptySquare,但更好的方法是 moveLeft,moveRight等之前调用它,以便它与您当前正在查看的节点匹配。

But the better approach would be to get rid of the variables that track the empty row and col. 但是更好的方法是摆脱跟踪空行和col的变量。 Each Node has its own empty square. 每个节点都有其自己的空正方形。 You can either move the empty-row/empty-col variables into the Node class, and update them every time the Node's state changes. 您可以将empty-row / empty-col变量移到Node类中,并在每次Node状态更改时对其进行更新。 Or don't add them at all, just add a method that searches Node.state for the empty square. 或根本不添加它们,只需添加一种在Node.state中搜索空正方形的方法即可。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM