【问题标题】:Java 8-puzzle Depth first search issue with children nodes带有子节点的Java 8-puzzle深度优先搜索问题
【发布时间】:2013-11-11 21:18:11
【问题描述】:

我正在创建一个深度优先搜索算法,该算法最终将能够解决一个简单的 8 难题。我能够读取文件和目标状态并相应地设置这些变量。

我收到的主要问题是,当我对当前节点的子节点进行评估时,我在我的 8 拼图中得到了 2 个“空”值,而且我还得到了一个索引越界异常。

为了获得给定父节点的子节点,我首先必须进行有效移动,然后更新子节点的状态以反映有效移动的结果。

为了执行移动,我检查它是否可行(如果我向左移动它仍然在拼图的范围内),请参阅发布的代码。

当它正确打印预期结果时,它在前 2 个移动(左右移动)中正常运行。

下面是我当前代码执行的输出,你可以看到它正确地左右移动,然后它开始遇到错误。

 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)

如您所见,在前两个之后,其余的打印状态都不正确。我将发布我的代码来展示我如何处理板的交换和更新,看看你是否能确定出现问题的地方。

    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);


    }
}

【问题讨论】:

  • 我找不到你的swapValues方法...
  • @EugenHalca 抱歉,我已经更新了源代码。
  • 使用 IDE 中的调试器检查变量的值,您一定会发现错误。

标签: java search depth


【解决方案1】:

move up 方法中,您像这样调用swap values

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

但我想应该是:

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

你也想打电话:

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

在您的 moveRight 方法中

【讨论】:

  • 感谢解决了索引越界异常,我的完全错误忘记在复制和粘贴后编辑值啊啊!但我仍然有相同的输出错误,它显示 2 个“0”值。猜猜我和调试器今晚有个约会!
  • @chrisedwards 我想补充一点,在大多数情况下,您的算法永远不会停止运行,因为您检查了已经检查过一次的节点,因此将 open 变量从 Stack 更改为 Set 和在Node 类中正确实现equals 方法...
  • 我很欣赏这个建议,但规范要求使用 Stack 类。
  • 如果需要,您可以使用Stack,但请确保不要两次处理相同的Node
  • 谢谢,我理解我在这方面的错误,仍然不明白为什么它在第二次运行时在板上添加了两个“0”值。目前正在尝试使用调试器解决它,但进展并不顺利!
【解决方案2】:

我相信您报告的另一个问题是因为代码中关于空方块所在位置的概念并不总是与您当前正在处理的节点匹配。您在每次交换之后调用 trackEmptySquare,但更好的位置是在 before moveLeft、moveRight 等处调用它,以便它与您当前正在查看的节点匹配。

但更好的方法是去掉跟踪空行和列的变量。每个节点都有自己的空方格。您可以将 empty-row/empty-col 变量移动到 Node 类中,并在每次 Node 的状态更改时更新它们。或者根本不添加它们,只需添加一个在Node.state 中搜索空方格的方法即可。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-07
    相关资源
    最近更新 更多