Java - 二维数组操作影响索引的倒数

Java - 2D Array manipulation is affecting the inverse of the index

我正在尝试通过应用我的知识和制作 Java 国际象棋游戏来学习 Java。目前它是严格的文本。在我的程序中,我有一个功能可以让我移动一块。所有的棋子都存储在一个称为棋盘的二维数组中。然而,当我试图移动一块时,问题在于这个函数。如果我出于某种原因将一块 ("Rook") 从 board[7][0] 移动到 board[6][0],则与此相反的 (board[0][0]board[1][0]) 也会移动。

这是没有任何修改的电路板 displayBoard()

ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK, 
PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, 
null, null, null, null, null, null, null, null, 
null, null, null, null, null, null, null, null, 
null, null, null, null, null, null, null, null, 
null, null, null, null, null, null, null, null, 
PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, 
ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK,

棋子移动后的棋盘:

null, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK, 
ROOK, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, 
null, null, null, null, null, null, null, null, 
null, null, null, null, null, null, null, null, 
null, null, null, null, null, null, null, null, 
null, null, null, null, null, null, null, null, 
ROOK, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, 
null, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK, 

应该只移动了左下方的车。

Board.Java Class:

public class Board {
    public Pieces[][] board = new Pieces[8][8];

    private Pieces[] MainLine = new Pieces[]{Pieces.ROOK, Pieces.KNIGHT, Pieces.BISHOP, Pieces.QUEEN, Pieces.KING, Pieces.BISHOP, Pieces.KNIGHT, Pieces.ROOK};
    private Pieces[] BishopLine = new Pieces[]{Pieces.PAWN, Pieces.PAWN, Pieces.PAWN, Pieces.PAWN, Pieces.PAWN, Pieces.PAWN, Pieces.PAWN, Pieces.PAWN};

    public Board(){
        resetBoard();
    }

    private void resetBoard() {
        board = new Pieces[8][8];
        board[0] = MainLine;
        board[board.length - 1] = MainLine;
        board[1] = BishopLine;
        board[board.length - 2] = BishopLine;
    }

    public void displayBoard() {
        for(int rank = 0; rank < board.length; rank++) {
            System.out.println("");
            for(int file = 0; file < board.length; file ++) {
                System.out.print(board[rank][file] + ", ");
            }
        }
        for(int x = 0; x < 3; x++) {
            System.out.println("");
        }
    }

    public Pieces getPiece(int rank, int file) {
        return board[rank][file];
    }

    public void movePiece(int rank, int file, int newRank, int newFile) {
        Pieces temp = getPiece(rank, file);
        board[rank][file] = null;
        board[newRank][newFile] = temp;
    }
}

在我的 Main Class 中,我创建了一个新的棋盘实例,显示它,移动一块 movePiece(7, 0, 6, 0) 然后再次显示棋盘。我认为主要问题出在 Board.java class 中,我不知道哪里出了问题,也不知道为什么其他索引会受到影响。任何人都可以向我解释为什么会发生这种情况或如何更好地操纵 2D board 数组以进一步实现我的目标,即在不影响任何其他棋子的情况下将棋子移动到给定位置。

编辑:添加了请求的额外代码-

Main.Java 创建一个游戏实例,在该实例中其他条件将在未来发生,但是它是 Game.java,它直接引用 Board.Java,因为它继承自它:

public class Main {
    public static void main(String[] args) {
        Game game = new Game();

        game.displayBoard();
        game.movePiece(7, 0, 6, 0);
        game.displayBoard();

    }
}

Game.java 只需调用 super 即可创建面板。它稍后将拥有额外的功能:

public class Game extends Board {
    public Game() {
        super();
    }

}

问题出在 Board 的构造函数中,更具体地说是 resetBoard() 方法,您将第一行初始化为与最后一行相同的数组,同样,第二行指的是与倒数第二行相同的数组:

private void resetBoard() {
    board = new Pieces[8][8];

    // board[0] is a reference to MainLine so if we change move
    // into or out of board[0] MainLine will be affected and 
    // we won't be able to start with a fresh board by calling boardReset()
    // board[0] = MainLine;

    // Initialize the first row to a fresh array every time we call
    // reset.
    board[0] = new Pieces[] { 
        Pieces.ROOK, Pieces.KNIGHT, Pieces.BISHOP, Pieces.QUEEN, 
        Pieces.KING, Pieces.BISHOP, Pieces.KNIGHT, Pieces.ROOK
    };

    // This makes the last line and
    // the first line point to the same array
    // You need to create a new array that is a deep copy
    // of the array.
    // board[board.length - 1] = MainLine; 

    // Create new array by copying the original array
    board[board.length - 1] = Arrays.copyOf(board[0], board[0].length);

    // Similarly
    //board[1] = BishopLine;
    Arrays.fill(board[1], Pieces.PAWN);
    board[board.length - 2] = Arrays.copyOf(board[1], board[1].length);

    // You don't need member variables MainLine and BishopLine
    // and you can remove them if you want.
}

现在两行都指向不同的数组。当你调用 movePiece(7, 0, 6, 0) 你应该看到

ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK, 
PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, 
null, null, null, null, null, null, null, null, 
null, null, null, null, null, null, null, null, 
null, null, null, null, null, null, null, null, 
null, null, null, null, null, null, null, null, 
PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, 
ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK, 



ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK, 
PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, 
null, null, null, null, null, null, null, null, 
null, null, null, null, null, null, null, null, 
null, null, null, null, null, null, null, null, 
null, null, null, null, null, null, null, null, 
ROOK, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, 
null, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK, 

问题出在resetBoard()函数上。在这里,您对两个玩家的棋子使用相同的对象引用。因此,由于 java 是按值传递的,所以 board[7][0] 和 board[0][0] 都指的是同一个对象,当一个对象发生变化时,另一个对象也会发生变化。

为简单起见,您可以尝试以下操作

或者分段创建复制构造函数class并从resetBoard方法调用

或者分片覆盖clone()方法class做一个对象的深拷贝,这样两个引用就不会指向一个共同的对象。

或使用Arrays.copyOf(arrayToCopy,length)创建一个新副本。

 private void resetBoard() {
    board = new Pieces[8][8];
    board[0] = new Pieces[]{Pieces.ROOK, Pieces.KNIGHT, Pieces.BISHOP, Pieces.QUEEN, Pieces.KING, Pieces.BISHOP, Pieces.KNIGHT, Pieces.ROOK};
    board[board.length - 1] = new Pieces[]{Pieces.ROOK, Pieces.KNIGHT, Pieces.BISHOP, Pieces.QUEEN, Pieces.KING, Pieces.BISHOP, Pieces.KNIGHT, Pieces.ROOK};
    board[1] = new Pieces[]{Pieces.PAWN, Pieces.PAWN, Pieces.PAWN, Pieces.PAWN, Pieces.PAWN, Pieces.PAWN, Pieces.PAWN, Pieces.PAWN};;
    board[board.length - 2] = new Pieces[]{Pieces.PAWN, Pieces.PAWN, Pieces.PAWN, Pieces.PAWN, Pieces.PAWN, Pieces.PAWN, Pieces.PAWN, Pieces.PAWN};;
}