Object Oriented Design for a Chess game [closed]
Solution 1:
I actually just wrote a full C# implementation of a chess board, pieces, rules, etc. Here's roughly how I modeled it (actual implementation removed since I don't want to take all the fun out of your coding):
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 {
// ....
}
The basic idea is that Game/Board/etc simply store the state of the game. You can manipulate them to e.g. set up a position, if that's what you want. I have a class that implements my IGameRules interface that is responsible for:
- Determining what moves are valid, including castling and en passant.
- Determining if a specific move is valid.
- Determining when players are in check/checkmate/stalemate.
- Executing moves.
Separating the rules from the game/board classes also means you can implement variants relatively easily. All methods of the rules interface take a Game
object which they can inspect to determine which moves are valid.
Note that I do not store player information on Game
. I have a separate class Table
that is responsible for storing game metadata such as who was playing, when the game took place, etc.
EDIT: Note that the purpose of this answer isn't really to give you template code you can fill out -- my code actually has a bit more information stored on each item, more methods, etc. The purpose is to guide you towards the goal you're trying to achieve.
Solution 2:
Here is my idea, for a fairly basic chess game :
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 {....}