diff --git a/src/suicideChess/Board.java b/src/suicideChess/Board.java
index 5e04bd1..0288421 100644
--- a/src/suicideChess/Board.java
+++ b/src/suicideChess/Board.java
@@ -10,6 +10,9 @@ import suicideChess.Square.NotAValidSquare;
*
a2 is square 8
* ... and so on
*
+ * 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$
*
@@ -37,7 +40,17 @@ public class Board {
NoPieceOnSquare(String s) { super(s); };
}
-
+ /**
+ * Value returned by the evaluation function when White wins
+ */
+ public static final int WHITE_WINS = 99999;
+
+ /**
+ * Value returned by the evaluation function when Black wins
+ */
+ public static final int BLACK_WINS = -99999;
+
+
/*======*
* DATA *
*======*/
@@ -60,6 +73,9 @@ public class Board {
private boolean enPassant=false; //is there an 'en passant pawn' on the board
private Square enPassantSquare;
+ private int numberOfBlackPieces = NB_OF_FILES*2;
+ private int numberOfWhitePieces = NB_OF_FILES*2;
+ private int boardValue = 0; //evaluation of the board value
/*=============*
@@ -111,12 +127,29 @@ public class Board {
}
+ /**
+ * A constructor that simply copies a bitboard
+ * @param bitboard The bitboard to be copied
+ */
+
+ public Board(Board bitboard) {
+ this.numberOfBlackPieces = bitboard.numberOfBlackPieces;
+ this.numberOfWhitePieces = bitboard.numberOfWhitePieces;
+ this.boardValue = bitboard.boardValue;
+ this.bitBoards = new long[NB_OF_BITBOARDS];
+ for (int i=0; i allLegalMoves = Rules.getLegalMovesCapture();
@@ -39,8 +43,73 @@ public class ComputerPlayer {
return allLegalMoves.get(generator.nextInt(allLegalMoves.size()));
}
- throw new RuntimeException();
+ throw new RuntimeException("**Error** in doRandomMove");
}
+ /**
+ * Basic MinMax
+ * @param bitboard The bitboard
+ * @param color The color to play
+ * @return The best Move found
+ * @throws NotAValidSquare
+ * @throws NoPieceOnSquare
+ * @see Board
+ * @see Move
+ */
+ public Move doMinMaxMove(Board bitboard, int color) throws NotAValidSquare, NoPieceOnSquare {
+ bestMove = null;
+ MinMax(bitboard, color, 0);
+ return bestMove;
+ }
+
+
+ private int MinMax(Board bitboard, int color, int currentDepth) throws NotAValidSquare, NoPieceOnSquare {
+ if (currentDepth >= SuicideChess.PLY_DEPTH) {
+ return bitboard.getBoardValue();
+ }
+ Rules.legalMovesForPlayer(bitboard,color);
+ ArrayList allLegalMoves = Rules.getLegalMovesCapture();
+ if (allLegalMoves.size()==0) {
+ allLegalMoves = Rules.getLegalMovesNonCapture();
+ }
+ if (allLegalMoves.size()==0) {
+ if (color==Piece.BLACK) {
+ return Board.BLACK_WINS;
+ } else {
+ return Board.WHITE_WINS;
+ }
+ } else {
+ int bestMoveIndex=0;
+ int currentScore;
+ int bestScoreSoFar;
+ if (color==Piece.BLACK) {
+ bestScoreSoFar=Board.WHITE_WINS+1; //any move even a WHITE_WINS will be better than that
+ for (int i=0; i bestScoreSoFar) { //white tries to maximise his score
+ bestScoreSoFar = currentScore;
+ bestMoveIndex = i;
+ }
+ }
+ }
+ bestMove = allLegalMoves.get(bestMoveIndex);
+ return bestScoreSoFar;
+ }
+ }
+
+ private static Move bestMove = null;
}
\ No newline at end of file
diff --git a/src/suicideChess/Rules.java b/src/suicideChess/Rules.java
index 2238a38..3152acb 100644
--- a/src/suicideChess/Rules.java
+++ b/src/suicideChess/Rules.java
@@ -15,7 +15,7 @@ public class Rules {
private static ArrayList legalMovesNonCapture;
private static ArrayList legalMovesCapture;
-
+
// public class UnexpectedError extends Exception {
// /*
// * Generated by Eclipse
diff --git a/src/suicideChess/SuicideChess.java b/src/suicideChess/SuicideChess.java
index bafb6a9..709596d 100644
--- a/src/suicideChess/SuicideChess.java
+++ b/src/suicideChess/SuicideChess.java
@@ -33,13 +33,18 @@ public class SuicideChess {
/**
* The name to be displayed
*/
- public static final String NAME = "djib's SuicideChess v0.3 beta 2";
+ public static final String NAME = "djib's SuicideChess v0.4.1";
/**
* Displays informations in the console.
*/
public static final boolean ASCII_GAME = false;
-
+
+ /**
+ * Number of Plies the computes searches to
+ */
+ public static final int PLY_DEPTH = 5;
+
/**
* The color of the current player
*/
@@ -60,167 +65,200 @@ public class SuicideChess {
}
}
+ /**
+ * If feature usermove has not been accepted by XBoard then consider all unknown commands
+ * as moves
+ */
+ private static boolean acceptedUsermove = false;
+
/**
* The main function
* @param args No parameters should be transmitted to this function.
+ * @throws NotAValidSquare
*/
- public static void main(String[] args) {
+ public static void main(String[] args) throws NotAValidSquare {
+
+
+ System.out.println("Welcome to SuicideChess "+SuicideChess.NAME+"!");
+ if (!SuicideChess.ASCII_GAME) {
+ System.out.println("This game was not designed to be played in console. Please use it with XBoard, WinBoard or any compatible program.");
+ }
+ System.out.println();
+
+
+ BufferedReader moveInput = new BufferedReader(new InputStreamReader(System.in));
+ Board bitboard = new Board();
+
+ if (ASCII_GAME) {
+ bitboard.display();
+ System.out.println("White: ");
+ }
+
+ ComputerPlayer computer = new ComputerPlayer();
+ boolean computerPlaying = true; //the computer does not play in foce mode.
+
+ boolean playing = true;
+
+ while (playing) {
+ try {
+ String whatMove= moveInput.readLine();
+ boolean playedALegalMove = false;
- try {
-
- BufferedReader moveInput = new BufferedReader(new InputStreamReader(System.in));
- Board bitboard = new Board();
-
- if (ASCII_GAME) {
- bitboard.display();
- System.out.println("White: ");
- }
-
- ComputerPlayer computer = new ComputerPlayer();
-
- boolean playing = true;
-
- while (playing) {
- 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.NOT_ACCEPTED_USERMOVE:
- System.out.println("tellusererror \"XBoard must send moves starting with 'usermove'\"");
- playing=false;
- 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.UNKNOWN:
+ 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: "+computer.doRandomMove(bitboard,currentPlayerColor));
+ break;
+ case XBoardProtocol.FORCE:
+ computerPlaying = false;
+ break;
+ case XBoardProtocol.UNKNOWN:
+ if (acceptedUsermove) {
System.out.println("Error (unknown command): "+whatMove);
break;
- case XBoardProtocol.MOVE:
- Move theMove = new Move(whatMove.substring(9), bitboard);
-
- boolean needToCapture = false;
- int foundMoveIndex = -1;
- if(theMove.getMovingPiece().getColor() == currentPlayerColor) {
- Rules.legalMovesForPlayer(bitboard,currentPlayerColor);
- ArrayList 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));
- if (ASCII_GAME) {
- allLegalMoves.get(foundMoveIndex).display();
- bitboard.display();
- }
- playedALegalMove=true;
- }
+ }
+ //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 {
+ theMove = new Move(whatMove, bitboard);
+ }
+
+ boolean needToCapture = false;
+ int foundMoveIndex = -1;
+ if(theMove.getMovingPiece().getColor() == currentPlayerColor) {
+ Rules.legalMovesForPlayer(bitboard,currentPlayerColor);
+ ArrayList allLegalMoves = Rules.getLegalMovesCapture();
+ if (allLegalMoves.size()==0) {
+ allLegalMoves = Rules.getLegalMovesNonCapture();
} else {
- if (ASCII_GAME)
- System.out.println("Please play a piece of the right color.");
+ 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));
+ if (ASCII_GAME) {
+ allLegalMoves.get(foundMoveIndex).display();
+ System.out.println("Board value: "+bitboard.getBoardValue());
+ bitboard.display();
+ }
+ playedALegalMove=true;
}
-
- if (!playedALegalMove) {
- break;
- }
- changeCurrentPlayerColor();
- //No break statement here on purpose.
- case XBoardProtocol.GO:
- Move computerMove = computer.doMove(bitboard,currentPlayerColor);
+ } else {
+ if (ASCII_GAME)
+ System.out.println("Please play a piece of the right color.");
+ System.out.println("Illegal move: "+theMove.toString());
+ }
+
+ if (!playedALegalMove) {
+ break;
+ }
+ changeCurrentPlayerColor();
+ //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 (computerPlaying) {
+ Move computerMove = computer.doMinMaxMove(bitboard,currentPlayerColor);
bitboard.doMove(computerMove);
XBoardProtocol.doMove(computerMove);
if (ASCII_GAME) {
computerMove.display();
+ System.out.println("Board value: "+bitboard.getBoardValue());
bitboard.display();
}
changeCurrentPlayerColor();
-
- break;
-
- }
-
-// if (whatMove.startsWith("hint")) {
-// Rules rules = new Rules();
-// rules.legalMovesForPlayer(bitboard,currentPlayerColor);
-// ArrayList allLegalMoves = rules.getLegalMovesCapture();
-// if (allLegalMoves.size()==0) {
-// allLegalMoves = rules.getLegalMovesNonCapture();
-// }
-// for(int i = 0; i allLegalMoves = rules.getLegalMovesCapture();
+// if (allLegalMoves.size()==0) {
+// allLegalMoves = rules.getLegalMovesNonCapture();
+// }
+// for(int i = 0; i