-1

下面的 evalBoard() 方法接受 brd,并将其参数复制到 pos 中。然后它遍历一些可能的值,通过调用 makeMove() 对 pos 进行更改。这些对 pos.makeMove 的调用也在某种程度上改变了 brd 内部的值。通过我在 evalBoard 中标记的区域可以清楚地看到它。为什么会这样?

public Move evalBoard(Board brd) {
    // evaluates current board and returns point of best move

    Move best;
    Move tmp = new Move(-1, -1, LOSE, brd.getPlayer());
    if (brd.getPlayer() == PLAYER1) {
        best = new Move(-1, -1, LOSE, PLAYER1);
    } else {
        best = new Move(-1, -1, WIN, PLAYER2);
    }
    // check if board is empty if so return optimal move
    //

    if (brd.isEmpty()) {

        return (new Move(0, 0, 0, PLAYER1));

    }

    // iterate through possible moves
    for (int x = 0; x < 3; x++) {
        for (int y = 0; y < 3; y++) {
            if (brd.getSpace(x, y) == ' ') {
                // copy all of brd to pos

                pos=new Board(brd.getBoard(),brd.getPlayer());

                tmp.setX(x);
                tmp.setY(y);
                tmp.setPlayer(brd.getPlayer());
/*
 *   problem can be seen by stepping through the next line.  brd is changed at the same time.
*/
                pos.makeMove(tmp);//Problem is here this call is changing brd as well

                // evaluate for immediate win or loss
                if (brd.getPlayer() == PLAYER1) {
                    if (pos.win()) {// immediate win
                        tmp.setValue(WIN);
                        return tmp;
                    } else { // not a winning move check it's recursive
                                // value
                        pos.setPlayer(PLAYER2);
                        tmp.copyFrom(evalBoard(pos));
                        if (tmp.getValue() >= best.getValue()) {
                            best.copyFrom(tmp);
                        }

                    }
                } else {
                    if (pos.win()) {// immediate loss
                        tmp.setValue(LOSE);
                        return tmp;
                    } else {// not a losing move check it's recursive value
                        pos.setPlayer(PLAYER1);
                        tmp.copyFrom(evalBoard(pos));
                        if (tmp.getValue() <= best.getValue()) {
                            best.copyFrom(tmp);
                        }
                    }
                }

            }
        }
    }
    return best;

}

这是董事会课程:

public class Board {
final boolean PLAYER1=true;
final boolean PLAYER2=false;
public char[][] board = new char[3][3];
public boolean Turn;

public Board(char[][] brd,boolean plr1){
    board=brd;
    Turn=plr1;

}
public char getPlayerChar(){
    if (Turn==PLAYER1){
        return 'X';
    }else{
        return 'O';
    }
        }
public char[][] getBoard(){
    return board;
}
public void setBoard(char[][] brd){
    board=brd;
}
public void displayBoard(){
    for(int y=0;y<3;y++){
        for(int x=0;x<3;x++){
            System.out.print(board[x][y]);
            if (x<2){
                System.out.print(" | ");
            } 

        }
        System.out.println("");
        if (y<2){
            System.out.println("----------");

        }

    }
}
public void makeMove(Move mv){
    //System.out.println("hit");

    if (mv.getPlayer()==PLAYER1){
        board[mv.getX()][mv.getY()]='X';
    }else{
        board[mv.getX()][mv.getY()]='O';
    }

}
public void setPlayer(boolean plr){
    Turn=plr;
}
public boolean getPlayer(){
    return Turn;
}
public char getSpace(int x,int y){
    return board[x][y];

}
public boolean isEmpty(){
    for(int x=0;x<3;x++){
        for(int y=0;y<3;y++){

            if(!(board[x][y]==' ')){
                return false;
            }
        }
    }
    return true;
}
public boolean win(){
    char plrChar;
    //returns true if board is winning position for current player
    if (Turn==PLAYER1){
        plrChar='X';
    }else {
        plrChar='O';
    }
    //Across
    for(int y=0;y<3;y++){
        if (board[0][y]+board[1][y]+board[2][y]==(plrChar+plrChar+plrChar)){
            return true;
        }
    }
    //Up/Down
    for(int x=0;x<3;x++){
        if (board[x][0]+board[x][1]+board[x][2]==(plrChar+plrChar+plrChar)){
            return true;
        }
    }
    //Diagonals
        //top left to bottom right
    if (board[0][0]+board[1][1]+board[2][2]==(plrChar+plrChar+plrChar)){
        return true;
    }
        //bottom left to top right
    if (board[0][2]+board[1][1]+board[2][0]==(plrChar+plrChar+plrChar)){
        return true;
    }
    return false;
}


}
4

1 回答 1

2

问题是当你这样做时:

  pos=new Board(brd.getBoard(),brd.getPlayer());

您正在创建一个与原始(in pos)共享board数组的新 Board (in )。这就是构造函数在这里所做的:BoardbrdBoard

  public Board(char[][] brd,boolean plr1){
      board=brd;
      ...

Naturally, since there is only one array, when you update it via one Board the changes are visible via the other Board.

If you don't want the old and new Board instances to share the same char array, then you should not assign like that. Instead, you should use a nested loop to copy the state from brd to board.


The Lesson to be learned

This is an example of a "leaky abstraction". The getBoard and setBoard methods allow code external to the Board to damage the state of a Board instance ... in a rather unexpected way. Non-leaky versions of these methods and the Board constructor would copy the contents of the array (may be to a new array) rather than allowing the Boards array instance to be accessible outside of the abstraction boundary.

于 2013-03-31T03:43:45.873 回答