Version 6.9
=========== Now detects draw (50 moves only) Displays time to find move Can read a library of problems from a file Each problem can be selected independently or all can be played in succession and then the result is displayed.
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
package suicideChess;
|
||||
|
||||
|
||||
import suicideChess.Square.NotAValidSquare;
|
||||
|
||||
/**
|
||||
@ -32,8 +33,11 @@ public class Board {
|
||||
private static final int NB_OF_BITBOARDS = 14;
|
||||
|
||||
//with less than that many pawns on one side, the computer will enter endgame mode
|
||||
public static final int ENDGAME = 3;
|
||||
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 = 6;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class NoPieceOnSquare extends Exception {
|
||||
NoPieceOnSquare(String s) { super(s); };
|
||||
@ -61,9 +65,12 @@ public class Board {
|
||||
* 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;
|
||||
|
||||
/*======*
|
||||
* DATA *
|
||||
*======*/
|
||||
@ -94,6 +101,11 @@ public class Board {
|
||||
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 *
|
||||
@ -108,6 +120,9 @@ public class Board {
|
||||
//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;
|
||||
@ -163,6 +178,9 @@ public class Board {
|
||||
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++) {
|
||||
@ -214,9 +232,16 @@ public class Board {
|
||||
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];
|
||||
numberOfPieces = new int[Piece.MAX_PIECE_NUMBER+1];
|
||||
|
||||
for(int split=0; split < 8; split++) {
|
||||
int offset=0;
|
||||
@ -262,12 +287,14 @@ public class Board {
|
||||
*/
|
||||
|
||||
public void doMove(Move move) throws NoPieceOnSquare, NotAValidSquare {
|
||||
if (move.isCaptureMove()) {
|
||||
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()) {
|
||||
@ -275,6 +302,9 @@ public class Board {
|
||||
} 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()) {
|
||||
@ -287,11 +317,12 @@ public class Board {
|
||||
//if (SuicideChess.ASCII_GAME)
|
||||
// System.out.println("Black: ");
|
||||
} else {
|
||||
fullmoveNumber++; //black has just played
|
||||
currentPlayer=Piece.WHITE;
|
||||
//if (SuicideChess.ASCII_GAME)
|
||||
// System.out.println("White: ");
|
||||
}
|
||||
|
||||
|
||||
evaluateNewBoardValue(move);
|
||||
}
|
||||
|
||||
@ -396,6 +427,24 @@ public class Board {
|
||||
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
|
||||
@ -543,13 +592,14 @@ public class Board {
|
||||
//this is a very very basic evaluation function that will be changed.
|
||||
//boardValue = numberOfBlackPieces - numberOfWhitePieces;
|
||||
boardValue = 0;
|
||||
if((numberOfPieces[Piece.BLACK_PAWN] <= ENDGAME) || (numberOfPieces[Piece.WHITE_PAWN] <= ENDGAME)) {
|
||||
System.out.println("Playing endgame");
|
||||
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");
|
||||
//System.out.println("Playing midgame");
|
||||
for (int i = Piece.OFFSET; i<=Piece.MAX_PIECE_NUMBER; i++) {
|
||||
boardValue += numberOfPieces[i]*Piece.PIECE_VALUE_MIDDLEGAME[i];
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package suicideChess;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Random;
|
||||
|
||||
import suicideChess.Board.NoPieceOnSquare;
|
||||
@ -138,9 +139,11 @@ public class ComputerPlayer {
|
||||
public static Move doAlphaBetaMove(Board bitboard) throws NotAValidSquare, NoPieceOnSquare {
|
||||
bestMove = null;
|
||||
nodesSearched = 0;
|
||||
|
||||
ReturnWrapper bestScore = AlphaBeta(bitboard, 0, Board.BLACK_WINS-1, Board.WHITE_WINS+1);
|
||||
|
||||
Date thinkingBeginingTime = new Date();
|
||||
ReturnWrapper bestScore = AlphaBeta(bitboard, 0, Board.BLACK_WINS-1, Board.WHITE_WINS+1);
|
||||
Date thinkingEndTime = new Date();
|
||||
|
||||
//select one of the best moves randomly
|
||||
Random generator = new Random();
|
||||
//if (currentDepth == 0) { System.out.println(bestMoveIndex.size()); }
|
||||
@ -149,7 +152,9 @@ public class ComputerPlayer {
|
||||
System.out.println("Found "+bestMoves.size()+" good moves.");
|
||||
|
||||
if (SuicideChess.postThinkingOutput()) {
|
||||
System.out.println(SuicideChess.PLY_DEPTH+" "+bestScore.getAlphaBeta()*100+" 0 "+nodesSearched+" "+bestMove);
|
||||
System.out.println(SuicideChess.PLY_DEPTH+" "+bestScore.getAlphaBeta()*100+
|
||||
" "+((int)(thinkingEndTime.getTime()-thinkingBeginingTime.getTime())/10)+ //search time in centiseconds
|
||||
" "+nodesSearched+" "+bestMove);
|
||||
}
|
||||
|
||||
return bestMove;
|
||||
@ -172,6 +177,10 @@ public class ComputerPlayer {
|
||||
};
|
||||
private static ReturnWrapper AlphaBeta(Board bitboard, int currentDepth, int alpha, int beta) throws NotAValidSquare, NoPieceOnSquare {
|
||||
nodesSearched++;
|
||||
|
||||
if(bitboard.isADraw()) {
|
||||
return new ReturnWrapper(Board.DRAW_BOARD,Board.DRAW_BOARD);
|
||||
}
|
||||
if (currentDepth >= SuicideChess.PLY_DEPTH) {
|
||||
//System.out.println("'-> Evaluate: "+bitboard.getBoardValue());
|
||||
return new ReturnWrapper(bitboard.getBoardValue(),bitboard.getBoardValue());
|
||||
@ -202,7 +211,7 @@ public class ComputerPlayer {
|
||||
|
||||
//System.out.println("Analysing "+currentDepth+":"+allLegalMoves.get(i));
|
||||
|
||||
ReturnWrapper returnValue = AlphaBeta(boardCopy,currentDepth+1,alpha,beta);
|
||||
ReturnWrapper returnValue = AlphaBeta(boardCopy,currentDepth+1,Board.MIN_VALUE,beta);
|
||||
currentScore = returnValue.getBranchValue();
|
||||
currentAlphaBeta = returnValue.getAlphaBeta();
|
||||
|
||||
@ -229,7 +238,7 @@ public class ComputerPlayer {
|
||||
}
|
||||
|
||||
if(beta<alpha) {
|
||||
//System.out.println("Pruning "+Integer.toString(allLegalMoves.size()-i)+" alternatives at depth "+ currentDepth);
|
||||
//if(currentDepth!=SuicideChess.PLY_DEPTH-1) System.out.println("Pruning "+Integer.toString(allLegalMoves.size()-i)+" alternatives at depth "+ currentDepth);
|
||||
return new ReturnWrapper(alpha,bestScoreSoFar); //pruning
|
||||
}
|
||||
}
|
||||
@ -242,7 +251,7 @@ public class ComputerPlayer {
|
||||
|
||||
//System.out.println("Analysing "+currentDepth+":"+allLegalMoves.get(i));
|
||||
|
||||
ReturnWrapper returnValue = AlphaBeta(boardCopy,currentDepth+1,alpha,beta);
|
||||
ReturnWrapper returnValue = AlphaBeta(boardCopy,currentDepth+1,alpha,Board.MAX_VALUE);
|
||||
currentScore = returnValue.getBranchValue();
|
||||
currentAlphaBeta = returnValue.getAlphaBeta();
|
||||
|
||||
@ -269,7 +278,7 @@ public class ComputerPlayer {
|
||||
}
|
||||
|
||||
if(alpha>beta) {
|
||||
//System.out.println("Pruning "+Integer.toString(allLegalMoves.size()-i)+" alternatives at depth "+ currentDepth);
|
||||
//if(currentDepth!=SuicideChess.PLY_DEPTH-1) System.out.println("Pruning "+Integer.toString(allLegalMoves.size()-i)+" alternatives at depth "+ currentDepth);
|
||||
return new ReturnWrapper(beta,bestScoreSoFar); //pruning
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,11 @@ import suicideChess.Square.NotAValidSquare;
|
||||
*/
|
||||
|
||||
public class Rules {
|
||||
|
||||
/**
|
||||
* Number of moves without a piece being capture or a pawn being moved before the game becomes a draw
|
||||
*/
|
||||
public static int NUMBER_OF_MOVES_BEFORE_DRAW=50;
|
||||
|
||||
private static ArrayList<Move> legalMovesNonCapture;
|
||||
private static ArrayList<Move> legalMovesCapture;
|
||||
|
@ -5,8 +5,11 @@ import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
||||
import suicideChess.Board.NoPieceOnSquare;
|
||||
import suicideChess.Board.UnableToParseFENStringException;
|
||||
import suicideChess.Move.NotAValidMoveException;
|
||||
import suicideChess.Square.NotAValidSquare;
|
||||
import suicideChess.SuicideProblems.NoSuchSuicideProblem;
|
||||
|
||||
/**
|
||||
* Main file (the game in itself)
|
||||
@ -33,7 +36,7 @@ public class SuicideChess {
|
||||
/**
|
||||
* The name to be displayed
|
||||
*/
|
||||
public static final String NAME = "djib's SuShi v0.5.5";
|
||||
public static final String NAME = "djib's SuShi v0.6.9";
|
||||
|
||||
/**
|
||||
* Displays informations in the console.
|
||||
@ -51,13 +54,16 @@ public class SuicideChess {
|
||||
* @return True or False
|
||||
*/
|
||||
|
||||
private static boolean testWinningPosition (Board bitboard) {
|
||||
private static boolean testAndDisplayIfWinningOrDrawPosition (Board bitboard) {
|
||||
if (bitboard.getBoardValue()==Board.BLACK_WINS) {
|
||||
System.out.println("0-1 {Black mates}");
|
||||
return true;
|
||||
} else if (bitboard.getBoardValue()==Board.WHITE_WINS) {
|
||||
System.out.println("1-0 {White mates}");
|
||||
return true;
|
||||
} else if (bitboard.isADraw()) {
|
||||
System.out.println("1/2-1/2 {Draw}");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -134,164 +140,184 @@ public class SuicideChess {
|
||||
try {
|
||||
String whatMove= moveInput.readLine();
|
||||
boolean playedALegalMove = false;
|
||||
|
||||
int xBoardCommand = XBoardProtocol.getCommand(whatMove);
|
||||
|
||||
switch (xBoardCommand) {
|
||||
case XBoardProtocol.XBOARD:
|
||||
break;
|
||||
case XBoardProtocol.PROTOVER:
|
||||
XBoardProtocol.initialise();
|
||||
break;
|
||||
case XBoardProtocol.NOT_ACCEPTED_SUICIDE:
|
||||
System.out.println("tellusererror \"This game only plays suicide chess.\"");
|
||||
playing=false;
|
||||
break;
|
||||
case XBoardProtocol.ACCEPTED_USERMOVE:
|
||||
acceptedUsermove=true;
|
||||
break;
|
||||
case XBoardProtocol.NOPROTOVER:
|
||||
System.out.println("tellusererror \"You must use an engine with XBoard protocol 2 or higher.\"");
|
||||
playing=false;
|
||||
break;
|
||||
case XBoardProtocol.QUIT:
|
||||
System.out.println("Goodbye!");
|
||||
playing=false;
|
||||
break;
|
||||
case XBoardProtocol.NEW:
|
||||
//System.out.println("variant suicide");
|
||||
break;
|
||||
case XBoardProtocol.HINT:
|
||||
System.out.println("Hint: "+ComputerPlayer.doRandomMove(bitboard));
|
||||
break;
|
||||
case XBoardProtocol.FORCE:
|
||||
computerPlaying = false;
|
||||
break;
|
||||
case XBoardProtocol.PING:
|
||||
System.out.println("pong "+whatMove.substring(5));
|
||||
break;
|
||||
case XBoardProtocol.REMOVE:
|
||||
removePlayedPosition();
|
||||
//no break here
|
||||
case XBoardProtocol.UNDO:
|
||||
bitboard=new Board(removePlayedPosition());
|
||||
if (ASCII_GAME) {
|
||||
bitboard.display();
|
||||
}
|
||||
break;
|
||||
case XBoardProtocol.POST:
|
||||
post=true;
|
||||
break;
|
||||
case XBoardProtocol.NOPOST:
|
||||
post=false;
|
||||
break;
|
||||
case XBoardProtocol.SETBOARD:
|
||||
bitboard=new Board(whatMove.substring(9));
|
||||
if(ASCII_GAME)
|
||||
bitboard.display();
|
||||
break;
|
||||
case XBoardProtocol.UNKNOWN:
|
||||
if (acceptedUsermove) {
|
||||
System.out.println("Error (unknown command): "+whatMove);
|
||||
break;
|
||||
}
|
||||
//if XBoard did not accept usermove command we try and interpret every unknown command
|
||||
//as a move.
|
||||
case XBoardProtocol.MOVE:
|
||||
Move theMove;
|
||||
if (acceptedUsermove) {
|
||||
theMove = new Move(whatMove.substring(9), bitboard);
|
||||
if (whatMove.startsWith("problem")) { //special case for problems
|
||||
if(whatMove.length()==7) {
|
||||
System.out.println("There are "+SuicideProblems.numberOfProblems()+" problems.");
|
||||
} else if (whatMove.substring(8).equals("auto")) {
|
||||
autoProblem();
|
||||
} else if ((whatMove.length()>=12)&&(whatMove.substring(8,12).equals("load"))) {
|
||||
SuicideProblems.suicideProblemsLoad(whatMove.substring(13));
|
||||
} else {
|
||||
theMove = new Move(whatMove, bitboard);
|
||||
try {
|
||||
int problemNb = Integer.parseInt(whatMove.substring(8));
|
||||
bitboard=new Board(SuicideProblems.getProblemNumber(problemNb));
|
||||
if(ASCII_GAME)
|
||||
bitboard.display();
|
||||
} catch (NumberFormatException e) {
|
||||
System.out.println("Not a valid number: "+ whatMove.substring(8));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int xBoardCommand = XBoardProtocol.getCommand(whatMove);
|
||||
|
||||
if (testWinningPosition(bitboard)) {
|
||||
//if board was set in an illegal position
|
||||
System.out.println("Illegal move: "+theMove.toString());
|
||||
switch (xBoardCommand) {
|
||||
case XBoardProtocol.XBOARD:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
boolean needToCapture = false;
|
||||
int foundMoveIndex = -1;
|
||||
if(theMove.getMovingPiece().getColor() == bitboard.getCurrentPlayer()) {
|
||||
Rules.legalMovesForPlayer(bitboard);
|
||||
ArrayList<Move> allLegalMoves = Rules.getLegalMovesCapture();
|
||||
if (allLegalMoves.size()==0) {
|
||||
allLegalMoves = Rules.getLegalMovesNonCapture();
|
||||
case XBoardProtocol.PROTOVER:
|
||||
XBoardProtocol.initialise();
|
||||
break;
|
||||
case XBoardProtocol.NOT_ACCEPTED_SUICIDE:
|
||||
System.out.println("tellusererror \"This game only plays suicide chess.\"");
|
||||
playing=false;
|
||||
break;
|
||||
case XBoardProtocol.ACCEPTED_USERMOVE:
|
||||
acceptedUsermove=true;
|
||||
break;
|
||||
case XBoardProtocol.NOPROTOVER:
|
||||
System.out.println("tellusererror \"You must use an engine with XBoard protocol 2 or higher.\"");
|
||||
playing=false;
|
||||
break;
|
||||
case XBoardProtocol.QUIT:
|
||||
System.out.println("Goodbye!");
|
||||
playing=false;
|
||||
break;
|
||||
case XBoardProtocol.NEW:
|
||||
//System.out.println("variant suicide");
|
||||
break;
|
||||
case XBoardProtocol.HINT:
|
||||
System.out.println("Hint: "+ComputerPlayer.doRandomMove(bitboard));
|
||||
break;
|
||||
case XBoardProtocol.FORCE:
|
||||
computerPlaying = false;
|
||||
break;
|
||||
case XBoardProtocol.PING:
|
||||
System.out.println("pong "+whatMove.substring(5));
|
||||
break;
|
||||
case XBoardProtocol.REMOVE:
|
||||
removePlayedPosition();
|
||||
//no break here
|
||||
case XBoardProtocol.UNDO:
|
||||
bitboard=new Board(removePlayedPosition());
|
||||
if (ASCII_GAME) {
|
||||
bitboard.display();
|
||||
}
|
||||
break;
|
||||
case XBoardProtocol.POST:
|
||||
post=true;
|
||||
break;
|
||||
case XBoardProtocol.NOPOST:
|
||||
post=false;
|
||||
break;
|
||||
case XBoardProtocol.SETBOARD:
|
||||
bitboard=new Board(whatMove.substring(9));
|
||||
if(ASCII_GAME)
|
||||
bitboard.display();
|
||||
break;
|
||||
case XBoardProtocol.UNKNOWN:
|
||||
if (acceptedUsermove) {
|
||||
System.out.println("Error (unknown command): "+whatMove);
|
||||
break;
|
||||
}
|
||||
//if XBoard did not accept usermove command we try and interpret every unknown command
|
||||
//as a move.
|
||||
case XBoardProtocol.MOVE:
|
||||
Move theMove;
|
||||
if (acceptedUsermove) {
|
||||
theMove = new Move(whatMove.substring(9), bitboard);
|
||||
} else {
|
||||
needToCapture = true;
|
||||
theMove = new Move(whatMove, bitboard);
|
||||
}
|
||||
for (int moveIndex = 0; moveIndex < allLegalMoves.size(); moveIndex++) {
|
||||
if (allLegalMoves.get(moveIndex).isSimpleEqual(theMove)) {
|
||||
if(theMove.isPromotionMove()&&
|
||||
theMove.getPromotionPiece().getPieceNumber()!=allLegalMoves.get(moveIndex).getPromotionPiece().getPieceNumber()) {
|
||||
continue;
|
||||
}
|
||||
foundMoveIndex=moveIndex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (foundMoveIndex == -1) {
|
||||
if (needToCapture) {
|
||||
if (ASCII_GAME)
|
||||
System.out.println("Capturing is mandatory.");
|
||||
}
|
||||
|
||||
if (testAndDisplayIfWinningOrDrawPosition(bitboard)) {
|
||||
//if board was set in an illegal position
|
||||
System.out.println("Illegal move: "+theMove.toString());
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
boolean needToCapture = false;
|
||||
int foundMoveIndex = -1;
|
||||
if(theMove.getMovingPiece().getColor() == bitboard.getCurrentPlayer()) {
|
||||
Rules.legalMovesForPlayer(bitboard);
|
||||
ArrayList<Move> allLegalMoves = Rules.getLegalMovesCapture();
|
||||
if (allLegalMoves.size()==0) {
|
||||
allLegalMoves = Rules.getLegalMovesNonCapture();
|
||||
} else {
|
||||
needToCapture = true;
|
||||
}
|
||||
for (int moveIndex = 0; moveIndex < allLegalMoves.size(); moveIndex++) {
|
||||
if (allLegalMoves.get(moveIndex).isSimpleEqual(theMove)) {
|
||||
if(theMove.isPromotionMove()&&
|
||||
theMove.getPromotionPiece().getPieceNumber()!=allLegalMoves.get(moveIndex).getPromotionPiece().getPieceNumber()) {
|
||||
continue;
|
||||
}
|
||||
foundMoveIndex=moveIndex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (foundMoveIndex == -1) {
|
||||
if (needToCapture) {
|
||||
if (ASCII_GAME)
|
||||
System.out.println("Capturing is mandatory.");
|
||||
}
|
||||
System.out.println("Illegal move: "+theMove.toString());
|
||||
} else {
|
||||
bitboard.doMove(allLegalMoves.get(foundMoveIndex));
|
||||
addPlayedPosition(bitboard);
|
||||
if (ASCII_GAME) {
|
||||
allLegalMoves.get(foundMoveIndex).display();
|
||||
System.out.println("Board value: "+bitboard.getBoardValue());
|
||||
bitboard.display();
|
||||
}
|
||||
playedALegalMove=true;
|
||||
}
|
||||
} else {
|
||||
bitboard.doMove(allLegalMoves.get(foundMoveIndex));
|
||||
addPlayedPosition(bitboard);
|
||||
if (ASCII_GAME)
|
||||
System.out.println("Please play a piece of the right color.");
|
||||
System.out.println("Illegal move: "+theMove.toString());
|
||||
}
|
||||
|
||||
if (testAndDisplayIfWinningOrDrawPosition(bitboard)) {
|
||||
computerPlaying=false;
|
||||
}
|
||||
|
||||
if (!playedALegalMove) {
|
||||
break;
|
||||
}
|
||||
//No break statement here on purpose.
|
||||
case XBoardProtocol.GO:
|
||||
//this is not really nice but it avoids having to write twice the code
|
||||
//I check if I did really receive a XBoardProtocol.GO or it I just got there
|
||||
//because there is no break statement.
|
||||
if (xBoardCommand==XBoardProtocol.GO)
|
||||
computerPlaying = true;
|
||||
|
||||
if (testAndDisplayIfWinningOrDrawPosition(bitboard)) {
|
||||
//in case an illegal position have been sent
|
||||
computerPlaying=false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (computerPlaying) {
|
||||
Move computerMove = ComputerPlayer.doAlphaBetaMove(bitboard);
|
||||
bitboard.doMove(computerMove);
|
||||
addPlayedPosition(bitboard);
|
||||
XBoardProtocol.doMove(computerMove);
|
||||
if (ASCII_GAME) {
|
||||
allLegalMoves.get(foundMoveIndex).display();
|
||||
computerMove.display();
|
||||
System.out.println("Board value: "+bitboard.getBoardValue());
|
||||
bitboard.display();
|
||||
}
|
||||
playedALegalMove=true;
|
||||
}
|
||||
|
||||
if (testAndDisplayIfWinningOrDrawPosition(bitboard)) {
|
||||
computerPlaying=false;
|
||||
}
|
||||
} else {
|
||||
if (ASCII_GAME)
|
||||
System.out.println("Please play a piece of the right color.");
|
||||
System.out.println("Illegal move: "+theMove.toString());
|
||||
}
|
||||
|
||||
if (testWinningPosition(bitboard)) {
|
||||
computerPlaying=false;
|
||||
}
|
||||
|
||||
if (!playedALegalMove) {
|
||||
|
||||
break;
|
||||
}
|
||||
//No break statement here on purpose.
|
||||
case XBoardProtocol.GO:
|
||||
//this is not really nice but it avoids having to write twice the code
|
||||
//I check if I did really receive a XBoardProtocol.GO or it I just got there
|
||||
//because there is no break statement.
|
||||
if (xBoardCommand==XBoardProtocol.GO)
|
||||
computerPlaying = true;
|
||||
|
||||
if (testWinningPosition(bitboard)) {
|
||||
//in case an illegal position have been sent
|
||||
computerPlaying=false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (computerPlaying) {
|
||||
Move computerMove = ComputerPlayer.doAlphaBetaMove(bitboard);
|
||||
bitboard.doMove(computerMove);
|
||||
addPlayedPosition(bitboard);
|
||||
XBoardProtocol.doMove(computerMove);
|
||||
if (ASCII_GAME) {
|
||||
computerMove.display();
|
||||
System.out.println("Board value: "+bitboard.getBoardValue());
|
||||
bitboard.display();
|
||||
}
|
||||
}
|
||||
|
||||
if (testWinningPosition(bitboard)) {
|
||||
computerPlaying=false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// if (whatMove.startsWith("hint")) {
|
||||
@ -330,10 +356,39 @@ public class SuicideChess {
|
||||
} catch (NotAValidSquare err) {
|
||||
System.out.println(err);
|
||||
continue;
|
||||
} catch (NoSuchSuicideProblem err) {
|
||||
System.out.println(err);
|
||||
continue;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//lets the computer try every problem and stop on error.
|
||||
//in the end it says what games where lost by white.
|
||||
private static void autoProblem() throws NotAValidSquare, UnableToParseFENStringException, NoPieceOnSquare, NoSuchSuicideProblem {
|
||||
Board bitboard;
|
||||
boolean[] result=new boolean[SuicideProblems.numberOfProblems()];
|
||||
for(int i=1; i<=SuicideProblems.numberOfProblems(); i++) {
|
||||
System.out.println("\n\nProblem "+i);
|
||||
bitboard=new Board(SuicideProblems.getProblemNumber(i));
|
||||
while(!testAndDisplayIfWinningOrDrawPosition(bitboard)) {
|
||||
Move computerMove = ComputerPlayer.doAlphaBetaMove(bitboard);
|
||||
bitboard.doMove(computerMove);
|
||||
}
|
||||
if (bitboard.getCurrentPlayer()==Piece.BLACK) {
|
||||
result[i-1]=false;
|
||||
} else {
|
||||
result[i-1]=true;
|
||||
}
|
||||
}
|
||||
System.out.println("\n\nLost following games:\n========begin========");
|
||||
for(int i=1; i<=SuicideProblems.numberOfProblems(); i++) {
|
||||
if (!result[i-1])
|
||||
System.out.println("Problem "+i+" lost !");
|
||||
}
|
||||
System.out.println("=========end=========");
|
||||
}
|
||||
}
|
89
src/suicideChess/SuicideProblems.java
Normal file
89
src/suicideChess/SuicideProblems.java
Normal file
@ -0,0 +1,89 @@
|
||||
package suicideChess;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
|
||||
public class SuicideProblems {
|
||||
/**
|
||||
* This class is used to load problems from a file
|
||||
*
|
||||
* @author Jean-Baptiste Hétier
|
||||
* @version $LastChangedRevision$, $LastChangedDate$
|
||||
*
|
||||
*/
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class NoSuchSuicideProblem extends Exception {
|
||||
NoSuchSuicideProblem(String s) { super(s); };
|
||||
}
|
||||
|
||||
|
||||
//This array can hold setup for different problems.
|
||||
private static String[] suicideProblems;
|
||||
static { suicideProblemsLoad("problems"); } //initialise with file 'problems' if found in current directory
|
||||
|
||||
/**
|
||||
* How many problems are loaded
|
||||
*/
|
||||
public static int numberOfProblems() {
|
||||
if (suicideProblems[0].equals("")) {
|
||||
return 0;
|
||||
} else {
|
||||
return suicideProblems.length;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return FEN notation string for given problem number
|
||||
* @param problemNb
|
||||
* @throws NoSuchSuicideProblem
|
||||
*/
|
||||
public static String getProblemNumber(int problemNb) throws NoSuchSuicideProblem {
|
||||
if ((problemNb > numberOfProblems())||(problemNb<1)) {
|
||||
throw new NoSuchSuicideProblem("*** Invalid Entry: "+problemNb+" ***");
|
||||
}
|
||||
return suicideProblems[problemNb-1];
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is used to load other problem files
|
||||
* @param file
|
||||
*/
|
||||
public static void suicideProblemsLoad(String file) {
|
||||
StringBuffer problemBuffer = new StringBuffer();
|
||||
//declared here only to make visible to finally clause
|
||||
BufferedReader problemReader = null;
|
||||
try {
|
||||
problemReader = new BufferedReader(new FileReader(file));
|
||||
String line = null; //not declared within while loop
|
||||
while ((line = problemReader.readLine()) != null) {
|
||||
if (!line.startsWith("#")) { //ignore lines starting with # (comments)
|
||||
problemBuffer.append(line);
|
||||
problemBuffer.append("\n"); //I will then use this symbol to break the buffer in an array
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException e) {
|
||||
System.out.println("File '"+file+"' not found. Problems won't be available.");
|
||||
}
|
||||
catch (IOException e){
|
||||
System.out.println("Error reading file '"+file+"'.");
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
if (problemReader!= null) {
|
||||
problemReader.close();
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
suicideProblems = problemBuffer.toString().split("\n");
|
||||
System.out.println(numberOfProblems()+" loaded");
|
||||
}
|
||||
|
||||
|
||||
}
|
Reference in New Issue
Block a user