我试图了解如何以面向对象的方式进行设计和思考,并希望从社区获得有关此主题的一些反馈.以下是我希望以OO方式设计的国际象棋游戏的示例.这是一个非常广泛的设计,我在这个阶段的重点只是确定谁负责什么消息以及对象如何相互交互来模拟游戏.请指出是否有不良设计元素(高耦合,内聚力差等)以及如何改进它们.
国际象棋游戏有以下几类
董事会由正方形组成,因此董事会可以负责创建和管理Square对象.每件作品也都放在一个正方形上,因此每件作品都可以参考它所在的正方形.(这有意义吗?).然后每件作品都有责任将自己从一个方格移动到另一个方格.Player类拥有对他拥有的所有作品的引用,并且还负责创建它们(玩家应该创建Pieces吗?).播放器有一个方法takeTurn,后者又调用一个方法movePiece,它属于片段Class,它将片段的位置从当前位置改变到另一个位置.现在我对Board类必须负责的内容感到困惑.我认为需要确定游戏的当前状态并知道游戏何时结束.但当一件作品发生变化时 位置如何更新电路板?它应该保持一个单独的正方形数组,其中存在碎片并随着碎片的移动而得到更新吗?
此外,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();
}
Run Code Online (Sandbox Code Playgroud)
我不清楚董事会的状态将如何更新.应该是否有参考板?责任在哪里?谁持有什么参考?请帮助我提供您的输入并指出此设计中的问题.我故意不关注任何算法或游戏的进一步细节,因为我只对设计方面感兴趣.我希望这个社区可以提供有价值的见解.
cdh*_*wie 54
我实际上只是编写了一个完整的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 {
// ....
}
Run Code Online (Sandbox Code Playgroud)
基本的想法是Game/Board/etc只是存储游戏的状态.你可以操纵它们,例如设置一个位置,如果这是你想要的.我有一个实现我的IGameRules接口的类,负责:
将规则与游戏/板类分开也意味着您可以相对容易地实现变体.规则接口的所有方法都采用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 {....}
Run Code Online (Sandbox Code Playgroud)