面向对象的国际象棋游戏devise

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

国际象棋游戏有以下类

  • 播放机
  • 广场
  • ChessGame

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

此外,ChessGame会主动创buildBoard和Player对象,然后分别创build正方形和块,然后开始模拟。 简而言之,这可能是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(); } 

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

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

 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 eg 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 {....}