How can you design a java chess game using object oriented principles?
I would like to know if my approach is correct and how it could be improved? Also, is there a way to get rid of the relation between the Piece and the Board? At the moment, I am storing the position of the piece both in the piece and on the board. Is there some way to change that?
I have considered a Game to contain an instance of the Board and the two Players (one black, one white). The pieces contain a connection to the Board, because in order to determine if they are valid, we need to know the relationship to other pieces.
Could I use design patterns for this? Should I use interfaces instead of the super class?
Game.java
public class Game {
private Board board = new Board();
private Player white;
private Player black;
public Game() {
super();
}
public void setColorWhite(Player player) {
this.white = player;
}
public void setColorBlack(Player player) {
this.black = player;
}
public Board getBoard() {
return board;
}
public void setBoard(Board board) {
this.board = board;
}
public Player getWhite() {
return white;
}
public void setWhite(Player white) {
this.white = white;
}
public Player getBlack() {
return black;
}
public void setBlack(Player black) {
this.black = black;
}
public boolean initializeBoardGivenPlayers() {
if(this.black == null || this.white == null)
return false;
this.board = new Board();
for(int i=0; iboard.getSpot(black.getPieces().get(i).getX(), black.getPieces().get(i).getY()).occupySpot(black.getPieces().get(i));
}
return true;
}
}
Player.java
public class Player {
public final int PAWNS = 8;
public final int BISHOPS = 2;
public final int ROOKS = 2;
public boolean white;
private Listpieces = new ArrayList<>();
public Player(boolean white) {
super();
this.white = white;
}
public ListgetPieces() { return pieces;
}
public void initializePieces(){
if(this.white == true){
for(int i=0; ipieces.add(new Pawn(true,i,2));
}
pieces.add(new Rook(true, 0, 0));
pieces.add(new Rook(true, 7, 0));
pieces.add(new Bishop(true, 2, 0));
pieces.add(new Bishop(true, 5, 0));
pieces.add(new Knight(true, 1, 0));
pieces.add(new Knight(true, 6, 0));
pieces.add(new Queen(true, 3, 0));
pieces.add(new King(true, 4, 0));
}
else{
for(int i=0; ipieces.add(new Pawn(true,i,6));
}
pieces.add(new Rook(true, 0, 7));
pieces.add(new Rook(true, 7, 7));
pieces.add(new Bishop(true, 2, 7));
pieces.add(new Bishop(true, 5, 7));
pieces.add(new Knight(true, 1, 7));
pieces.add(new Knight(true, 6, 7));
pieces.add(new Queen(true, 3, 7));
pieces.add(new King(true, 4, 7));
}
}
}
Board.java
public class Board {
private Spot[][] spots = new Spot[8][8];
public Board() {
super();
for(int i=0; ifor(int j=0; j this.spots[i][j] = new Spot(i, j);
}
}
}
public Spot getSpot(int x, int y) {
return spots[x][y];
}
}
Spot.java
public class Spot {
int x;
int y;
Piece piece;
public Spot(int x, int y) {
super();
this.x = x;
this.y = y;
piece = null;
}
public void occupySpot(Piece piece){
//if piece already here, delete it, i. e. set it dead
if(this.piece != null)
this.piece.setAvailable(false);
//place piece here
this.piece = piece;
}
public boolean isOccupied() {
if(piece != null)
return true;
return false;
}
public Piece releaseSpot() {
Piece releasedPiece = this.piece;
this.piece = null;
return releasedPiece;
}
}
Piece.java
public class Piece {
private boolean available;
private int x;
private int y;
public Piece(boolean available, int x, int y) {
super();
this.available = available;
this.x = x;
this.y = y;
}
public boolean isAvailable() {
return available;
}
public void setAvailable(boolean available) {
this.available = available;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public boolean isValid(Board board, int fromX, int fromY, int toX, int toY){
if(toX == fromX && toY == fromY)
return false; //cannot move nothing
if(toX < 0> 7 || fromX < 0> 7 || toY < 0> 7 || fromY <0> 7)
return false;
return true;
}
}
King.java
public class King extends Piece{
public King(boolean available, int x, int y) {
super(available, x, y);
// TODO Auto-generated constructor stub
}
@Override
public boolean isValid(Board board, int fromX, int fromY, int toX, int toY) {
if(super.isValid(board, fromX, fromY, toX, toY) == false)
return false;
if(Math.sqrt(Math.pow(Math.abs((toX - fromX)),2)) + Math.pow(Math.abs((toY - fromY)), 2) != Math.sqrt(2)){
return false;
}
return false;
}
}
Knight.java
public class Knight extends Piece{
public Knight(boolean available, int x, int y) {
super(available, x, y);
}
@Override
public boolean isValid(Board board, int fromX, int fromY, int toX, int toY) {
if(super.isValid(board, fromX, fromY, toX, toY) == false)
return false;
if(toX != fromX - 1 && toX != fromX + 1 && toX != fromX + 2 && toX != fromX - 2)
return false;
if(toY != fromY - 2 && toY != fromY + 2 && toY != fromY - 1 && toY != fromY + 1)
return false;
return true;
}
}
Bishop.java
public class Bishop extends Piece{
public Bishop(boolean available, int x, int y) {
super(available, x, y);
// TODO Auto-generated constructor stub
}
@Override
public boolean isValid(Board board, int fromX, int fromY, int toX, int toY) {
if(super.isValid(board, fromX, fromY, toX, toY) == false)
return false;
if(toX - fromX == toY - fromY)
return true;
return false;
}
}
Rook.java
public class Rook extends Piece{
public Rook(boolean available, int x, int y) {
super(available, x, y);
// TODO Auto-generated constructor stub
}
@Override
public boolean isValid(Board board, int fromX, int fromY, int toX, int toY) {
if(super.isValid(board, fromX, fromY, toX, toY) == false)
return false;
if(toX == fromX)
return true;
if(toY == fromY)
return true;
return false;
}
}
Queen.java
public class Queen extends Piece{
public Queen(boolean available, int x, int y) {
super(available, x, y);
}
@Override
public boolean isValid(Board board, int fromX, int fromY, int toX, int toY) {
if(super.isValid(board, fromX, fromY, toX, toY) == false)
return false;
//diagonal
if(toX - fromX == toY - fromY)
return true;
if(toX == fromX)
return true;
if(toY == fromY)
return true;
return false;
}
}
Without offering a deep code review (as I don't have a lot of specific Java knowledge), let's look at what a full "move" entails in java chess game:
Player chooses piece to move.
Piece makes legal move according to its own move rules.
In addition to purely move-based rules, there's also capture logic, so a bishop cannot move from a1-h8 if there's a piece sitting on c3.
If the player was previous under check and the move does not remove the check, it must be undone.
If the move exposes a check, it must be undone / disallowed.
If a player captures a piece, remove the piece (including en passant!)
If the piece is a pawn reaching the back rank, promote it.
If the move is a castling, set the new position of the rook accordingly. But a king and rook can only castle if they haven't moved, so you need to keep track of that. And if the king moves through a check to the castle, that's disallowed, too.
If the move results in a stalemate or checkmate, the game is over.
There may be more even (?). This is a complicated step, more than just counting and subsequently occupying spaces.
So my general intuition would be to just call:
Code Review
Design a chess game using object-oriented principles
Asked 7 years, 3 months ago
Modified 3 years, 6 months ago
Viewed 222k times
76
47
I would like to know if my approach is correct and how it could be improved? Also, is there a way to get rid of the relation between the Piece and the Board? At the moment, I am storing the position of the piece both in the piece and on the board. Is there some way to change that?
I have considered a Game to contain an instance of the Board and the two Players (one black, one white). The pieces contain a connection to the Board, because in order to determine if they are valid, we need to know the relationship to other pieces.
Could I use design patterns for this? Should I use interfaces instead of the super class?
Game.java
public class Game {
private Board board = new Board();
private Player white;
private Player black;
public Game() {
super();
}
public void setColorWhite(Player player) {
this.white = player;
}
public void setColorBlack(Player player) {
this.black = player;
}
public Board getBoard() {
return board;
}
public void setBoard(Board board) {
this.board = board;
}
public Player getWhite() {
return white;
}
public void setWhite(Player white) {
this.white = white;
}
public Player getBlack() {
return black;
}
public void setBlack(Player black) {
this.black = black;
}
public boolean initializeBoardGivenPlayers() {
if(this.black == null || this.white == null)
return false;
this.board = new Board();
for(int i=0; i pieces = new ArrayList<>();
public Player(boolean white) {
super();
this.white = white;
}
public List getPieces() {
return pieces;
}
public void initializePieces(){
if(this.white == true){
for(int i=0; i 7 || fromX < 0> 7 || toY < 0> 7 || fromY 7)
return false;
return true;
}
}
King.java
public class King extends Piece{
public King(boolean available, int x, int y) {
super(available, x, y);
// TODO Auto-generated constructor stub
}
@Override
public boolean isValid(Board board, int fromX, int fromY, int toX, int toY) {
if(super.isValid(board, fromX, fromY, toX, toY) == false)
return false;
if(Math.sqrt(Math.pow(Math.abs((toX - fromX)),2)) + Math.pow(Math.abs((toY - fromY)), 2) != Math.sqrt(2)){
return false;
}
return false;
}
}
Knight.java
public class Knight extends Piece{
public Knight(boolean available, int x, int y) {
super(available, x, y);
}
@Override
public boolean isValid(Board board, int fromX, int fromY, int toX, int toY) {
if(super.isValid(board, fromX, fromY, toX, toY) == false)
return false;
if(toX != fromX - 1 && toX != fromX + 1 && toX != fromX + 2 && toX != fromX - 2)
return false;
if(toY != fromY - 2 && toY != fromY + 2 && toY != fromY - 1 && toY != fromY + 1)
return false;
return true;
}
}
Bishop.java
public class Bishop extends Piece{
public Bishop(boolean available, int x, int y) {
super(available, x, y);
// TODO Auto-generated constructor stub
}
@Override
public boolean isValid(Board board, int fromX, int fromY, int toX, int toY) {
if(super.isValid(board, fromX, fromY, toX, toY) == false)
return false;
if(toX - fromX == toY - fromY)
return true;
return false;
}
}
Rook.java
public class Rook extends Piece{
public Rook(boolean available, int x, int y) {
super(available, x, y);
// TODO Auto-generated constructor stub
}
@Override
public boolean isValid(Board board, int fromX, int fromY, int toX, int toY) {
if(super.isValid(board, fromX, fromY, toX, toY) == false)
return false;
if(toX == fromX)
return true;
if(toY == fromY)
return true;
return false;
}
}
Queen.java
public class Queen extends Piece{
public Queen(boolean available, int x, int y) {
super(available, x, y);
}
@Override
public boolean isValid(Board board, int fromX, int fromY, int toX, int toY) {
if(super.isValid(board, fromX, fromY, toX, toY) == false)
return false;
//diagonal
if(toX - fromX == toY - fromY)
return true;
if(toX == fromX)
return true;
if(toY == fromY)
return true;
return false;
}
}
java
object-oriented
design-patterns
game
chess
Share
Improve this question
Follow
edited Dec 5, 2014 at 20:32
200_success
141k2121 gold badges183183 silver badges466466 bronze badges
asked Dec 5, 2014 at 18:05
SummerCode
86311 gold badge99 silver badges88 bronze badges
Where is the Pawn.java file ? I did not find that. –
user92331
Dec 15, 2015 at 12:36
1
@Nitin Kumar i have indeed forgotten to write it down apparently, but i no longer have the project due to some hardware issues... –
SummerCode
Dec 15, 2015 at 13:15
1
bishop moves only in diagonal shape if it is in white place means its only moves in white diagonally otherwise moves in black –
user115324
Aug 18, 2016 at 9:56
Add a comment
6 Answers
31
Without offering a deep code review (as I don't have a lot of specific Java knowledge), let's look at what a full "move" entails in chess:
Player chooses a piece to move.
Piece makes legal moves according to its own move rules.
In addition to purely move-based rules, there's also capture logic, so a bishop cannot move from a1-h8 if there's a piece sitting on c3.
If the player was previous under check and the move does not remove the check, it must be undone.
If the move exposes a check, it must be undone / disallowed.
If a player captures a piece, remove the piece (including en passant!)
If the piece is a pawn reaching the back rank, promote it.
If the move is a castling, set the new position of the rook accordingly. But a king and rook can only castle if they haven't moved, so you need to keep track of that. And if the king moves through a check to the castle, that's disallowed, too.
If the move results in a stalemate or checkmate, the game is over.
There may be more even (?). This is a complicated step, more than just counting and subsequently occupying spaces.
So my general intuition would be to just call:
Game.move(currentSpot, NewSpot);
And the move method would contain all the code to validate the steps above:
Check Piece.isValidMove(currentSpot, newSpot); - probably need castling logic here since king moves more than 1 space and rook jumps the king)
Check Player.isChecked() (which is just sugar for Player.Pieces["King"].CanBeCaptured() - more fun logic here!)
Check if newSpot contains a piece and if so, newSpot.Piece.Remove();
Build some logic to call Piece.CheckEnPassant() (Piece is pawn, first move, 2 steps, past an enemy pawn who moved into capturing position on previous move - have fun with that!)
Piece.CheckPromote() (Piece is pawn, move ends on opposing player's back rank)
Check if Game.isOver(), which checks Game.isStaleMate() and Game.isCheckMate().
Your Board class is highly anemic, you're only using it in your code as a proxy object for the array of spots. You might as well just create a Board as an array of Spots in Game. In either case, you can already remove it from all your piece logic since all your logic is entirely predicated on the Xs and Ys you're passing in.
UPDATE
I would remove all your position properties from the piece. You're only using it as a proxy to figure out what spot the piece occupies during initialization. Instead, remove Player.initializePieces() and just initialize the Board with the pieces in the right spot (Board.Spot.Piece = King, etc.) and then let players choose a color.