【问题标题】:OOP Design for Chess Game in Java (Trouble with Piece / Board Interaction)Java中国际象棋游戏的OOP设计(棋子/棋盘交互问题)
【发布时间】:2014-12-31 18:54:04
【问题描述】:

我正在尝试用 Java 编写自己的国际象棋游戏。我已经开始编写课程,我的高级想法如下:

我有一个包含这些字段的 Piece 类:

private String name;
private String color;

最初我打算为每个棋子设置一个 x 和 y 坐标,但这似乎更像是棋盘的属性。这让我...

我有一个 Board 类,其字段如下:

Piece[][] myBoard = new Piece[8][8];

我不确定我应该在哪里/如何跟踪碎片的位置。到目前为止,我只有一个 Piece 对象的二维数组。但是,我认为这会带来一些挑战。例如,假设用户点击一块,想要移动它。我需要确定移动是否有效,为此,我需要棋子所在的当前格子。

如果我有每个棋子的 x 和 y 坐标,我将更新两个地方的游戏状态(在 Board 类的 2d 数组中)以及当前棋子的 x 和 y 坐标。这似乎很糟糕......

有什么建议吗?

感谢您的帮助, 马里格斯

【问题讨论】:

  • 这有点取决于解释,但您可能会考虑的一种方法是让棋盘由正方形而不是棋子组成。然后每个正方形可能会或可能不会容纳一块。然后,棋盘将负责根据所选棋子和用户尝试移动到的方格来确定移动是否有效。所以至少在我看来,棋盘控制着一切,棋子不知道它们在哪里,但也许只是具有指定移动尝试的有效偏移量的函数。
  • 这是一个相当广泛的问题,因此很难回答。我会说名称和颜色绝对不应该是字符串。而是使用枚举。 enum Name { PAWN, ROOK, KNIGHT, BISHOP, KING, QUEEN }enum Color { BLACK, WHITE }.
  • 我同意在 固定网格 场景中将位置排除在棋子之外 - 棋盘有棋子,棋子本身只是一个值。包含棋子的“单击”网格单元由棋盘内的偏移量确定。
  • 在我看来,这件作品应该有一个坐标来由董事会解释。老实说,棋盘都不能移动棋子。应该有一个单独的类,例如ChessGameChessRules。如果你做了类似的事情,那么你可以轻松地使用相同的类来处理棋子和棋盘,然后如果你想说实现检查器,你只需创建一个 CheckersGame
  • 我想我的部分困惑源于如何连接 myBoard 和实际的 GUI。也许这似乎无关,但与@Dtor 建议的实现,是否有一些 setUp 方法循环遍历二维数组并为我的二维数组中的每个正方形对象创建可点击的 GUI 正方形?

标签: java oop


【解决方案1】:

我可以帮忙,因为我已经用 Java 编写了一个完整的国际象棋引擎,你可以找到 here

需要考虑的几点:

不要让你的棋盘是一个 8x8 的棋子数组,为什么不使用一个 64 维数组Tile'sTile 类可以是抽象的,并且有两个子类OccupiedTileEmptyTile。每个图块可以有一个整数 coordinate,编号为 0 到 63,OccupiedTiles 上也有一个 Piece

Originally I was going to have an x and y coordinate for each piece but that seems like it's more a property of the board. Which brings me to...

一个片段“知道”它的位置很方便,因此使用片段中的整数字段跟踪这一点,恕我直言,这不是一件坏事。

Piece 还应该有子类,如 KnightBishopPawnRookQueenKing。这样他们的toString() 方法可以为pieceName 返回一个固定值,而不是将其作为成员字段进行跟踪

最后,为什么不使用名为Alliance 的枚举来跟踪白色或黑色棋子。 String 对于这项工作来说非常脆弱,因为调用者可以传递它真正想要的任何值。查看我的Alliance 版本。

我在我的程序中创建了一个这样的片段:

King king = new King(Alliance.BLACK, 4);

我认为这很容易阅读。

【讨论】:

    【解决方案2】:

    您的Piece[8][8] 方法似乎足以跟踪碎片的位置(除了我宁愿让它成为自己的类,其中包含一个数组,您可能希望它迟早拥有更多逻辑,而不仅仅是设置和移动件)。至于确定一块可以移动的位置,这似乎是实际一块的功能:

    public class BoardCoordinates {
       public final char vertical;
       public final int horizontal;
       public BoardCoordinates(char v, int h) { vertical = v; horizontal = h; }
    }
    public class Board {
        private Piece[8][8] state = new Piece[8][8]{};
        public Piece at(BoardCoordinates c) { 
            state[c.vertical - 'a'][c.horizontal];
        }
        public void set(Piece what, BoardCoordinates where) { 
            state[where.vertical - 'a'][where.horizontal] = what;
        }
        public void move(BoardCoordinates from, BoardCoordinates to) {
            set(at(from), to);
            set(null, from);           
        }
    }
    
    public class Piece {
        ....
        public List<BoardCoordinates> findMoves(BoardCoordinates from, Board theBoard) {
            ... 
        }
    }
    

    大多数情况下,您不需要第二个参数,但有必要处理特殊情况 - 例如易位或过路 - 在这些情况下移动的可能性取决于棋盘上的其他棋子(您实际上需要更多信息可以正确处理过路人,但这与手头的问题没有太大关系。

    我绝对同意您在每件作品中保留坐标的说法,这听起来确实是一个可怕的想法。

    【讨论】:

    • 他为什么需要 8x8 件。这是一个可怕的想法,并且不能模拟现实。棋盘上没有 64 个棋子....
    • 不是 8x8 件。 8x8 空格用于片段。它甚至不是“模拟现实”,而是它现实:)
    • 你不同意什么?一个 8x8 数组的元素有 64 个空格?还是象棋棋盘那样?这些不是同意或不同意的论据,它们只是生活中的事实......
    【解决方案3】:

    您的描述中可能缺少另一个对象:BoardTile。每个 BoardTile 都知道它的位置、推断它的颜色和它的相邻图块。它还知道它是空的还是上面有任何 Piece。此外,BoardTile 和 Board 彼此认识(显然!)

    鉴于棋子的行为很大程度上取决于它在棋盘中的位置,它应该知道它在哪个图块中。因此,当您第一次将所有棋子放入棋盘时,棋盘应为每个棋子分配相应的棋子(但请注意,此知识对应于 ChessGame 的规则,而不是棋盘,因为您可能希望使用棋盘和棋子例如,国际象棋的一种变体。)类似地,当棋子从棋盘中取出时(可能是国际象棋游戏),棋子应该失去它的棋子(通过消灭它)。

    使用这三个对象,您将有多种选择。例如,Piece 可以通过回答其瓷砖的位置来了解其位置。棋盘可以通过查询棋子等知道每个棋子的位置。

    【讨论】:

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