663 lines
22 KiB
Java
663 lines
22 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>
|
|
*
|
|
* Note that the evaluation of the board balance is in this class since I considered that it is
|
|
* very closely related to the board position.
|
|
*
|
|
* @author Jean-Baptiste Hé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;
|
|
|
|
@SuppressWarnings("serial")
|
|
public class NoPieceOnSquare extends Exception {
|
|
NoPieceOnSquare(String s) { super(s); };
|
|
}
|
|
@SuppressWarnings("serial")
|
|
public class UnableToParseFENStringException extends Exception {
|
|
UnableToParseFENStringException(String s) { super(s); };
|
|
}
|
|
/**
|
|
* Value returned by the evaluation function when White wins
|
|
*/
|
|
public static final int WHITE_WINS = 99999;
|
|
|
|
/**
|
|
* Value representing the maximum value possible for the evaluation function
|
|
*/
|
|
public static final int MAX_VALUE = WHITE_WINS+1;
|
|
|
|
/**
|
|
* Value returned by the evaluation function when Black wins
|
|
*/
|
|
public static final int BLACK_WINS = -99999;
|
|
|
|
/**
|
|
* Value representing the minimum value possible for the evaluation function
|
|
*/
|
|
public static final int MIN_VALUE = BLACK_WINS-1;
|
|
|
|
/**
|
|
* Value representing the value of a draw position
|
|
*/
|
|
public static final int DRAW_BOARD = 0;
|
|
|
|
/**
|
|
* Importance of real mobility in position evaluation (ie. how many moves can one make compared to the other)
|
|
*/
|
|
public static final int REAL_MOBILITY_VALUE = 40; //10;
|
|
/**
|
|
* Importance of relative mobility (mobility of other pieces that may not be able to play because of a compulsory move)
|
|
*/
|
|
public static final int RELATIVE_MOBILITY_VALUE = 40; //5;
|
|
|
|
//with less than that many pawns on one side, the computer will enter endgame mode
|
|
public static final int ENDGAME_PAWNS = 3;
|
|
|
|
//with less than that many pieces on one side, the computer will enter endgame mode
|
|
public static final int ENDGAME_PIECES = 8;
|
|
|
|
public static final int[] SQUARE_WEIGHT = {
|
|
/* -20, -10, -10, -10, -10, -10, -10, -20,
|
|
-10, 0, 3, 5, 5, 3, 0, -10,
|
|
-10, 2, 15, 15, 15, 15, 2, -10,
|
|
-10, 7, 15, 25, 25, 15, 7, -10,
|
|
-10, 7, 15, 25, 25, 15, 7, -10,
|
|
-10, 2, 15, 15, 15, 15, 2, -10,
|
|
-10, 0, 3, 5, 5, 3, 0, -10,
|
|
-20, -10, -10, -10, -10, -10, -10, -20*/
|
|
10, 10, 10, 10, 10, 10, 10, 10,
|
|
10, 10, 10, 10, 10, 10, 10, 10,
|
|
10, 10, 10, 10, 10, 10, 10, 10,
|
|
10, 10, 10, 10, 10, 10, 10, 10,
|
|
10, 10, 10, 10, 10, 10, 10, 10,
|
|
10, 10, 10, 10, 10, 10, 10, 10,
|
|
10, 10, 10, 10, 10, 10, 10, 10,
|
|
10, 10, 10, 10, 10, 10, 10, 10
|
|
};
|
|
|
|
|
|
/*======*
|
|
* 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[];
|
|
|
|
|
|
private boolean enPassant=false; //is there an 'en passant pawn' on the board
|
|
private Square enPassantSquare;
|
|
|
|
//the number of each piece type will be accessed
|
|
//using the index and the piece value defined in Piece class
|
|
private int[] numberOfPieces;
|
|
//the value of each piece (used for the evaluation function)
|
|
|
|
private int boardValue = 0; //evaluation of the board value
|
|
|
|
private int currentPlayer; //color of the current player.
|
|
|
|
//starts at 1 and increment after each of black's move
|
|
private int fullmoveNumber;
|
|
//this variable holds the number of Moves since last capture or last pawn move
|
|
private int halfmoveClock;
|
|
|
|
/*=============*
|
|
* CONSTRUCTOR *
|
|
*=============*/
|
|
|
|
/**
|
|
* Constructor of the class Board
|
|
* @throws NotAValidSquare
|
|
*/
|
|
|
|
public Board() throws NotAValidSquare {
|
|
//the following line makes sure that enPassantSquare is defined at some point.
|
|
enPassantSquare = new Square("a1");
|
|
|
|
fullmoveNumber = 1;
|
|
halfmoveClock = 0;
|
|
|
|
numberOfPieces = new int[Piece.MAX_PIECE_NUMBER+1];
|
|
for (int i=0; i<=Piece.MAX_PIECE_NUMBER; i++) {
|
|
numberOfPieces[i]=0;
|
|
}
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
/**
|
|
* A constructor that simply copies a bitboard
|
|
* @param bitboard The bitboard to be copied
|
|
*/
|
|
|
|
public Board(Board bitboard) {
|
|
numberOfPieces = new int[Piece.MAX_PIECE_NUMBER+1];
|
|
for (int i=0; i<=Piece.MAX_PIECE_NUMBER; i++) {
|
|
this.numberOfPieces[i] = bitboard.numberOfPieces[i];
|
|
}
|
|
|
|
this.fullmoveNumber = bitboard.fullmoveNumber;
|
|
this.halfmoveClock = bitboard.halfmoveClock;
|
|
|
|
this.boardValue = bitboard.boardValue;
|
|
this.bitBoards = new long[NB_OF_BITBOARDS];
|
|
for (int i=0; i<NB_OF_BITBOARDS; i++) {
|
|
this.bitBoards[i] = bitboard.bitBoards[i];
|
|
}
|
|
this.enPassant = bitboard.enPassant;
|
|
this.enPassantSquare = new Square(bitboard.enPassantSquare);
|
|
this.currentPlayer = bitboard.currentPlayer;
|
|
}
|
|
|
|
/**
|
|
* This constructor is used to create a board with a string in FEN notation
|
|
* @param command A string representing the command
|
|
* @return A {@link Board} corresponding to the FEN string
|
|
* @throws NotAValidSquare
|
|
* @throws UnableToParseFENStringException
|
|
* @see Board
|
|
*/
|
|
public Board(String command) throws NotAValidSquare, UnableToParseFENStringException {
|
|
String[] result = command.split("/|\\s");
|
|
/*
|
|
* After splitting
|
|
* 0->rank 8
|
|
* 1->rank 7
|
|
* ...
|
|
* 7->rank 1
|
|
* 8->color on move
|
|
* 9->castling (I don't care about this)
|
|
* 10->enpassant Square (if any), otherwise '-'
|
|
* 11->count of plies since the last pawn advance or capturing move
|
|
* 12->fullmove number
|
|
*/
|
|
|
|
bitBoards = new long[NB_OF_BITBOARDS];
|
|
|
|
if (result.length!=13) {
|
|
throw new UnableToParseFENStringException(command);
|
|
}
|
|
|
|
if (result[8].equals("b")) {
|
|
currentPlayer=Piece.BLACK;
|
|
} else {
|
|
currentPlayer=Piece.WHITE;
|
|
}
|
|
if (!result[10].equals("-")) {
|
|
enPassant = true;
|
|
enPassantSquare = new Square(result[10]);
|
|
} else {
|
|
enPassant = false;
|
|
enPassantSquare = new Square("a1"); //otherwise it is null
|
|
}
|
|
try {
|
|
fullmoveNumber = Integer.parseInt(result[12]);
|
|
halfmoveClock = Integer.parseInt(result[11]);
|
|
} catch (NumberFormatException e) {
|
|
System.out.println("Error (impossible to parse clock): "+command);
|
|
fullmoveNumber = 1;
|
|
halfmoveClock = 0;
|
|
}
|
|
|
|
numberOfPieces = new int[Piece.MAX_PIECE_NUMBER+1];
|
|
|
|
for(int split=0; split < 8; split++) {
|
|
int offset=0;
|
|
char[] rowToParse = result[split].toCharArray();
|
|
for (int character=0; character<rowToParse.length; character++) {
|
|
if (Character.isDigit(rowToParse[character])) {
|
|
offset+=((int)rowToParse[character]-(int)'1');
|
|
} else {
|
|
Piece pieceToAdd = new Piece(rowToParse[character]);
|
|
addPiece(new Square(character+offset+1,NB_OF_RANKS-split),pieceToAdd);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (numberOfPieces[Piece.BLACK] == 0) {
|
|
boardValue = BLACK_WINS;
|
|
} else if (numberOfPieces[Piece.WHITE] == 0){
|
|
boardValue = WHITE_WINS;
|
|
} else if (!Rules.isThereALegalMovesForPlayer(this)) {
|
|
if (currentPlayer==Piece.WHITE) {
|
|
boardValue = WHITE_WINS;
|
|
} else {
|
|
boardValue = BLACK_WINS;
|
|
}
|
|
} else {
|
|
boardValue = getBoardValue();
|
|
}
|
|
}
|
|
|
|
|
|
/*================*
|
|
* 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.
|
|
* @throws NotAValidSquare
|
|
* @see Move
|
|
*/
|
|
|
|
public void doMove(Move move) throws NoPieceOnSquare, NotAValidSquare {
|
|
halfmoveClock++;
|
|
if (move.isCaptureMove()) {
|
|
if (move.isEnPassant()) {
|
|
removePiece(move.getEnPassantSquare(), move.getCapturedPiece());
|
|
} else {
|
|
removePiece(move.toSquare(), move.getCapturedPiece());
|
|
}
|
|
halfmoveClock=0; //reinitialise halfmoveClock since there has been a capture
|
|
}
|
|
removePiece(move.fromSquare(), move.getMovingPiece());
|
|
if (move.isPromotionMove()) {
|
|
addPiece(move.toSquare(), move.getPromotionPiece());
|
|
} else {
|
|
addPiece(move.toSquare(), move.getMovingPiece());
|
|
}
|
|
if(move.getMovingPiece().getPieceNumber()==Piece.PAWN) {
|
|
halfmoveClock = 0; //a pawn has been moved
|
|
}
|
|
|
|
this.enPassant=false;
|
|
if (move.enablesEnPassant()) {
|
|
enPassant=true;
|
|
enPassantSquare=move.getEnPassantSquare();
|
|
}
|
|
|
|
if(currentPlayer==Piece.WHITE) {
|
|
currentPlayer=Piece.BLACK;
|
|
} else {
|
|
fullmoveNumber++; //black has just played
|
|
currentPlayer=Piece.WHITE;
|
|
}
|
|
|
|
evaluateNewBoardValue(move);
|
|
}
|
|
|
|
/**
|
|
* 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 returns a boolean telling if a {@link Piece} is on a {@link Square}.
|
|
* @param square The Square
|
|
* @param piece A Piece constant
|
|
* @return boolean
|
|
* @see Piece
|
|
* @see Square
|
|
*/
|
|
public boolean isEmpty(Square square, Piece piece) {
|
|
long mask = mapSquaresToBits[squareToBitBoardSquare(square)];
|
|
if ((bitBoards[piece.getPieceNumber()] & mask) == 0) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function converts a {@link Square} to a number representing a bitboard square
|
|
* @param square The Square to be converted
|
|
* @return int
|
|
* @see Square
|
|
*/
|
|
public static int squareToBitBoardSquare(Square square) {
|
|
//converts a square ("e2") to a BitboardSquare (
|
|
return square.getFileNb() -1 + (square.getRank()-1)*NB_OF_FILES;
|
|
}
|
|
|
|
// /**
|
|
// * This function is used to set the table to an state in which a {@link Square} is an 'en passant' Square
|
|
// * @param Square The 'en passant' Square
|
|
// * @see Square
|
|
// */
|
|
// public void setEnPassant(Square square) {
|
|
// enPassant=true;
|
|
// enPassantSquare=square;
|
|
// }
|
|
//
|
|
// /**
|
|
// * This function is used to set the table back to a state with no 'en passant' Squares.
|
|
// */
|
|
// public void clearEnPassant () {
|
|
// enPassant=false;
|
|
// }
|
|
|
|
/**
|
|
* This function returns a boolean saying if the board is in an 'en passant' state.
|
|
* @return boolean
|
|
*/
|
|
public boolean isEnPassant() {
|
|
return enPassant;
|
|
}
|
|
|
|
/**
|
|
* This function is used to return the 'en passant' Square. Don't use it unless table is in an 'en passant' state.
|
|
* @return Square
|
|
* @see Square
|
|
*/
|
|
public Square getEnPassantSquare() {
|
|
return enPassantSquare;
|
|
}
|
|
|
|
/**
|
|
* This function returns an integer representing the result of the static evaluation function
|
|
* for the current board
|
|
* @return Integer
|
|
*/
|
|
public int getBoardValue() {
|
|
return boardValue;
|
|
}
|
|
|
|
/**
|
|
* This function tells if the board is in a draw status
|
|
*/
|
|
public boolean isADraw() {
|
|
if(halfmoveClock>=Rules.NUMBER_OF_MOVES_BEFORE_DRAW) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
/**
|
|
* Used to get the halfmoveClock.
|
|
* @return the number of halfmoves since the last capture or pawn movement
|
|
*/
|
|
public int getHalfmoveClock() {
|
|
return halfmoveClock;
|
|
}
|
|
|
|
|
|
/**
|
|
* This function returns the current player color
|
|
* @return Integer
|
|
*/
|
|
public int getCurrentPlayer() {
|
|
return currentPlayer;
|
|
}
|
|
|
|
/**
|
|
* 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 = file+" |";
|
|
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+="'"+Piece.BLACK_PAWN_CHAR+"'|";
|
|
}
|
|
if (displayPiece(Piece.BLACK_QUEEN,mask)) {
|
|
displayedSomething=true;
|
|
display+="'"+Piece.BLACK_QUEEN_CHAR+"'|";
|
|
}
|
|
if (displayPiece(Piece.BLACK_KING,mask)) {
|
|
displayedSomething=true;
|
|
display+="'"+Piece.BLACK_KING_CHAR+"'|";
|
|
}
|
|
if (displayPiece(Piece.BLACK_KNIGHT,mask)) {
|
|
displayedSomething=true;
|
|
display+="'"+Piece.BLACK_KNIGHT_CHAR+"'|";
|
|
}
|
|
if (displayPiece(Piece.BLACK_ROOK,mask)) {
|
|
displayedSomething=true;
|
|
display+="'"+Piece.BLACK_ROOK_CHAR+"'|";
|
|
}
|
|
if (displayPiece(Piece.BLACK_BISHOP,mask)) {
|
|
displayedSomething=true;
|
|
display+="'"+Piece.BLACK_BISHOP_CHAR+"'|";
|
|
}
|
|
if (displayPiece(Piece.WHITE_PAWN,mask)) {
|
|
displayedSomething=true;
|
|
display+=" "+Piece.WHITE_PAWN_CHAR+" |";
|
|
}
|
|
if (displayPiece(Piece.WHITE_QUEEN,mask)) {
|
|
displayedSomething=true;
|
|
display+=" "+Piece.WHITE_QUEEN_CHAR+" |";
|
|
}
|
|
if (displayPiece(Piece.WHITE_KING,mask)) {
|
|
displayedSomething=true;
|
|
display+=" "+Piece.WHITE_KING_CHAR+" |";
|
|
}
|
|
if (displayPiece(Piece.WHITE_KNIGHT,mask)) {
|
|
displayedSomething=true;
|
|
display+=" "+Piece.WHITE_KNIGHT_CHAR+" |";
|
|
}
|
|
if (displayPiece(Piece.WHITE_ROOK,mask)) {
|
|
displayedSomething=true;
|
|
display+=" "+Piece.WHITE_ROOK_CHAR+" |";
|
|
}
|
|
if (displayPiece(Piece.WHITE_BISHOP,mask)) {
|
|
displayedSomething=true;
|
|
display+=" "+Piece.WHITE_BISHOP_CHAR+" |";
|
|
}
|
|
if (!displayedSomething)
|
|
display+=" |";
|
|
}
|
|
System.out.println(display);
|
|
}
|
|
System.out.println(" +---+---+---+---+---+---+---+---+");
|
|
System.out.println(" a b c d e f g h");
|
|
System.out.println();
|
|
|
|
}
|
|
|
|
|
|
/*=================*
|
|
* PRIVATE METHODS *
|
|
*=================*/
|
|
|
|
|
|
/* private long getBitBoard(int bitboard_number) {
|
|
return bitBoards[bitboard_number];
|
|
}
|
|
*/
|
|
|
|
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)];
|
|
|
|
numberOfPieces[piece.getPieceNumber()] += 1;
|
|
numberOfPieces[piece.getColor()] += 1;
|
|
}
|
|
|
|
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)];;
|
|
|
|
numberOfPieces[piece.getPieceNumber()] -= 1;
|
|
numberOfPieces[piece.getColor()] -= 1;
|
|
}
|
|
|
|
//used by function display()
|
|
private boolean displayPiece(int whatToDisplay, long mask) {
|
|
if ((bitBoards[whatToDisplay] & mask)==0) {
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
//calculates player's mobility
|
|
public int mobility(int colour) throws NotAValidSquare {
|
|
Board thisCopy = new Board(this);
|
|
thisCopy.currentPlayer=colour;
|
|
Rules.legalMovesForPlayer(thisCopy);
|
|
if (Rules.getLegalMovesCapture().size()!=0) {
|
|
return Rules.getLegalMovesCapture().size()*REAL_MOBILITY_VALUE
|
|
+Rules.getLegalMovesNonCapture().size()*RELATIVE_MOBILITY_VALUE;
|
|
} else {
|
|
return Rules.getLegalMovesNonCapture().size()*REAL_MOBILITY_VALUE;
|
|
}
|
|
}
|
|
|
|
private void evaluateNewBoardValue (Move move) throws NotAValidSquare {
|
|
|
|
if (move.isCaptureMove()) {
|
|
if (numberOfPieces[Piece.BLACK] == 0) {
|
|
boardValue = BLACK_WINS;
|
|
} else if (numberOfPieces[Piece.WHITE] == 0){
|
|
boardValue = WHITE_WINS;
|
|
} else {
|
|
//this is a very very basic evaluation function that will be changed.
|
|
//boardValue = numberOfBlackPieces - numberOfWhitePieces;
|
|
boardValue = 0;
|
|
/*if((numberOfPieces[Piece.BLACK_PAWN] <= ENDGAME_PAWNS) || (numberOfPieces[Piece.WHITE_PAWN] <= ENDGAME_PAWNS)
|
|
|| (numberOfPieces[Piece.BLACK_PIECES] <= ENDGAME_PIECES) || (numberOfPieces[Piece.WHITE_PIECES] <= ENDGAME_PIECES) ) {
|
|
//System.out.println("Playing endgame");
|
|
for (int i = Piece.OFFSET; i<=Piece.MAX_PIECE_NUMBER; i++) {
|
|
boardValue += numberOfPieces[i]*Piece.PIECE_VALUE_ENDGAME[i];
|
|
}
|
|
} else {
|
|
//System.out.println("Playing midgame");
|
|
/*for (int i = Piece.OFFSET; i<=Piece.MAX_PIECE_NUMBER; i++) {
|
|
boardValue += numberOfPieces[i]*Piece.PIECE_VALUE_MIDDLEGAME[i];
|
|
}*/
|
|
for(int squareNb = 0; squareNb<NB_OF_SQUARES; squareNb++) {
|
|
Piece pieceOnSquare = getPiece(new Square(squareNb));
|
|
if(pieceOnSquare.getPieceNumber()!=Piece.NONE) {
|
|
//System.out.println(SQUARE_WEIGHT[squareNb]);
|
|
boardValue += SQUARE_WEIGHT[squareNb]*Piece.PIECE_VALUE_MIDDLEGAME[pieceOnSquare.getPieceNumber()];
|
|
}
|
|
}
|
|
//boardValue += ((mobility(Piece.WHITE)-mobility(Piece.BLACK)));
|
|
//}
|
|
}
|
|
}
|
|
if (!Rules.isThereALegalMovesForPlayer(this)) {
|
|
if (currentPlayer==Piece.WHITE) {
|
|
boardValue = WHITE_WINS;
|
|
} else {
|
|
boardValue = BLACK_WINS;
|
|
}
|
|
}
|
|
}
|
|
|
|
} |