【问题标题】:Programming a chess game in Java, and gameOver boolean not working用Java编写国际象棋游戏,而gameOver布尔值不起作用
【发布时间】:2014-09-29 02:46:31
【问题描述】:

我正在尝试用 Java 制作一个可以在控制台上玩的国际象棋游戏。对于每一步,游戏都会向玩家询问一个棋子(例如,第二行第三列中的棋子为 12)和最终位置(例如,第四行第三列中的棋子为 32)。一切都运行良好,包括测试移动是否非法以及给定玩家是否处于检查状态,但我的 gameOver 布尔值似乎在要求第一次移动之前改变了我的棋盘数组的值。

这里是相关代码。从我的主要方法:

public static void main(String[] args) {
    int[][] board = {   {12, 13, 14, 15, 16, 14, 13, 12},
                        {11, 11, 11, 11, 11, 11, 11, 11},
                        {0,  0,  0,  0,  0,  0,  0,  0},
                        {0,  0,  0,  0,  0,  0,  0,  0},
                        {0,  0,  0,  0,  0,  0,  0,  0},
                        {0,  0,  0,  0,  0,  0,  0,  0},
                        {21, 21, 21, 21, 21, 21, 21, 21},
                        {22, 23, 24, 25, 26, 24, 23, 22}
                    };
    Scanner scan = new Scanner(System.in);
    boolean oneTurn = true;
    while(!(gameOver(oneTurn, board))) {
        printBoard(board);
        System.out.println(((oneTurn) ? "1's" : "2's") +  " turn");
        System.out.print("What piece? ");
        int origin = scan.nextInt();

gameOver 布尔值,用于测试当前玩家是否可以做出任何合法且不会阻止玩家的动作:

public static boolean gameOver(boolean oneTurn, int[][] board) {
    for (int a = 0; a<8; a++) {
        for(int b = 0; b<8; b++) {
            for (int c = 0; c<8; c++) {
                for(int d = 0; d<8; d++) {
                    if(board[a][b] / 10 == (oneTurn ? 1 : 2) && !(illegal(oneTurn, 10*a+b, 10*c+d, board)) && !(illegalCheck(oneTurn, 10*a+b, 10*c+d, board))) return false;
                }
            }
        }
    }
    return true;
}

check 方法,试图找到其他玩家可以做的合法移动,从而消除国王:

public static boolean check(boolean oneTurn, int[][] board) {
    int king = kingNum(oneTurn, board);
    for (int a = 0; a<8; a++) {
        for(int b = 0; b<8; b++) {
            if(board[a][b] / 10 == (oneTurn ? 2 : 1) && !(illegal(!oneTurn, 10*a+b, king, board))) return true;
        }
    }
    return false;
}

非法检查方法,用于测试移动是否会阻止玩家。我认为这就是问题所在。我试图制作一个单独的 newBoard,这样原来的板子就不会改变,但它仍然会产生问题。

public static boolean illegalCheck(boolean oneTurn, int origin, int dest, int[][] board) {
    int[][] newBoard = board;
    newBoard[dest / 10][dest % 10] = board[origin / 10][origin % 10];
    newBoard[origin / 10][origin % 10] = 0;
    if(check(oneTurn, newBoard)) return true;
    else return false;
}

当我第一次运行程序时,我得到的第一个输出是这样的:

    |  0 |  1 |  2 |  3 |  4 |  5 |  6 |  7 |
_____________________________________________

0   | 1R |    | 1B | 1Q | 1K | 1B | 1N | 1R |
_____________________________________________

1   | 1P | 1P | 1P | 1P | 1P | 1P | 1P | 1P |
_____________________________________________

2   |    |    |    |    |    |    |    |    |
_____________________________________________

3   |    |    |    |    |    |    |    |    |
_____________________________________________

4   |    |    |    |    |    |    |    |    |
_____________________________________________

5   |    |    |    |    |    |    |    |    |
_____________________________________________

6   | 2P | 2P | 2P | 2P | 2P | 2P | 2P | 2P |
_____________________________________________

7   | 2R | 2N | 2B | 2Q | 2K | 2B | 2N | 2R |
_____________________________________________

1's turn
What piece? 

gameOver 发现的第一个合法移动是马移动,所以我认为这就是马没有出现在第一个棋盘上的原因。当我将 printBoard 方法放在布尔测试之前时,电路板打印完美。

我最近才开始学习编程,所以如果我能提供任何关于为什么会发生这种情况的建议,我将不胜感激。我错过了一些明显的东西。让我知道我是否可以提供其他详细信息。谢谢!

【问题讨论】:

  • 你的 gameOver 函数根本不可读。选择一些有意义的变量名而不是太花哨有多难?!!!
  • 还不错。只是没必要。另外,为什么不可读?为什么它“太花哨”?随意编辑它没有绒毛。
  • 很抱歉不够清晰。我认为这对我自己来说将是一个快速学习项目,只有我会阅读其代码,但这个小问题让我感到沮丧,不得不求助于外部资源。 gameOver 中的字母只是数组的索引(a 行,b 列到 c 行,d 列)。非法检查可能是一个错误的变量名,但它会测试从 ab 到 cd 的移动是否会检查玩家。

标签: java chess


【解决方案1】:

当你写作时

int[][] newBoard = board;
newBoard[dest / 10][dest % 10] = board[origin / 10][origin % 10];
newBoard[origin / 10][origin % 10] = 0;

您正在创建newBoard 作为新引用与board 相同的数组对象,然后继续修改数组。您可以像这样复制它:

int[][] newBoard = new int[8][];
for (int i = 0; i < newBoard.length; ++i)
    newBoard[i] = board[i].clone();

Java 的多维数组是对其他数组的引用数组(因为数组是对象),所以首先我们创建一个新的顶级数组,然后将子数组的副本分配给它。 (关于Object.clone() 和Cloneable 有很多规则,但这里你要知道的是,克隆一个数组会产生一个具有相同值的新数组。对于多维数组,这是一个浅拷贝(拷贝指相同的子数组),所以我们不能只调用board.clone() 就可以了。)

【讨论】:

  • 谢谢,我认为该解决方案有效!因此,为了将来参考,很明显,在整个程序中,每个顶级数组都在访问相同的二级数组。但是顶级数组是否也始终相同,或者我可以有两个名为 board 的数组引用不同的东西?
  • 您可以有两个名为board 的引用指向不同的数组,是的。 (例如,如果一个类有一个名为 board 的字段,则该类的每个实例都可以引用与该字段不同的数组。在不同或递归方法中的局部变量也是如此。)数组本身不知道引用指向什么他们。但仅分配 board = ... 不会创建新数组,除非 ... 包含 new 或调用记录在案的库函数以返回新数组。
【解决方案2】:

如果您认为这是由于数组的副本,请在非法检查中尝试System.arraycopy。

【讨论】:

  • 我将初始化更改为:int[][] newBoard = new int[8][8]; System.arraycopy(board, 0, newBoard, 0, board.length);但它没有用。这是正确使用arraycopy吗?感谢您的帮助!
【解决方案3】:

我建议您使用调试器并设置一些断点,这样您就可以看到到底发生了什么,这样您就不会猜测了。

有关使用 java 调试会话的更多信息:http://docs.oracle.com/javase/7/docs/technotes/tools/windows/jdb.html

【讨论】:

  • 感谢您的提示。我完全没有调试器的经验,但我会试一试。您知道布尔值如何以不同的方法更改变量吗?我的理解是变量只能在它们自己的方法中更改,但在这种情况下似乎是不正确的。
  • 我还没有真正看过整个代码,如果您需要帮助,您可以创建一个重现相同行为的测试用例,如果确实如此,请编辑您的问题并仅发布测试用例。另外,我没有看到 gameOver 布尔变量,而是看到了一个带有该标识符的方法。做一个测试用例或使用调试器,这应该是你最好的选择。
猜你喜欢
  • 1970-01-01
  • 2015-07-16
  • 1970-01-01
  • 2015-05-02
  • 1970-01-01
  • 2016-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多