面向对象的国际象棋游戏设计

我想了解如何以面向对象的方式进行设计和思考,并希望从社区获得关于此主题的一些反馈。 以下是我希望以面向对象方式设计的国际象棋游戏的一个例子。 这是一个非常广泛的设计,我在这个阶段的重点只是确定谁负责什么消息以及对象如何相互交互来模拟游戏。 请指出是否存在设计不好(高耦合,不良内聚等)的元素以及如何改进它们。

国际象棋游戏有以下类

  • 播放机
  • 广场
  • ChessGame
  • 董事会由正方形组成,因此董事会可以负责创建和管理Square对象。 每件作品也放在一个正方形上,因此每件作品也有一个参考它所在的正方形。 (这有道理吗?)。 每件作品都有责任将自己从一个广场移到另一个广场。 玩家类拥有对他拥有的所有作品的引用,并且也负责他们的创作(玩家是否应该创作作品?)。 玩家有一个方法takeTurn,它依次调用一个方法movePiece,该方法属于片段Class,它将片段的位置从其当前位置改变到另一个位置。 现在我很困惑董事会的职责究竟是什么。 我认为需要确定游戏的当前状态,并知道游戏何时结束。 但是,当一块改变它的位置板应该如何更新? 它是否应该维持一个单独的存在棋子的方块阵列,并且随着棋子的移动而更新?

    另外,ChessGame主要创建棋盘和玩家对象,然后分别创建正方形和棋子并开始模拟。 简而言之,这可能是ChessGame中的代码可能的样子

    Player p1 =new Player();
    Player p2 = new Player();
    
    Board b = new Board();
    
    while(b.isGameOver())
    {
      p1.takeTurn(); // calls movePiece on the Piece object
      p2.takeTurn();
    
    }
    

    我不清楚董事会的状态将如何更新。 应该有一个参考董事会? 责任在哪里呢? 谁拥有什么参考? 请帮助我提供您的意见,并指出此设计中的问题。 我故意没有专注于任何算法或玩游戏的更多细节,因为我只对设计方面感兴趣。 我希望这个社区能提供有价值的见解。


    我实际上只是写了一个完整的C#实现棋盘,棋子,规则等。这里大概是我如何建模的(由于我不想从你的编码中获得所有的乐趣,因此删除了实际的实现):

    public enum PieceType {
        None, Pawn, Knight, Bishop, Rook, Queen, King
    }
    
    public enum PieceColor {
        White, Black
    }
    
    public struct Piece {
        public PieceType Type { get; set; }
        public PieceColor Color { get; set; }
    }
    
    public struct Square {
        public int X { get; set; }
        public int Y { get; set; }
    
        public static implicit operator Square(string str) {
            // Parses strings like "a1" so you can write "a1" in code instead
            // of new Square(0, 0)
        }
    }
    
    public class Board {
        private Piece[,] board;
    
        public Piece this[Square square] { get; set; }
    
        public Board Clone() { ... }
    }
    
    public class Move {
        public Square From { get; }
        public Square To { get; }
        public Piece PieceMoved { get; }
        public Piece PieceCaptured { get; }
        public PieceType Promotion { get; }
        public string AlgebraicNotation { get; }
    }
    
    public class Game {
        public Board Board { get; }
        public IList<Move> Movelist { get; }
        public PieceType Turn { get; set; }
        public Square? DoublePawnPush { get; set; } // Used for tracking valid en passant captures
        public int Halfmoves { get; set; }
    
        public bool CanWhiteCastleA { get; set; }
        public bool CanWhiteCastleH { get; set; }
        public bool CanBlackCastleA { get; set; }
        public bool CanBlackCastleH { get; set; }
    }
    
    public interface IGameRules {
        // ....
    }
    

    基本的想法是游戏/委员会/等存储游戏的状态。 你可以操纵它们来设置一个位置,如果这就是你想要的。 我有一个实现我的IGameRules接口的类,它负责:

  • 确定什么样的动作是有效的,包括castling和en passant。
  • 确定具体的移动是否有效。
  • 确定玩家是否处于支票/将军/僵持状态。
  • 执行移动。
  • 将规则与游戏/棋盘类分开也意味着你可以相对容易地实现变体。 规则接口的所有方法都带有一个Game对象,可以检查它们以确定哪些移动是有效的。

    请注意,我不会在Game上存储玩家信息。 我有一个单独的班级Table ,负责存储游戏元数据,比如谁在玩游戏,何时发生游戏等等。

    编辑:请注意,这个答案的目的并不是真的给你模板代码,你可以填写 - 我的代码实际上有更多的信息存储在每个项目,更多的方法等。目的是引导你朝着你正试图达到的目标。


    这是我的想法,对于一个相当基本的国际象棋游戏:

    class GameBoard {
     IPiece config[8][8];  
    
     init {
      createAndPlacePieces("Black");
      createAndPlacePieces("White");
      setTurn("Black");
    
     }
    
     createAndPlacePieces(color) {
       //generate pieces using a factory method
       //for e.g. config[1][0] = PieceFactory("Pawn",color);
     }
    
     setTurn(color) {
       turn = color;
     }
    
     move(fromPt,toPt) {
      if(getPcAt(fromPt).color == turn) {
        toPtHasOppositeColorPiece = getPcAt(toPt) != null && getPcAt(toPt).color != turn;
        possiblePath = getPcAt(fromPt).generatePossiblePath(fromPt,toPt,toPtHasOppositeColorPiece);
       if(possiblePath != NULL) {
          traversePath();
          changeTurn();
       }
      }
     } 
    
    }
    
    Interface IPiece {
      function generatePossiblePath(fromPt,toPt,toPtHasEnemy);
    }
    
    class PawnPiece implements IPiece{
      function generatePossiblePath(fromPt,toPt,toPtHasEnemy) {
        return an array of points if such a path is possible
        else return null;
      }
    }
    
    class ElephantPiece implements IPiece {....}
    
    链接地址: http://www.djcxy.com/p/51037.html

    上一篇: Object Oriented Design for a Chess game

    下一篇: Is it bad OOP practice to have objects reference each other?