Version 1.4.2
Now possible to undo, save games, restore positions, and view statistics when the computer plays.
This commit is contained in:
@ -35,7 +35,10 @@ public class Board {
|
|||||||
public class NoPieceOnSquare extends Exception {
|
public class NoPieceOnSquare extends Exception {
|
||||||
NoPieceOnSquare(String s) { super(s); };
|
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
|
* Value returned by the evaluation function when White wins
|
||||||
*/
|
*/
|
||||||
@ -145,6 +148,73 @@ public class Board {
|
|||||||
this.currentPlayer = bitboard.currentPlayer;
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
numberOfBlackPieces = 0;
|
||||||
|
numberOfWhitePieces = 0;
|
||||||
|
|
||||||
|
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 (pieceToAdd.getColor()==Piece.BLACK) {
|
||||||
|
numberOfBlackPieces++;
|
||||||
|
} else {
|
||||||
|
numberOfWhitePieces++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
boardValue = getBoardValue();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*================*
|
/*================*
|
||||||
* PUBLIC METHODS *
|
* PUBLIC METHODS *
|
||||||
*================*/
|
*================*/
|
||||||
@ -315,51 +385,51 @@ public class Board {
|
|||||||
|
|
||||||
if (displayPiece(Piece.BLACK_PAWN,mask)) {
|
if (displayPiece(Piece.BLACK_PAWN,mask)) {
|
||||||
displayedSomething=true;
|
displayedSomething=true;
|
||||||
display+="'"+Character.toUpperCase(Piece.PAWN_CHAR)+"'|";
|
display+="'"+Piece.BLACK_PAWN_CHAR+"'|";
|
||||||
}
|
}
|
||||||
if (displayPiece(Piece.BLACK_QUEEN,mask)) {
|
if (displayPiece(Piece.BLACK_QUEEN,mask)) {
|
||||||
displayedSomething=true;
|
displayedSomething=true;
|
||||||
display+="'"+Character.toUpperCase(Piece.QUEEN_CHAR)+"'|";
|
display+="'"+Piece.BLACK_QUEEN_CHAR+"'|";
|
||||||
}
|
}
|
||||||
if (displayPiece(Piece.BLACK_KING,mask)) {
|
if (displayPiece(Piece.BLACK_KING,mask)) {
|
||||||
displayedSomething=true;
|
displayedSomething=true;
|
||||||
display+="'"+Character.toUpperCase(Piece.KING_CHAR)+"'|";
|
display+="'"+Piece.BLACK_KING_CHAR+"'|";
|
||||||
}
|
}
|
||||||
if (displayPiece(Piece.BLACK_KNIGHT,mask)) {
|
if (displayPiece(Piece.BLACK_KNIGHT,mask)) {
|
||||||
displayedSomething=true;
|
displayedSomething=true;
|
||||||
display+="'"+Character.toUpperCase(Piece.KNIGHT_CHAR)+"'|";
|
display+="'"+Piece.BLACK_KNIGHT_CHAR+"'|";
|
||||||
}
|
}
|
||||||
if (displayPiece(Piece.BLACK_ROOK,mask)) {
|
if (displayPiece(Piece.BLACK_ROOK,mask)) {
|
||||||
displayedSomething=true;
|
displayedSomething=true;
|
||||||
display+="'"+Character.toUpperCase(Piece.ROOK_CHAR)+"'|";
|
display+="'"+Piece.BLACK_ROOK_CHAR+"'|";
|
||||||
}
|
}
|
||||||
if (displayPiece(Piece.BLACK_BISHOP,mask)) {
|
if (displayPiece(Piece.BLACK_BISHOP,mask)) {
|
||||||
displayedSomething=true;
|
displayedSomething=true;
|
||||||
display+="'"+Character.toUpperCase(Piece.BISHOP_CHAR)+"'|";
|
display+="'"+Piece.BLACK_BISHOP_CHAR+"'|";
|
||||||
}
|
}
|
||||||
if (displayPiece(Piece.WHITE_PAWN,mask)) {
|
if (displayPiece(Piece.WHITE_PAWN,mask)) {
|
||||||
displayedSomething=true;
|
displayedSomething=true;
|
||||||
display+=" "+Piece.PAWN_CHAR+" |";
|
display+=" "+Piece.WHITE_PAWN_CHAR+" |";
|
||||||
}
|
}
|
||||||
if (displayPiece(Piece.WHITE_QUEEN,mask)) {
|
if (displayPiece(Piece.WHITE_QUEEN,mask)) {
|
||||||
displayedSomething=true;
|
displayedSomething=true;
|
||||||
display+=" "+Piece.QUEEN_CHAR+" |";
|
display+=" "+Piece.WHITE_QUEEN_CHAR+" |";
|
||||||
}
|
}
|
||||||
if (displayPiece(Piece.WHITE_KING,mask)) {
|
if (displayPiece(Piece.WHITE_KING,mask)) {
|
||||||
displayedSomething=true;
|
displayedSomething=true;
|
||||||
display+=" "+Piece.KING_CHAR+" |";
|
display+=" "+Piece.WHITE_KING_CHAR+" |";
|
||||||
}
|
}
|
||||||
if (displayPiece(Piece.WHITE_KNIGHT,mask)) {
|
if (displayPiece(Piece.WHITE_KNIGHT,mask)) {
|
||||||
displayedSomething=true;
|
displayedSomething=true;
|
||||||
display+=" "+Piece.KNIGHT_CHAR+" |";
|
display+=" "+Piece.WHITE_KNIGHT_CHAR+" |";
|
||||||
}
|
}
|
||||||
if (displayPiece(Piece.WHITE_ROOK,mask)) {
|
if (displayPiece(Piece.WHITE_ROOK,mask)) {
|
||||||
displayedSomething=true;
|
displayedSomething=true;
|
||||||
display+=" "+Piece.ROOK_CHAR+" |";
|
display+=" "+Piece.WHITE_ROOK_CHAR+" |";
|
||||||
}
|
}
|
||||||
if (displayPiece(Piece.WHITE_BISHOP,mask)) {
|
if (displayPiece(Piece.WHITE_BISHOP,mask)) {
|
||||||
displayedSomething=true;
|
displayedSomething=true;
|
||||||
display+=" "+Piece.BISHOP_CHAR+" |";
|
display+=" "+Piece.WHITE_BISHOP_CHAR+" |";
|
||||||
}
|
}
|
||||||
if (!displayedSomething)
|
if (!displayedSomething)
|
||||||
display+=" |";
|
display+=" |";
|
||||||
@ -438,14 +508,11 @@ public class Board {
|
|||||||
boardValue = numberOfBlackPieces - numberOfWhitePieces;
|
boardValue = numberOfBlackPieces - numberOfWhitePieces;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Rules.legalMovesForPlayer(this);
|
if (Rules.isThereALegalMovesForPlayer(this)) {
|
||||||
if ((Rules.getLegalMovesCapture().size()==0)&&(Rules.getLegalMovesNonCapture().size()==0)) {
|
if (currentPlayer==Piece.WHITE) {
|
||||||
// The following line is NOT an error !!!
|
|
||||||
// After move from WHITE, if there is no moves for BLACK, BLACK won.
|
|
||||||
if (move.getMovingPiece().getColor()==Piece.WHITE) {
|
|
||||||
boardValue = BLACK_WINS;
|
|
||||||
} else {
|
|
||||||
boardValue = WHITE_WINS;
|
boardValue = WHITE_WINS;
|
||||||
|
} else {
|
||||||
|
boardValue = BLACK_WINS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,9 +56,22 @@ public class Piece {
|
|||||||
public static final char BISHOP_CHAR='b';
|
public static final char BISHOP_CHAR='b';
|
||||||
public static final char KNIGHT_CHAR='n';
|
public static final char KNIGHT_CHAR='n';
|
||||||
public static final char ROOK_CHAR='r';
|
public static final char ROOK_CHAR='r';
|
||||||
//may be useful
|
|
||||||
public static final char PAWN_CHAR='p';
|
public static final char PAWN_CHAR='p';
|
||||||
|
|
||||||
|
public static final char WHITE_KING_CHAR='K';
|
||||||
|
public static final char WHITE_QUEEN_CHAR='Q';
|
||||||
|
public static final char WHITE_BISHOP_CHAR='B';
|
||||||
|
public static final char WHITE_KNIGHT_CHAR='N';
|
||||||
|
public static final char WHITE_ROOK_CHAR='R';
|
||||||
|
public static final char WHITE_PAWN_CHAR='P';
|
||||||
|
public static final char BLACK_KING_CHAR='k';
|
||||||
|
public static final char BLACK_QUEEN_CHAR='q';
|
||||||
|
public static final char BLACK_BISHOP_CHAR='b';
|
||||||
|
public static final char BLACK_KNIGHT_CHAR='n';
|
||||||
|
public static final char BLACK_ROOK_CHAR='r';
|
||||||
|
public static final char BLACK_PAWN_CHAR='p';
|
||||||
|
|
||||||
|
|
||||||
/*==============*
|
/*==============*
|
||||||
* PRIVATE DATA *
|
* PRIVATE DATA *
|
||||||
*==============*/
|
*==============*/
|
||||||
@ -79,7 +92,7 @@ public class Piece {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construcs a Piece given its color and its standard algebaic name
|
* Construcs a Piece given its color and its standard algebraic name
|
||||||
* (declared as constants in this file)
|
* (declared as constants in this file)
|
||||||
* @param piece A character used to represent the Piece.
|
* @param piece A character used to represent the Piece.
|
||||||
* @param color The color of the piece. (See declared constants)
|
* @param color The color of the piece. (See declared constants)
|
||||||
@ -108,6 +121,52 @@ public class Piece {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construcs a Piece given its standard algebraic name
|
||||||
|
* uppercase is white and lowercase is black
|
||||||
|
*/
|
||||||
|
public Piece(char piece) {
|
||||||
|
pieceNumber = NONE;
|
||||||
|
switch (piece) {
|
||||||
|
case WHITE_PAWN_CHAR:
|
||||||
|
pieceNumber = 2*(PAWN+1) + WHITE;
|
||||||
|
break;
|
||||||
|
case WHITE_KING_CHAR:
|
||||||
|
pieceNumber = 2*(KING+1) + WHITE;
|
||||||
|
break;
|
||||||
|
case WHITE_QUEEN_CHAR:
|
||||||
|
pieceNumber = 2*(QUEEN+1) + WHITE;
|
||||||
|
break;
|
||||||
|
case WHITE_BISHOP_CHAR:
|
||||||
|
pieceNumber = 2*(BISHOP+1) + WHITE;
|
||||||
|
break;
|
||||||
|
case WHITE_KNIGHT_CHAR:
|
||||||
|
pieceNumber = 2*(KNIGHT+1) + WHITE;
|
||||||
|
break;
|
||||||
|
case WHITE_ROOK_CHAR:
|
||||||
|
pieceNumber = 2*(ROOK+1) + WHITE;
|
||||||
|
break;
|
||||||
|
case BLACK_PAWN_CHAR:
|
||||||
|
pieceNumber = 2*(PAWN+1) + BLACK;
|
||||||
|
break;
|
||||||
|
case BLACK_KING_CHAR:
|
||||||
|
pieceNumber = 2*(KING+1) + BLACK;
|
||||||
|
break;
|
||||||
|
case BLACK_QUEEN_CHAR:
|
||||||
|
pieceNumber = 2*(QUEEN+1) + BLACK;
|
||||||
|
break;
|
||||||
|
case BLACK_BISHOP_CHAR:
|
||||||
|
pieceNumber = 2*(BISHOP+1) + BLACK;
|
||||||
|
break;
|
||||||
|
case BLACK_KNIGHT_CHAR:
|
||||||
|
pieceNumber = 2*(KNIGHT+1) + BLACK;
|
||||||
|
break;
|
||||||
|
case BLACK_ROOK_CHAR:
|
||||||
|
pieceNumber = 2*(ROOK+1) + BLACK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*=========*
|
/*=========*
|
||||||
* METHODS *
|
* METHODS *
|
||||||
*=========*/
|
*=========*/
|
||||||
|
@ -35,7 +35,6 @@ public class Rules {
|
|||||||
* Computes the possible moves according to the current status of the {@link Board} and the
|
* Computes the possible moves according to the current status of the {@link Board} and the
|
||||||
* color of the current player.
|
* color of the current player.
|
||||||
* @param board The current board position.
|
* @param board The current board position.
|
||||||
* @param color The color of the current player.
|
|
||||||
* @throws NotAValidSquare If the program throws this exception then there is a bug.
|
* @throws NotAValidSquare If the program throws this exception then there is a bug.
|
||||||
* @throws UnexpectedError This should never happen.
|
* @throws UnexpectedError This should never happen.
|
||||||
* @see Square
|
* @see Square
|
||||||
@ -55,18 +54,47 @@ public class Rules {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes the possible moves from a given {@link Square}
|
* Looks for one legal move according to the current status of the {@link Board} and the
|
||||||
* according to the current status of the {@link Board}
|
* color of the current player.
|
||||||
* @param fromSquare The square from which the move must start
|
|
||||||
* @param board The current board position.
|
* @param board The current board position.
|
||||||
* @throws NotAValidSquare If the program throws this exception then there is a bug.
|
* @throws NotAValidSquare If the program throws this exception then there is a bug.
|
||||||
* @throws UnexpectedError This should never happen.
|
* @throws UnexpectedError This should never happen.
|
||||||
* @see Square
|
* @see Square
|
||||||
* @see Board
|
* @see Board
|
||||||
*/
|
*/
|
||||||
public static void legalMovesFromSquare(Square fromSquare, Board board) throws NotAValidSquare {
|
public static boolean isThereALegalMovesForPlayer(Board board) throws NotAValidSquare {
|
||||||
|
legalMovesNonCapture = new ArrayList<Move>();
|
||||||
|
legalMovesCapture = new ArrayList<Move>();
|
||||||
|
|
||||||
|
Square square;
|
||||||
|
for(int squareNb = 0; squareNb < Board.NB_OF_SQUARES; squareNb++) {
|
||||||
|
square = new Square(squareNb);
|
||||||
|
if (board.isEmpty(square, new Piece(board.getCurrentPlayer()))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((legalMovesNonCapture.size()!=0)||(legalMovesCapture.size()!=0)) {
|
||||||
|
return true; //found a legal move
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the possible moves from a given {@link Square}
|
||||||
|
* according to the current status of the {@link Board}
|
||||||
|
* @param fromSquare The square from which the move must start
|
||||||
|
* @param board The current board position.
|
||||||
|
* @param fast If this boolean is set to true then the program only searches if there is ONE legal move.
|
||||||
|
* @return boolean Stating if there is or not a legal move.
|
||||||
|
* @throws NotAValidSquare If the program throws this exception then there is a bug.
|
||||||
|
* @throws UnexpectedError This should never happen.
|
||||||
|
* @see Square
|
||||||
|
* @see Board
|
||||||
|
*/
|
||||||
|
private static void legalMovesFromSquare(Square fromSquare, Board board) throws NotAValidSquare {
|
||||||
Move validMove;
|
Move validMove;
|
||||||
Square toSquare;
|
Square toSquare;
|
||||||
Piece movingPiece = board.getPiece(fromSquare);
|
Piece movingPiece = board.getPiece(fromSquare);
|
||||||
|
@ -185,6 +185,11 @@ public class SuicideChess {
|
|||||||
case XBoardProtocol.NOPOST:
|
case XBoardProtocol.NOPOST:
|
||||||
post=false;
|
post=false;
|
||||||
break;
|
break;
|
||||||
|
case XBoardProtocol.SETBOARD:
|
||||||
|
bitboard=new Board(whatMove.substring(9));
|
||||||
|
if(ASCII_GAME)
|
||||||
|
bitboard.display();
|
||||||
|
break;
|
||||||
case XBoardProtocol.UNKNOWN:
|
case XBoardProtocol.UNKNOWN:
|
||||||
if (acceptedUsermove) {
|
if (acceptedUsermove) {
|
||||||
System.out.println("Error (unknown command): "+whatMove);
|
System.out.println("Error (unknown command): "+whatMove);
|
||||||
@ -316,5 +321,4 @@ public class SuicideChess {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -82,6 +82,10 @@ public class XBoardProtocol {
|
|||||||
* Xboard asks NOT to display thinking output
|
* Xboard asks NOT to display thinking output
|
||||||
*/
|
*/
|
||||||
public static final int NOPOST = 16;
|
public static final int NOPOST = 16;
|
||||||
|
/**
|
||||||
|
* XBoard changes the board position
|
||||||
|
*/
|
||||||
|
public static final int SETBOARD = 17;
|
||||||
/**
|
/**
|
||||||
* Unknown command
|
* Unknown command
|
||||||
*/
|
*/
|
||||||
@ -98,7 +102,7 @@ public class XBoardProtocol {
|
|||||||
System.out.println("feature myname=\"djib's Suicide Chess\"");
|
System.out.println("feature myname=\"djib's Suicide Chess\"");
|
||||||
System.out.println("feature sigint=0 sigterm=0"); //do not interrupt me
|
System.out.println("feature sigint=0 sigterm=0"); //do not interrupt me
|
||||||
System.out.println("feature variants=\"suicide\"");
|
System.out.println("feature variants=\"suicide\"");
|
||||||
System.out.println("feature ping=1");
|
System.out.println("feature ping=1 setboard=1");
|
||||||
System.out.println("feature time=0 draw=0 reuse=0 analyze=0 colors=0");
|
System.out.println("feature time=0 draw=0 reuse=0 analyze=0 colors=0");
|
||||||
System.out.println("feature done=1");
|
System.out.println("feature done=1");
|
||||||
if (SuicideChess.ASCII_GAME)
|
if (SuicideChess.ASCII_GAME)
|
||||||
@ -154,9 +158,10 @@ public class XBoardProtocol {
|
|||||||
return POST;
|
return POST;
|
||||||
} else if (command.equals("nopost")) {
|
} else if (command.equals("nopost")) {
|
||||||
return NOPOST;
|
return NOPOST;
|
||||||
|
} else if (command.startsWith("setboard")) {
|
||||||
|
return SETBOARD;
|
||||||
}
|
}
|
||||||
|
|
||||||
return UNKNOWN;
|
return UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user