我正在创建一个国际象棋引擎。我有Piece接口,Rook,Bishop等实现这个类。我的板是Piece [] []数组。让我们说白人玩家想要移动他的主教。我将目的地的坐标和董事会参考传递给主教。主教检查,如果目的地在同一对角线上,那么它会询问董事会他的位置和目的地广场之间是否有任何碎片。从OOP的角度来看,这样做是否可以? 谢谢
答案 0 :(得分:2)
它有点微妙。
从OOP的角度来看,人们可能会质疑董事会是否应该首先成为Piece[][]
阵列。这里一个漂亮,干净,面向对象的设计可能会涉及到像
interface Board {
Piece get(int r, int c);
// Should this be here? See below...
void set(int r, int c, Piece p);
}
然后,一个至关重要的问题是:主教会选择自己和#34;在给定董事会的目标位置?或者,专注于OOP点:是否给予可变这一块的板或者它是否是#34;只读"?人们可以想象一个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"
但请注意,这可能并不总是最好的方法,也许并不总是足够的。特别是,您应该明确了解Engine
,Board
,Piece
和Player
课程的互动情况以及他们的互动情况责任是。 (在考虑了一段时间之后,你可能会得出结论,你还需要一个Move
课......)。通常,检查移动是否有效远比第一眼看上去更复杂。您提到,对于Bishop移动,您检查目标位置是否有效以及中间是否没有其他部分。但如果此举导致自己的国王被控制,此举仍然无效。这只能通过"引擎"来检查,而不是由作品本身检查。人们往往会忘记的其他事情(以及涉及整个游戏状态的信息,因而很难被单件处理)是Castling或En passant移动。
对于国际象棋引擎,有一些要求使得面向对象的方法变得特别困难。如果您的目的是编写一个有效的国际象棋引擎,那么您的电路板很可能是一个long
值的数组,这些值通过按位运算进行操作....
(旁注:如果您将Board
类设计为界面,如上所述,那么您仍然可以保持一个漂亮的,高级的,面向对象的查看这个高度性能优化的表示,用于引擎本身。我的经验法则:始终将所有内容建模为一个界面。之后很容易使其变得更具体)< / p>
所以取决于你是否想写
您可能希望以不同方式处理游戏设计的某些部分。
答案 1 :(得分:1)
从OOP的角度来看,主教(车等......)应该能够说明他的法律转向是什么 - 也就是说,如果给定的领域在同一对角线上。此外,它可以告诉董事会它不能“跳过”其他部分(IIRC只有骑士可以做到这一点,所以骑士可以覆盖它)。
然后,再一次,没有任何一块可以移动到另一块相同颜色的场地上,也没有任何移动应该危及(检查)国王。应该通过GameController类(或封装该逻辑的一些底层类)来检查这些约束,因为它们适用于所有部分。
如果GameController检查目标字段是否为空,然后询问该部分是否可以移动到那里,则该部件本身不必知道您的电路板阵列,并且通用逻辑将集中在控制器中。
对不起我可怜的国际象棋词汇:)
答案 2 :(得分:1)
从设计的角度来看,您有两个(或许更多)选项需要考虑:
Board只是一个占位符/坐标系统。使用这种方法,您可以通过使用抽象类(或接口,就像您编写的那样,但是片段之间会有许多共同的属性,因此抽象类看起来对我来说更好)来节省大量代码,并且每种类型的片段都会扩展/实现它。例如:
public abstract class Piece
{
private int row;
private int column; // or other method to store position
private boolean isBlack // or enum for type
// contructor, getters, setters etc...
public abstract boolean canMove(int newX, int newY);
/* some other abstract methods if you need */
}
以后
public class Bishop extends Piece
{
@Override
public boolean canMove(int newX, int newY)
{
if( /*check if new points aare on diagonal */)
return true;
else
return false;
}
}
public class Knight extends Piece
{
@Override
public boolean canMove(int newX, int newY)
{
if( /*check if L shaped with prev pos */)
return true;
else
return false;
}
}
我会选择第二种选择。它更加OOP +它可以更灵活地存储件。在游戏类中,你可以使用方法作为参数,并传递任何扩展Piece类,Bishops,Knight等的东西,并且多态将为你完成工作。如果是第一个选项,您可能需要使用一些开关/案例。
当然,你还需要为玩家,游戏状态等提供其他课程。
要回答你的问题 - 可以通过委员会来解决问题。在我的命题中,它知道它所处的位置,所以它只需要知道什么是新的建议位置,以检查它是否不超过电路板尺寸并且对于其类型是合法的。由于游戏控制器检查碰撞,你实际上不需要董事会吗?