[ACCEPTED]-Object Oriented Design for a Chess game-oop

Accepted answer
Score: 54

I actually just wrote a full C# implementation 24 of a chess board, pieces, rules, etc. Here's 23 roughly how I modeled it (actual implementation 22 removed since I don't want to take all the 21 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 20 that Game/Board/etc simply store the state 19 of the game. You can manipulate them to 18 e.g. set up a position, if that's what you 17 want. I have a class that implements my 16 IGameRules interface that is responsible 15 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 14 classes also means you can implement variants 13 relatively easily. All methods of the rules 12 interface take a Game object which they can 11 inspect to determine which moves are valid.

Note 10 that I do not store player information on 9 Game. I have a separate class Table that is responsible 8 for storing game metadata such as who was 7 playing, when the game took place, etc.

EDIT: Note 6 that the purpose of this answer isn't really 5 to give you template code you can fill out 4 -- my code actually has a bit more information 3 stored on each item, more methods, etc. The 2 purpose is to guide you towards the goal 1 you're trying to achieve.

Score: 6

Here is my idea, for a fairly basic chess 1 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 {....}
Score: 0

I recently created a chess program in PHP 8 (website click here, source click here) and I made it object oriented. Here 7 are the classes I used.

  • ChessRulebook (static) - I put all my generate_legal_moves() code in here. That method is given a board, whose turn it is, and some variables to set the level of detail of the output, and it generates all the legal moves for that position. It returns a list of ChessMoves.
  • ChessMove - Stores everything needed to create algebraic notation, including starting square, ending square, color, piece type, capture, check, checkmate, promotion piece type, and en passant. Optional additional variables include disambiguation (for moves like Rae4), castling, and board.
  • ChessBoard - Stores the same information as a Chess FEN, including an 8x8 array representing the squares and storing the ChessPieces, whose turn it is, en passant target square, castling rights, halfmove clock, and fullmove clock.
  • ChessPiece - Stores piece type, color, square, and piece value (for example, pawn = 1, knight = 3, rook = 5, etc.)
  • ChessSquare - Stores the rank and file, as ints.

I am currently trying 6 to turn this code into a chess A.I., so 5 it needs to be FAST. I've optimized the 4 generate_legal_moves() function from 1500ms to 8ms, and am still 3 working on it. Lessons I learned from that 2 are...

  • Do not store an entire ChessBoard in every ChessMove by default. Only store the board in the move when needed.
  • Use primitive types such as int when possible. That is why ChessSquare stores rank and file as int, rather than also storing an alphanumeric string with human readable chess square notation such as "a4".
  • The program creates tens of thousands of ChessSquares when searching the move tree. I will probably refactor the program to not use ChessSquares, which should give a speed boost.
  • Do not calculate any unnecessary variables in your classes. Originally, calculating the FEN in each of my ChessBoards was really killing the program's speed. I had to find this out with a profiler.

I know this is old, but hopefully 1 it helps somebody. Good luck!

More Related questions