Browse Source

Version 1.0.2

=============
Corrected a major but in move ordering
and a major bug in the evaluation function.
master
djib 15 years ago
parent
commit
9c4916fb1b
  1. 119
      src/suicideChess/Board.java
  2. 28
      src/suicideChess/ComputerPlayer.java
  3. 10
      src/suicideChess/MoveComparator.java
  4. 63
      src/suicideChess/Rules.java
  5. 30
      src/suicideChess/SuicideChess.java

119
src/suicideChess/Board.java

@ -92,8 +92,11 @@ public class Board {
private int[] numberOfPieces;
//the value of each piece (used for the evaluation function)
private int boardValue = 0; //evaluation of the board value
//boardValue
private int boardValue = 0; //= mobilityValue+pieceValue except for wining and draw positions
private int mobilityValue = 0;
private int pieceValue = 0;
private int currentPlayer; //color of the current player.
//starts at 1 and increment after each of black's move
@ -176,6 +179,9 @@ public class Board {
this.halfmoveClock = bitboard.halfmoveClock;
this.boardValue = bitboard.boardValue;
this.pieceValue = bitboard.pieceValue;
this.mobilityValue = bitboard.mobilityValue;
this.bitBoards = new long[NB_OF_BITBOARDS];
for (int i=0; i<NB_OF_BITBOARDS; i++) {
this.bitBoards[i] = bitboard.bitBoards[i];
@ -594,7 +600,6 @@ public class Board {
return Rules.getLegalMovesNonCapture().size()*ConfigFile.getPrimaryMobilityValueMidgame();
}
}
private void evaluateNewBoardValue (Move move) throws NotAValidSquare {
@ -603,41 +608,83 @@ public class Board {
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] > ConfigFile.getEndGamePawns()) && (numberOfPieces[Piece.WHITE_PAWN] > ConfigFile.getEndGamePawns())
&& (numberOfPieces[Piece.BLACK_PIECES] > ConfigFile.getEndGamePieces()) && (numberOfPieces[Piece.WHITE_PIECES] > ConfigFile.getEndGamePieces()) ) {
//System.out.println("Playing midgame");
/*for (int i = Piece.OFFSET; i<=Piece.MAX_PIECE_NUMBER; i++) {
boardValue += numberOfPieces[i]*Piece.PIECE_VALUE_MIDGAME[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 += ConfigFile.getSquareWeightMidgame()[squareNb]*
ConfigFile.getPieceValuesMidgame()[pieceOnSquare.getPieceNumber()];
}
}
boardValue += ((mobilityMidgame(Piece.WHITE)-mobilityMidgame(Piece.BLACK)));
}
}
//this is a very very basic evaluation function that will be changed.
//boardValue = numberOfBlackPieces - numberOfWhitePieces;
boardValue = 0;
if((numberOfPieces[Piece.BLACK_PAWN] > ConfigFile.getEndGamePawns()) && (numberOfPieces[Piece.WHITE_PAWN] > ConfigFile.getEndGamePawns())
&& (numberOfPieces[Piece.BLACK_PIECES] > ConfigFile.getEndGamePieces()) && (numberOfPieces[Piece.WHITE_PIECES] > ConfigFile.getEndGamePieces()) ) {
//System.out.println("Playing midgame");
/*for (int i = Piece.OFFSET; i<=Piece.MAX_PIECE_NUMBER; i++) {
boardValue += numberOfPieces[i]*Piece.PIECE_VALUE_MIDGAME[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 += ConfigFile.getSquareWeightMidgame()[squareNb]*
ConfigFile.getPieceValuesMidgame()[pieceOnSquare.getPieceNumber()];
}
}*/
//update the board value : remove the value of the square the piece comes from and add the value
//of the square the piece goes to
pieceValue += (
ConfigFile.getSquareWeightMidgame()[squareToBitBoardSquare(move.toSquare())]
- ConfigFile.getSquareWeightMidgame()[squareToBitBoardSquare(move.fromSquare())]
)*ConfigFile.getPieceValuesMidgame()[move.getMovingPiece().getPieceNumber()];
//if there is a capture also remove the value of the sqare the piece was captured
if (move.isCaptureMove()) {
if (move.isEnPassant()) {
pieceValue -= ConfigFile.getSquareWeightMidgame()[squareToBitBoardSquare(move.getEnPassantSquare())]
*ConfigFile.getPieceValuesMidgame()[move.getCapturedPiece().getPieceNumber()];
} else {
pieceValue -= ConfigFile.getSquareWeightMidgame()[squareToBitBoardSquare(move.toSquare())]
*ConfigFile.getPieceValuesMidgame()[move.getCapturedPiece().getPieceNumber()];
}
}
if(SuicideChess.USE_MOBILITY) {
mobilityValue = ((mobilityMidgame(Piece.WHITE)-mobilityMidgame(Piece.BLACK)));
}
boardValue = pieceValue + mobilityValue;
} else {
//System.out.println("Playing endgame");
/*for (int i = Piece.OFFSET; i<=Piece.MAX_PIECE_NUMBER; i++) {
boardValue += numberOfPieces[i]*Piece.PIECE_VALUE_ENDGAME[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 += ConfigFile.getSquareWeightEndgame()[squareNb]*
ConfigFile.getPieceValuesEndgame()[pieceOnSquare.getPieceNumber()];
}
}*/
pieceValue += (
ConfigFile.getSquareWeightEndgame()[squareToBitBoardSquare(move.toSquare())]
- ConfigFile.getSquareWeightEndgame()[squareToBitBoardSquare(move.fromSquare())]
)*ConfigFile.getPieceValuesEndgame()[move.getMovingPiece().getPieceNumber()];
if (move.isCaptureMove()) {
if (move.isEnPassant()) {
pieceValue -= ConfigFile.getSquareWeightEndgame()[squareToBitBoardSquare(move.getEnPassantSquare())]
*ConfigFile.getPieceValuesEndgame()[move.getCapturedPiece().getPieceNumber()];
} else {
//System.out.println("Playing endgame");
/*for (int i = Piece.OFFSET; i<=Piece.MAX_PIECE_NUMBER; i++) {
boardValue += numberOfPieces[i]*Piece.PIECE_VALUE_ENDGAME[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 += ConfigFile.getSquareWeightEndgame()[squareNb]*
ConfigFile.getPieceValuesEndgame()[pieceOnSquare.getPieceNumber()];
}
}
boardValue += ((mobilityEndgame(Piece.WHITE)-mobilityEndgame(Piece.BLACK)));
pieceValue -= ConfigFile.getSquareWeightMidgame()[squareToBitBoardSquare(move.toSquare())]
*ConfigFile.getPieceValuesEndgame()[move.getCapturedPiece().getPieceNumber()];
}
}
}
if(SuicideChess.USE_MOBILITY) {
mobilityValue = ((mobilityEndgame(Piece.WHITE)-mobilityEndgame(Piece.BLACK)));
}
boardValue = pieceValue + mobilityValue;
}
if (!Rules.isThereALegalMovesForPlayer(this)) {
if (currentPlayer==Piece.WHITE) {

28
src/suicideChess/ComputerPlayer.java

@ -175,6 +175,8 @@ public class ComputerPlayer {
}
}
thinkingBeginingTime = new Date();
nodesSearched=0;
//alpha beta pruning.
ReturnWrapper bestScore = AlphaBeta(bitboard, 0, SuicideChess.PRINCIPAL_VARIATION_FIRST
, maxDepth, Board.MIN_VALUE, Board.MAX_VALUE);
@ -300,7 +302,31 @@ public class ComputerPlayer {
String bestVariationSoFar="";
ReturnWrapper returnValue;
if (SuicideChess.MOVE_ORDERING) {
Collections.sort(allLegalMoves,new MoveCompare(bitboard));
/* DEBUG
if(currentDepth==0) {
String debug = "";
for (int i=0; i<allLegalMoves.size(); i++) {
Board bitboardCopy = new Board(bitboard);
bitboardCopy.doMove(allLegalMoves.get(i));
debug += allLegalMoves.get(i).toString()+bitboardCopy.getBoardValue()+" ";
}
System.out.println(debug);
}
*/
Collections.sort(allLegalMoves,new MoveCompare(bitboard));
/* DEBUG
if(currentDepth==0) {
String debug = "";
for (int i=0; i<allLegalMoves.size(); i++) {
Board bitboardCopy = new Board(bitboard);
bitboardCopy.doMove(allLegalMoves.get(i));
debug += allLegalMoves.get(i).toString()+bitboardCopy.getBoardValue()+" ";
}
System.out.println(debug);
}
*/
}
if (bitboard.getCurrentPlayer()==Piece.BLACK) {
bestScoreSoFar=Board.MAX_VALUE; //black tries to minimise

10
src/suicideChess/MoveComparator.java

@ -25,9 +25,11 @@ class MoveCompare implements Comparator<Move> {
public MoveCompare(Board bitboard) {
this.bitboard = bitboard;
if(this.bitboard.getCurrentPlayer()==Piece.BLACK) {
sortOrder= +1;
// low scores are considered "smaller" than high ones and thus will be first after ordering
sortOrder= -1;
} else {
sortOrder= -1;
// high scores are consideres "smaller" than low ones
sortOrder= +1;
}
}
@ -42,9 +44,9 @@ class MoveCompare implements Comparator<Move> {
} catch (NotAValidSquare e) {
e.printStackTrace();
}
if(oneBoardCopy.getBoardValue()>anotherBoardCopy.getBoardValue()) {
if(oneBoardCopy.getBoardValue()<anotherBoardCopy.getBoardValue()) {
return sortOrder;
} else if (oneBoardCopy.getBoardValue()>anotherBoardCopy.getBoardValue()) {
} else if (oneBoardCopy.getBoardValue()==anotherBoardCopy.getBoardValue()) {
return 0;
}
return -sortOrder;

63
src/suicideChess/Rules.java

@ -327,6 +327,69 @@ public class Rules {
} //end case
}
/**
* Computes the mobility of a piece on 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.
* @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
*/
/*public static int mobilityEndgame(Square fromSquare, Board board) throws NotAValidSquare {
legalMovesNonCapture = new ArrayList<Move>();
legalMovesCapture = new ArrayList<Move>();
legalMovesFromSquare(fromSquare,board);
int mobility;
if (legalMovesCapture.size()!=0) {
mobility = legalMovesCapture.size()*ConfigFile.getPrimaryMobilityValueEndgame()
+legalMovesNonCapture.size()*ConfigFile.getScondaryMobilityValueEndgame();
} else {
mobility = legalMovesNonCapture.size()*ConfigFile.getPrimaryMobilityValueEndgame();
}
if (board.getPiece(fromSquare).getColor()==Piece.BLACK) {
return -mobility;
} else {
return mobility;
}
}*/
/**
* Computes the mobility of a piece on 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.
* @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
*/
/*public static int mobilityMidgame(Square fromSquare, Board board) throws NotAValidSquare {
legalMovesNonCapture = new ArrayList<Move>();
legalMovesCapture = new ArrayList<Move>();
legalMovesFromSquare(fromSquare,board);
int mobility;
if (legalMovesCapture.size()!=0) {
mobility = legalMovesCapture.size()*ConfigFile.getPrimaryMobilityValueMidgame()
+legalMovesNonCapture.size()*ConfigFile.getPrimaryMobilityValueMidgame();
} else {
mobility = legalMovesNonCapture.size()*ConfigFile.getPrimaryMobilityValueMidgame();
}
if (board.getPiece(fromSquare).getColor()==Piece.BLACK) {
return -mobility;
} else {
return mobility;
}
}*/
/**
* This function return the current status of the ArrayList<Move> of all legal {@link Move}

30
src/suicideChess/SuicideChess.java

@ -34,6 +34,11 @@ public class SuicideChess {
*/
public static final boolean SQUARE_CHECK_INVALID = true;
/**
* Use mobility in evaluation function (slows the program down a lot)
*/
public static final boolean USE_MOBILITY = true;
/**
* do move ordering in Alpha-Beta pruning ?
*/
@ -74,7 +79,7 @@ public class SuicideChess {
/**
* Adaptative depth -> ie: when only one possible move, don't search. When very few moves, add one to depth.
*/
public static final boolean ADAPTATIVE_DEPTH = true;
public static final boolean ADAPTATIVE_DEPTH = false;
/**
* Adaptative branchin limit
@ -89,12 +94,12 @@ public class SuicideChess {
/**
* Try the primary variation from the earliest iteration first
*/
public static final boolean PRINCIPAL_VARIATION_FIRST = true;
public static final boolean PRINCIPAL_VARIATION_FIRST = false;
/**
* The name to be displayed
*/
public static final String NAME = "djib's SuShi v1.0.0";
public static final String NAME = "djib's SuShi v1.0.2";
/**
* Displays informations in the console.
@ -232,6 +237,7 @@ public class SuicideChess {
System.out.println("force\t\t\tthe computer will check moves but not play");
System.out.println();
System.out.println("board\t\t\tdisplays the current status of the board");
System.out.println("eval\t\t\tevaluates the current board position");
System.out.println("setboard FEN\t\tsets the board according to the FEN position");
System.out.println("sd N\t\t\tsets the search depth to n");
System.out.println("bk\t\t\tdisplays available openbook moves for current position");
@ -258,8 +264,11 @@ public class SuicideChess {
try {
int problemNb = Integer.parseInt(whatMove.substring(8));
bitboard=new Board(SuicideProblems.getProblemNumber(problemNb));
if(asciiGame)
if(asciiGame) {
bitboard.display();
displayPlayer(bitboard);
}
addPlayedPosition(bitboard);
} catch (NumberFormatException e) {
System.out.println("Not a valid number: "+ whatMove.substring(8));
}
@ -277,8 +286,10 @@ public class SuicideChess {
} else if (whatMove.startsWith("asciiplay")) {
asciiGame=false;
} else if ((whatMove.startsWith("board"))) {
bitboard.display();
} else {
bitboard.display();
} else if ((whatMove.startsWith("eval"))) {
System.out.println(bitboard.getBoardValue());
}else {
int xBoardCommand = XBoardProtocol.getCommand(whatMove);
switch (xBoardCommand) {
@ -314,8 +325,10 @@ public class SuicideChess {
OpeningBook.reset();
computerPlaying = true; //the computer does not play in foce mode.
if(playInACSII())
if(playInACSII()) {
bitboard.display();
displayPlayer(bitboard);
}
//System.out.println("variant suicide");
break;
case XBoardProtocol.HINT:
@ -334,6 +347,7 @@ public class SuicideChess {
bitboard=new Board(removePlayedPosition());
if (asciiGame) {
bitboard.display();
displayPlayer(bitboard);
}
openingPhase = false; //due to the way I implemented the opening book
break;
@ -345,9 +359,11 @@ public class SuicideChess {
break;
case XBoardProtocol.SETBOARD:
bitboard=new Board(whatMove.substring(9));
addPlayedPosition(bitboard);
openingPhase = false;
if(asciiGame)
bitboard.display();
displayPlayer(bitboard);
break;
case XBoardProtocol.SETPLY:
try{

Loading…
Cancel
Save