I am currently creating a chess game consisting of the following classes:
I was wondering if I should be using a Singleton pattern (With regards to the ChessBoard class) ? Currently I am not and I am passing the instance of the ChessBoard into the chess pieces movement functionality so that the piece can understand its surroundings. This is because of course moves are deemed legal depending on what spaces are occupied/empty on the board at any time.
Singletons are very rarely a good idea. I happen to have started a similar project recently so I will answer this from my current experience.
The way I've implemented it is by considering a chessboard a collection of Location
objects, where a location holds an X
-value, Y
-value and a Piece
object. Only relevant places are filled in where empty ones aren't even tracked.
You seem to be wondering if you should use a singleton for the single purpose of validation. There are many, many things you have to validate when a move is done: Can you move that way? Are you check? Is it en-passant? Is it a rochade? etc.
What you could do is create a bunch of validate methods that take as arguments a chessboard and the start- and endlocation. This way you have all information required to check if the move is valid. This does require the pieces to know their own properties: how can I move? What's my color?
When you have all this, you can implement the different validation logic to make a move.
Using a singleton will be rather nasty when you could just extract the validation and pass the chessboard around. It would also be much harder to test (and good testing is definitely something you want in a chessgame).
My setup looks like this:
Chessboard.CanMoveToLocation(int startX, int startY, int endX, int endY) {
// Call validators with local field chessboard and given location objects
}
Each validator will return a custom enum ValidationResult
to indicate if it's allowed or forbidden for this particular validator.
You'll have to make sure the validators are called in the correct order (returning false after checking if it's a valid move is not a good idea: he might have been rochading or slaying en-passant). Or you could ofcourse combine related validators.
Should you wish to take a look: my current (far from finished) implementation.