Files
Sushi/src/suicideChess/Board.java

298 lines
9.0 KiB
Java

package suicideChess;
import suicideChess.Square.NotAValidSquare;
/**
* This class contains the board representation.
* The board is represented using bitboards.
* <ul><li>a1 is square 0</li>
* <li>h8 is square 7</li>
* <li>a2 is square 8</li>
* <li>... and so on</li>
*
* @author Jean-Baptiste H&eacute;tier
* @version $LastChangedRevision$, $LastChangedDate$
*
*/
public class Board {
/*===========*
* CONSTANTS *
*===========*/
//Some constants to make code more readable
public static final int NB_OF_RANKS = 8;
public static final int NB_OF_FILES = 8;
public static final int NB_OF_SQUARES = NB_OF_RANKS*NB_OF_FILES;
private static final int NB_OF_BITBOARDS = 14;
public class NoPieceOnSquare extends Exception {
/*
* Added by Eclipse
*/
private static final long serialVersionUID = -2750943856086117656L;
NoPieceOnSquare(String s) { super(s); };
}
/*======*
* DATA *
*======*/
//The following table is used to map squares to bits
protected static long mapSquaresToBits[];
//static function used to initialise data
static {
mapSquaresToBits = new long[NB_OF_SQUARES];
for(int i=0; i<NB_OF_SQUARES; i++) {
mapSquaresToBits[i] = (1L << i);
}
}
//The following table contains all the bit boards
protected long bitBoards[];
/*=============*
* CONSTRUCTOR *
*=============*/
/**
* Constructor of the class Board
* @throws NotAValidSquare
*/
public Board() throws NotAValidSquare {
bitBoards = new long[NB_OF_BITBOARDS];
addPiece(new Square("a1"),new Piece(Piece.WHITE_ROOK));
addPiece(new Square("b1"),new Piece(Piece.WHITE_KNIGHT));
addPiece(new Square("c1"),new Piece(Piece.WHITE_BISHOP));
addPiece(new Square("d1"),new Piece(Piece.WHITE_QUEEN));
addPiece(new Square("e1"),new Piece(Piece.WHITE_KING));
addPiece(new Square("f1"),new Piece(Piece.WHITE_BISHOP));
addPiece(new Square("g1"),new Piece(Piece.WHITE_KNIGHT));
addPiece(new Square("h1"),new Piece(Piece.WHITE_ROOK));
addPiece(new Square("a2"),new Piece(Piece.WHITE_PAWN));
addPiece(new Square("b2"),new Piece(Piece.WHITE_PAWN));
addPiece(new Square("c2"),new Piece(Piece.WHITE_PAWN));
addPiece(new Square("d2"),new Piece(Piece.WHITE_PAWN));
addPiece(new Square("e2"),new Piece(Piece.WHITE_PAWN));
addPiece(new Square("f2"),new Piece(Piece.WHITE_PAWN));
addPiece(new Square("g2"),new Piece(Piece.WHITE_PAWN));
addPiece(new Square("h2"),new Piece(Piece.WHITE_PAWN));
addPiece(new Square("a8"),new Piece(Piece.BLACK_ROOK));
addPiece(new Square("b8"),new Piece(Piece.BLACK_KNIGHT));
addPiece(new Square("c8"),new Piece(Piece.BLACK_BISHOP));
addPiece(new Square("d8"),new Piece(Piece.BLACK_QUEEN));
addPiece(new Square("e8"),new Piece(Piece.BLACK_KING));
addPiece(new Square("f8"),new Piece(Piece.BLACK_BISHOP));
addPiece(new Square("g8"),new Piece(Piece.BLACK_KNIGHT));
addPiece(new Square("h8"),new Piece(Piece.BLACK_ROOK));
addPiece(new Square("a7"),new Piece(Piece.BLACK_PAWN));
addPiece(new Square("b7"),new Piece(Piece.BLACK_PAWN));
addPiece(new Square("c7"),new Piece(Piece.BLACK_PAWN));
addPiece(new Square("d7"),new Piece(Piece.BLACK_PAWN));
addPiece(new Square("e7"),new Piece(Piece.BLACK_PAWN));
addPiece(new Square("f7"),new Piece(Piece.BLACK_PAWN));
addPiece(new Square("g7"),new Piece(Piece.BLACK_PAWN));
addPiece(new Square("h7"),new Piece(Piece.BLACK_PAWN));
}
/*================*
* PUBLIC METHODS *
*================*/
/**
* This methods takes a {@link Move} and applies it (updating the bitboard)
* @param move The move that is to be done
* @throws NoPieceOnSquare If a piece is trying to be moved from a square that does not exist.
* @see Move
*/
public void doMove(Move move) throws NoPieceOnSquare {
if (move.isCaptureMove()) {
removePiece(move.toSquare(), move.getCapturedPiece());
}
removePiece(move.fromSquare(), move.getMovingPiece());
if (move.isPromotionMove()) {
addPiece(move.toSquare(), move.getPromotionPiece());
} else {
addPiece(move.toSquare(), move.getMovingPiece());
}
}
/**
* This function searchs for what piece is on a square.
* @param onSquare The Square on which we will look for a piece.
* @return a {@link Piece}
* @see Square
* @see Piece
*/
public Piece getPiece(Square onSquare) {
//if there is a corresponding white piece.
if (!isEmpty(onSquare, new Piece(Piece.WHITE_PIECES))) {
//for every white piece bitboard, look for the piece
for (int piece = Piece.WHITE_PAWN; piece <= Piece.WHITE_ROOK; piece += 2) {
if(!isEmpty(onSquare, new Piece(piece))) {
return new Piece(piece);
}
}
} else if (!isEmpty(onSquare, new Piece(Piece.BLACK_PIECES))) {
//for every white piece bitboard, look for the piece
for (int piece = Piece.BLACK_PAWN; piece <= Piece.BLACK_ROOK; piece += 2) {
if(!isEmpty(onSquare, new Piece(piece))) {
return new Piece(piece);
}
}
}
//if no piece found
return new Piece(Piece.NONE);
}
/**
* This function can be used to display the board
* Black pieces are displayed in uppercase letters.
*/
public void display(){
for (int file = NB_OF_FILES; file >= 1; file--) {
System.out.println("+---+---+---+---+---+---+---+---+");
String display = "| ";
for (int rank=1; rank <= NB_OF_RANKS; rank++) {
boolean displayedSomething = false;
long mask = mapSquaresToBits[rank-1+(file-1)*NB_OF_RANKS];
if (displayPiece(Piece.BLACK_PAWN,mask)) {
displayedSomething=true;
display+=Character.toUpperCase(Piece.PAWN_CHAR)+" | ";
}
if (displayPiece(Piece.BLACK_QUEEN,mask)) {
displayedSomething=true;
display+=Character.toUpperCase(Piece.QUEEN_CHAR)+" | ";
}
if (displayPiece(Piece.BLACK_KING,mask)) {
displayedSomething=true;
display+=Character.toUpperCase(Piece.KING_CHAR)+" | ";
}
if (displayPiece(Piece.BLACK_KNIGHT,mask)) {
displayedSomething=true;
display+=Character.toUpperCase(Piece.KNIGHT_CHAR)+" | ";
}
if (displayPiece(Piece.BLACK_ROOK,mask)) {
displayedSomething=true;
display+=Character.toUpperCase(Piece.ROOK_CHAR)+" | ";
}
if (displayPiece(Piece.BLACK_BISHOP,mask)) {
displayedSomething=true;
display+=Character.toUpperCase(Piece.BISHOP_CHAR)+" | ";
}
if (displayPiece(Piece.WHITE_PAWN,mask)) {
displayedSomething=true;
display+=Piece.PAWN_CHAR+" | ";
}
if (displayPiece(Piece.WHITE_QUEEN,mask)) {
displayedSomething=true;
display+=Piece.QUEEN_CHAR+" | ";
}
if (displayPiece(Piece.WHITE_KING,mask)) {
displayedSomething=true;
display+=Piece.KING_CHAR+" | ";
}
if (displayPiece(Piece.WHITE_KNIGHT,mask)) {
displayedSomething=true;
display+=Piece.KNIGHT_CHAR+" | ";
}
if (displayPiece(Piece.WHITE_ROOK,mask)) {
displayedSomething=true;
display+=Piece.ROOK_CHAR+" | ";
}
if (displayPiece(Piece.WHITE_BISHOP,mask)) {
displayedSomething=true;
display+=Piece.BISHOP_CHAR+" | ";
}
if (!displayedSomething)
display+=" | ";
}
System.out.println(display);
}
System.out.println("+---+---+---+---+---+---+---+---+");
}
/*=================*
* PRIVATE METHODS *
*=================*/
/* private long getBitBoard(int bitboard_number) {
return bitBoards[bitboard_number];
}
*/
private int squareToBitBoardSquare(Square square) {
//converts a square ("e2") to a BitboardSquare (
return square.getFileNb() -1 + (square.getRank()-1)*NB_OF_FILES;
}
protected void addPiece(Square square, Piece piece) {
//OR :
// 0 OR a = a
// 1 OR a = 1
//add Piece to corresponding bitboard.
bitBoards[piece.getPieceNumber()] |= mapSquaresToBits[squareToBitBoardSquare(square)];
//update the bitboard of all pieces of that color
bitBoards[piece.getColor()] |= mapSquaresToBits[squareToBitBoardSquare(square)];
}
protected void removePiece(Square square, Piece piece) throws NoPieceOnSquare {
//XOR :
// 0 XOR a = a
// 1 XOR 0 = 1 !!! Don't remove a piece that don't exist !!!
// 1 XOR 1 = 0
//remove Piece to corresponding bitboard.
if (SuicideChess.BITBOARD_REMOVEPIECE_CHECK_REMOVE) {
if (!isEmpty(square, piece)) {
bitBoards[piece.getPieceNumber()] ^= mapSquaresToBits[squareToBitBoardSquare(square)];
} else {
throw new NoPieceOnSquare("Square: "+square + "; Piece: " + piece.getPieceNumber());
}
} else {
bitBoards[piece.getPieceNumber()] ^= mapSquaresToBits[squareToBitBoardSquare(square)];
}
//update the bitboard of all pieces of that color
bitBoards[piece.getColor()] ^= mapSquaresToBits[squareToBitBoardSquare(square)];;
}
//checks if a square is empty for a certain piece
private boolean isEmpty(Square square, Piece piece) {
long mask = mapSquaresToBits[squareToBitBoardSquare(square)];
if ((bitBoards[piece.getPieceNumber()] & mask) == 0) {
return true;
} else {
return false;
}
}
private boolean displayPiece(int whatToDisplay, long mask) {
if ((bitBoards[whatToDisplay] & mask)==0) {
return false;
} else {
return true;
}
}
}