我正在创建一个国际象棋引擎。我有 Piece 接口(interface),Rook、Bishop 等实现了这个类。我的板子是 Piece[][] 数组。假设白人玩家想要移动他的象。我将目的地的坐标和板引用传递给主教。 Bishop 检查,如果目的地在同一条对角线上,然后它会询问棋盘在他的位置和目的地方格之间是否没有任何棋子。从 OOP 的角度来看,这样做可以吗?
谢谢

最佳答案

它有点微妙。

面向对象的观点

从 OOP 的角度来看,人们可能会质疑 Board 是否应该首先是一个 Piece[][] 数组。一个漂亮的、干净的、面向对象的设计可能会涉及类似

interface Board {
    Piece get(int r, int c);

    // Should this be here? See below...
    void set(int r, int c, Piece p);
}

然后,一个关键问题是:主教会不会将“自己”放在给定棋盘的目标位置上?或者,关注 OOP 点:分配给该棋子的棋盘是可变的还是“只读的”?可以想象一个 MaliciousBishop 类,当它被赋予 Board 时,通过将自己置于国王的位置来暗杀对手的国王。

从非常高级、抽象的 OOP 的角度来看,人们可能会质疑 Piece 是否应该具有任何智能。 Piece 是一块愚蠢的塑料。 不知道 任何有关国际象棋规则的信息。 (玩家)可以将棋子放在任何地方,无论是遵守还是无视国际象棋规则。因此,遵守甚至检查任何规则当然不是这件作品的工作。可以说遵守规则是对玩家的期望,而强制遵守规则是上级智能(可能是“ChessGameManager”类)的工作。

似乎 (!) 适合 OO 国际象棋实现的一个简单方法是使用类似
abstract class Piece {
    Color getColor() { ... }
    Point getPosition() { ... }

    abstract void doMove(...) { ... }
}

class Bishop extends Piece {
    void doMove(....) { ... }
}

// + other classes extending "Piece"

但请注意,这可能并不总是最好的方法,也可能并不总是足够的。特别是,您应该非常清楚 EngineBoardPiecePlayer 类如何交互以及它们的职责是什么。 (考虑一段时间后,您可能会得出结论,您还需要一个 Move 类...)。通常,检查移动是否有效比乍一看要复杂得多。您提到,对于 Bishop 移动,您检查目标位置是否有效,并且中间没有其他棋子。但是,如果此举导致自己的国王受阻,则该举措仍然无效。这只能通过“引擎”进行检查,而几乎无法通过工件本身进行检查。人们容易忘记的其他事情(并且涉及有关整个游戏状态的信息,因此很难由单个 Piece 处理)是 CastlingEn passant 移动。

国际象棋引擎的观点

对于国际象棋引擎,有几个要求使得一个好的、面向对象的方法特别困难。如果您的目的是编写一个高效的国际象棋引擎,那么您的棋盘很可能是一个 long 值数组,这些值通过按位运算进行操作....

(旁注:如果您将 Board 类设计为 接口(interface) ,如上所述,那么您仍然可以在用于引擎的这种高性能优化表示上保持一个漂亮的、高级的、面向对象的 View 我的经验法则:一开始总是将一切建模为界面。之后很容易让它变得更具体)

所以要看你要不要写
  • 一个不错的面向对象的国际象棋,适用于两个人类玩家,带有规则检查或
  • 国际象棋引擎

  • 您可能希望以不同的方式处理游戏设计的某些部分。

    编辑:当您寻找有关国际象棋(引擎)编程的信息时,您肯定会偶然发现这一点,但我想指出 https://www.chessprogramming.org/Main_Page 提供了很多背景信息。再说一遍:这不是真正的面向对象设计,而是更多关于国际象棋引擎的细节。

    关于java - 国际象棋引擎。可以将板对象引用传递给一块吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29717345/

    10-11 21:39