国际象棋引擎。将板对象引用传递给一块是否可以?

时间:2015-04-18 12:28:10

标签: java chess

我正在创建一个国际象棋引擎。我有Piece接口,Rook,Bishop等实现这个类。我的板是Piece [] []数组。让我们说白人玩家想要移动他的主教。我将目的地的坐标和董事会参考传递给主教。主教检查,如果目的地在同一对角线上,那么它会询问董事会他的位置和目的地广场之间是否有任何碎片。从OOP的角度来看,这样做是否可以? 谢谢

3 个答案:

答案 0 :(得分:2)

它有点微妙。

OOP观点

从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"

但请注意,这可能并不总是最好的方法,也许并不总是足够的。特别是,您应该明确了解EngineBoardPiecePlayer课程的互动情况以及他们的互动情况责任是。 (在考虑了一段时间之后,你可能会得出结论,你还需要一个Move课......)。通常,检查移动是否有效比第一眼看上去更复杂。您提到,对于Bishop移动,您检查目标位置是否有效以及中间是否没有其他部分。但如果此举导致自己的国王被控制,此举仍然无效。这只能通过"引擎"来检查,而不是由作品本身检查。人们往往会忘记的其他事情(以及涉及整个游戏状态的信息,因而很难被单件处理)是CastlingEn passant移动。

国际象棋引擎观点

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

(旁注:如果您将Board类设计为界面,如上所述,那么您仍然可以保持一个漂亮的,高级的,面向对象的查看这个高度性能优化的表示,用于引擎本身。我的经验法则:始终将所有内容建模为一个界面。之后很容易使其变得更具体)< / p>


所以取决于你是否想写

  • 一个漂亮的,面向对象的国际象棋,适用于两个人类玩家,通过规则检查或
  • 国际象棋引擎

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


编辑:当您在寻找有关国际象棋(引擎)编程的信息时,您肯定会遇到这种情况,但我想指出https://www.chessprogramming.org/Main_Page提供了大量背景信息。再说一遍:这不是关于OO设计的,而是更多关于国际象棋引擎的细节。

答案 1 :(得分:1)

从OOP的角度来看,主教(车等......)应该能够说明他的法律转向是什么 - 也就是说,如果给定的领域在同一对角线上。此外,它可以告诉董事会它不能“跳过”其他部分(IIRC只有骑士可以做到这一点,所以骑士可以覆盖它)。

然后,再一次,没有任何一块可以移动到另一块相同颜色的场地上,也没有任何移动应该危及(检查)国王。应该通过GameController类(或封装该逻辑的一些底层类)来检查这些约束,因为它们适用于所有部分。

如果GameController检查目标字段是否为空,然后询问该部分是否可以移动到那里,则该部件本身不必知道您的电路板阵列,并且通用逻辑将集中在控制器中。

对不起我可怜的国际象棋词汇:)

答案 2 :(得分:1)

从设计的角度来看,您有两个(或许更多)选项需要考虑:

  1. 董事会是一种规则管理者,应该知道作品是如何行动的 - 有一个限制 - 董事会必须了解每个演员,因为国际象棋的类型有限,这不是问题。
  2. 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;
          }
     }
    
  3. 我会选择第二种选择。它更加OOP +它可以更灵活地存储件。在游戏类中,你可以使用方法作为参数,并传递任何扩展Piece类,Bishops,Knight等的东西,并且多态将为你完成工作。如果是第一个选项,您可能需要使用一些开关/案例。

    当然,你还需要为玩家,游戏状态等提供其他课程。

    要回答你的问题 - 可以通过委员会来解决问题。在我的命题中,它知道它所处的位置,所以它只需要知道什么是新的建议位置,以检查它是否不超过电路板尺寸并且对于其类型是合法的。由于游戏控制器检查碰撞,你实际上不需要董事会吗?