当前位置: 首页 > 知识库问答 >
问题:

象棋引擎。将board对象引用传递给工件可以吗?

邢新
2023-03-14

我正在创建一个象棋引擎。我有一个接口,Rook,Bishop等。实现了这个类。我的电路板是一块[]阵列。假设白人球员想移动他的主教。我将目标的坐标和棋盘引用传递给bishop。Bishop检查,如果目的地在同一对角线上,那么它会询问董事会,在他的位置和目的地方块之间是否没有任何碎片。从面向对象的角度来看,这样做可以吗?非常感谢。

共有3个答案

赵宏达
2023-03-14

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

>

  • 棋盘是一种规则管理器,它应该知道棋子可以如何操作-有一个限制-棋盘必须知道每个参与者,因为国际象棋的类型数量有限,这不是问题
  • 电路板只是工件的一个占位符/坐标系。使用这种方法,您可以通过为Piece创建抽象类(或接口,如您所写,但片段之间会有许多公共属性,因此抽象类对我来说更合适)来节省大量代码,并且每种类型的片段都将扩展/实现它。例子:

    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;
          }
     }
    

    我会选择第二个选项。它更面向对象,它允许存储碎片的更大灵活性。在游戏类中,您可以使用将Piece作为参数并传递任何扩展Piece类、Bishops、Knight等的方法,多态性将为您完成这项工作。在第一个选项的情况下,您可能需要使用一些开关/大小写。

    当然,你还需要为玩家、游戏状态等设置其他类。

    为了回答你的问题,可以一块一块地传下去。在我的提议中,这篇文章知道它的位置,所以它只需要知道新提议的位置是什么,以检查它是否没有超过董事会的大小,以及它的类型是否合法。既然游戏控制器检查碰撞,你实际上不需要棋盘?

  • 养慈
    2023-03-14

    从面向对象的角度来看,bishop(rook等…)应该能够说什么是他合法的转折点——也就是说,如果给定的场在同一对角线上。它还可以告诉董事会,它不能“跳过”其他部分(IIRC只有骑士可以这样做,所以骑士可以覆盖这一点)。

    再说一次,没有一个棋子可以移动到另一个有相同颜色棋子的领域,也没有任何移动应该危及(检查)国王。这些约束应该由GameController类(或封装该逻辑的一些底层类)检查,因为它们适用于所有部分。

    如果GameController检查目标区域是否为空,然后询问棋子是否可以移动到那里,棋子本身就不必知道你的棋盘阵列,常见的逻辑将集中在控制器中。

    对不起,我的象棋词汇量很差:)

    郑松
    2023-03-14

    这有点微妙。

    从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点:给棋盘的棋盘是可变的还是“只读的”?人们可以想象一个恶意主教类,当它被赋予棋盘时,通过把自己放在国王的位置来暗杀对手的国王。

    从非常高层次、抽象的面向对象的角度来看,人们可能会质疑一个片段是否应该具有任何智能。一块塑料是一块哑巴。它对国际象棋规则一无所知。你(玩家)可以将棋子放在任何地方,要么遵守,要么无视国际象棋规则。因此,遵守甚至检查任何规则肯定不是这件作品的工作。可以说,遵守规则是对玩家的期望,强制遵守规则是高级智能(可能是一些“ChessGameManager”类)的工作。

    一个简单的方法似乎(!)用于OO国际象棋实现的类是

    abstract class Piece {
        Color getColor() { ... }
        Point getPosition() { ... }
    
        abstract void doMove(...) { ... }
    }
    
    class Bishop extends Piece {
        void doMove(....) { ... }   
    }
    
    // + other classes extending "Piece"
    

    但请注意,这可能并不总是最好的方法,也可能并不总是足够的。特别是,您应该非常清楚您的引擎、您的板、您的工件和您的播放器类是如何交互的,以及它们的职责是什么。(思考了一会儿后,你可能会得出结论,你还需要一个移动类…)。一般来说,检查一个动作是否有效要比乍一看复杂得多。您提到,对于Bishop移动,您要检查目标位置是否有效,并且中间没有其他棋子。但是,如果这一举动导致自己的国王受到约束,那么这一举动仍然无效。这只能通过“引擎”进行检查,而很难通过工件本身进行检查。人们往往忘记的其他事情(涉及整个游戏状态的信息,因此很难用单个棋子来处理)是投掷或顺便移动。

    对于象棋引擎,有几个要求使得一个好的、面向对象的方法特别困难。如果您打算编写一个高效的国际象棋引擎,那么您的棋盘很可能是一个由按位操作的长值数组。。。。

    (附带说明:如果您按照上面的建议将Board类设计为接口,那么您仍然可以在这个用于引擎本身的高度性能优化的表示上保留一个漂亮的、高级的、面向对象的视图。我的经验法则:一开始总是将所有内容建模为接口。之后很容易使其更加具体)

    所以取决于你是否想写

    • 一个很好的面向对象的国际象棋为两个人类玩家,规则检查或
    • 国际象棋引擎

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

    编辑:当你寻找有关国际象棋(引擎)编程的信息时,你肯定会遇到这个问题,但我想指出一点https://www.chessprogramming.org/Main_Page提供了大量的背景信息。再次强调:这实际上不是关于OO设计,而是关于国际象棋引擎的细节。

     类似资料:
    • 问题内容: 我正在尝试将自定义对象从活动传递到片段。我选择实现可序列化并使用以下对象传递对象: 我遇到了错误 尝试在空对象引用上调用虚拟方法 当我尝试将我的对象设置为与活动传递的参数相等时。 这是我的对象 接下来是我要传递的活动,我最终希望传递所有四个对象,但是现在我想至少获得一个成功传递的对象。 然后是引发Null Pointer Exception的片段,我已经用“->”包com.cs246.

    • 问题内容: 我正在尝试将自定义对象从活动传递到片段。我选择实现可序列化并使用以下对象传递对象: 我遇到了错误 尝试在空对象引用上调用虚拟方法 当我尝试将我的对象设置为与活动传递的参数相等时。 这是我的对象 接下来是我要传递的活动,我最终希望传递所有四个对象,但是现在我想至少获得一个成功传递的对象。 然后是引发Null Pointer Exception的片段,我已经用“->”包com.cs246.

    • 下面您将找到应该调用的函数,而不是: 我可以为这些自定义类型创建工厂,并根据值生成类型,而不是传递给的类型,或者传递一个字符串化的对象(对象/数组、更多的对象/数组)。但我想知道(尤其是后者,它让我发冷)是否真的有必要。文档只提到这个函数,作为向区块链提交事务的一种方式。 我应该用我的工厂解决方案吗?是否有另一个函数,我可以使用它来提交使用类型的事务?或者这不是我应该构造我的链码的方式,我应该考虑

    • 问题内容: 是否可以通过Java通过引用传递对象 就像在C#中一样 问题答案: 不,这在Java中是不可能的。 在Java中,方法的所有参数均按值传递。注意非原始型的的变量,它们是对对象的引用,也由值来传递:在这种情况下, 参考 是 由值来传递 。请注意,按值传递引用与按引用传递不同。

    • 问题内容: 考虑一个非fx的现有应用程序,将其称为。 公开一个对象,该对象又公开了一些属性。也接受这些属性的侦听器。 我的问题是关于 将 JavaFx gui 添加 到此类应用程序。将明显延长,将需要一个参考对象。 在寻找将非String参数传递给我的解决方案时,我发现了几种不同的方法: 静态方法:例如,已初始化对in 的静态引用。在这里可以看到使用静电的一个示例。 JavaFx 9方法:如此处所

    • 问题内容: 我在php中有对象,每个对象代表一个“项目”以及与之相关的所有信息。 当用户浏览页面时,这些对象应传递给javascript。理想情况下,镜像相同的结构,因此我可以使用Raphael在我的网站上将每个项目及其信息显示为单独的形状。 但是,如何将对象从php转换为javascript? 问题答案: 您可以将PHP对象转换为数组,然后使用JSON函数对其进行编码。之后,从JavaScrip