I have written code for making a Chess Validator, which will validate the moves of a chess game. There is a Main class which is taking the input from the user, about the move.
Problem Description
The board is maintained in the form of a 2D matrix, which contains the pieces as {color}{type}.
Eg. BH : black horse.
Pieces:
- K: king,
- Q: queen,
- P: pawn,
- R: rook,
- C: bishop,
- H: horse
A Move is defined as {color}{type} {src i}{src j} {dest i}{dest j} where \$i\$ denotes row and \$j\$ gives column.
Eg. BP 12 22, which move black pawn from \$(1,2)\$ to \$(2,2)\$.
The Implementation
Piece
is taken as an abstract class, which is being implemented by the different pieces King
, Rook
, Queen
, Bishop
, Horse
, Pawn
. A Piece
has a basic validation rule defined as common. All pieces have their own specific move, and a validation specific to the piece type.
Bishop
move is still missing in code.
Using Factory design pattern, the object of the specific piece is created, and further movements and validations are performed. Board allows its default, as well as user defined initialization.
Piece class
public abstract class Piece {
private char color;
public char getColor() {
return color;
}
public void setColor(char color) {
this.color = color;
}
public abstract boolean validateForPiece(int srcX, int srcY, int destX, int destY);
public void move(int srcX, int srcY, int destX, int destY, String piece) {
Board.CHESS_BOARD[destX][destY]=piece;
Board.CHESS_BOARD[srcX][srcY]="--";
}
public boolean checkMiddlePieces(int srcX, int srcY, int destX, int destY) {
if(srcX==destX && srcY!=destY) {
for(int i=srcY+1;i<destY;i++) {
if(Board.CHESS_BOARD[destX][i]!="--")
return false;
}
}
else if(srcX!=destX && srcY==destY) {
for(int i=srcX+1;i<destX;i++) {
if(Board.CHESS_BOARD[i][destY]!="--")
return false;
}
}
else if(Math.abs(srcX-destX)==Math.abs(srcY-destY)) {
for(int i=srcX+1,j=srcY+1;i<destX && j<destY;i++,j++) {
if(Board.CHESS_BOARD[i][destY]!="--")
return false;
}
}
return true;
}
public boolean validateFirst(int srcX, int srcY, int destX, int destY, String piece) {
char color = piece.charAt(0);
if(srcX>=8 || destX>=8 || srcY>=8 || destY>=8) {
System.out.println("Exception handled");
return false;
}
if(Board.CHESS_BOARD[srcX][srcY].equals("--")) {
System.out.println("Invalid move: No piece in this place");
return false;
}
if(!Board.CHESS_BOARD[srcX][srcY].equals(piece)) {
System.out.println("Invalid move: Different piece at given source");
return false;
}
if(Board.CHESS_BOARD[destX][destY]!="--") {
if(Board.CHESS_BOARD[destX][destY].charAt(0)==color) {
System.out.println("Invalid move: Your color piece at that place");
return false;
}
}
return true;
}
}
Pawn class
public class Pawn extends Piece {
@Override
public boolean validateForPiece(int srcX, int srcY, int destX, int destY) {
if(Board.TOP_WHITE) {
if(this.getColor()=='W' && destX-srcX<0)
return false;
if(this.getColor()=='B' && destX-srcX>0)
return false;
}
else {
if(this.getColor()=='B' && destX-srcX<0)
return false;
if(this.getColor()=='W' && destX-srcX>0)
return false;
}
if(((srcX==1 || srcX==6) && (Math.abs(destX-srcX)==2))
|| ((srcX!=1 || srcX!=6) && (Math.abs(destX-srcX)==1))
&& srcY==destY) {
return true;
}
if(Math.abs(srcY-destY)==1) {
if(Board.CHESS_BOARD[destX][destY]=="--")
return true;
}
if(Math.abs(srcX-destX)==1 && Math.abs(srcY-destY)==1) {
return true;
}
return false;
}
}
The other classes like Rook
, King
, Queen
, etc are also written in the same format, with different validation logic.
MoveImpl class
public class MoveImpl implements Move {
String piece;
int srcX;
int srcY;
int destX;
int destY;
char color;
char pieceType;
private void initializeValues(String inputMove[]) {
piece = inputMove[0];
srcX = Integer.parseInt(""+inputMove[1].charAt(0));
srcY = Integer.parseInt(""+inputMove[1].charAt(1));
destX = Integer.parseInt(""+inputMove[2].charAt(0));
destY = Integer.parseInt(""+inputMove[2].charAt(1));
color = piece.charAt(0);
pieceType = piece.charAt(1);
}
@Override
public void move(String inputMove[]) {
initializeValues(inputMove);
Piece pieceObj = PieceFactory.getPiece(piece);
boolean check1=pieceObj.validateFirst(srcX, srcY, destX, destY, piece);
boolean check2=pieceObj.validateForPiece(srcX, srcY, destX, destY);
if(!check1 || !check2)
System.out.println("Invalid move");
if(check1 && check2)
pieceObj.move(srcX, srcY, destX, destY, piece);
}
}
Main class
public class Main {
public static void main(String[] args) throws IOException {
Move move = new MoveImpl();
System.out.println("Input:");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String inp = br.readLine();
if(inp.equals("Board")) {
String board[][] = new String[8][8];
for(int i=0;i<8;i++) {
String row = br.readLine();
String rowArr[]=row.split(" ");
if(row.trim()!="")
for(int j=0;j<8;j++) {
board[i][j] = rowArr[j];
}
}
BoardInitializer.initialize(board);
System.out.println();
System.out.println("INITIAL STATE:");
BoardInitializer.displayBoardState();
}
else if(inp.equals("Display")) {
BoardInitializer.initialize();
System.out.println();
System.out.println("INITIAL STATE:");
BoardInitializer.displayBoardState();
}
inp=br.readLine();
if(inp.equals("Moves")){
while(inp!=null && inp.trim()!="") {
if(inp.trim().equals(""))
break;
inp = br.readLine();
if(inp.trim().equals(""))
break;
String inputMove[]=inp.split(" ");
move.move(inputMove);
BoardInitializer.displayBoardState();
}
}
}
}
Github link: https://github.com/yashi320/Chess-Validator
Sample Input and Output:
Input:
Display
INITIAL STATE:
CURRENT BOARD:
BR BH BC BK BQ BC BH BR
BP BP BP BP BP BP BP BP
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
WP WP WP WP WP WP WP WP
WR WH WC WQ WK WC WH WR
Moves
BP 12 32
CURRENT BOARD:
BR BH BC BK BQ BC BH BR
BP BP -- BP BP BP BP BP
-- -- -- -- -- -- -- --
-- -- BP -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
WP WP WP WP WP WP WP WP
WR WH WC WQ WK WC WH WR
BP 32 12
Invalid move
CURRENT BOARD:
BR BH BC BK BQ BC BH BR
BP BP -- BP BP BP BP BP
-- -- -- -- -- -- -- --
-- -- BP -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
WP WP WP WP WP WP WP WP
WR WH WC WQ WK WC WH WR
Please suggest possible improvements in the design.