diff --git a/src/suicideChess/Board.java b/src/suicideChess/Board.java index 000b67f..6965830 100644 --- a/src/suicideChess/Board.java +++ b/src/suicideChess/Board.java @@ -188,7 +188,6 @@ public class Board { /** * 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 @@ -571,7 +570,7 @@ public class Board { } //calculates player's mobility in the endgame - private int mobilityEnd(int colour) throws NotAValidSquare { + private int mobilityEndgame(int colour) throws NotAValidSquare { Board thisCopy = new Board(this); thisCopy.currentPlayer=colour; Rules.legalMovesForPlayer(thisCopy); @@ -584,7 +583,7 @@ public class Board { } //calculates player's mobility in the midgame - public int mobilityMiddle(int colour) throws NotAValidSquare { + private int mobilityMidgame(int colour) throws NotAValidSquare { Board thisCopy = new Board(this); thisCopy.currentPlayer=colour; Rules.legalMovesForPlayer(thisCopy); @@ -608,8 +607,22 @@ 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] <= ConfigFile.getEndGamePawns()) || (numberOfPieces[Piece.WHITE_PAWN] <= ConfigFile.getEndGamePawns()) - || (numberOfPieces[Piece.BLACK_PIECES] <= ConfigFile.getEndGamePieces()) || (numberOfPieces[Piece.WHITE_PIECES] <= ConfigFile.getEndGamePieces()) ) { + 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 bestMoves=new ArrayList(); + //private static Move[] killerMoves = new Move[SuicideChess.KILLER_SIZE]; //killer + private static Move[] principalVariation; + /** * Alpha-Beta * @param bitboard The bitboard @@ -145,6 +158,7 @@ public class ComputerPlayer { thinkingBeginingTime = new Date(); quiescenceSearch = false; + adaptativeDepth = false; extraSymbol = ""; principalVariation=new Move[0]; @@ -153,15 +167,18 @@ public class ComputerPlayer { if(maxDepth==SuicideChess.getPlyDepth()) { if(SuicideChess.QUIESCENCE_SEARCH) { quiescenceSearch = true; //don't do quiescence search till the last level of iterative deepening - extraSymbol = "+"; + extraSymbol = "+"; //display extra symbol in the thinking output } if(SuicideChess.ADAPTATIVE_DEPTH) { adaptativeDepth = true; //don't do adaptative search till the last level of iterative deepening - extraSymbol = "+"; + extraSymbol = "+"; //display extra symbol in the thinking output } } + + //alpha beta pruning. ReturnWrapper bestScore = AlphaBeta(bitboard, 0, SuicideChess.PRINCIPAL_VARIATION_FIRST , maxDepth, Board.MIN_VALUE, Board.MAX_VALUE); + Date thinkingEndTime = new Date(); //select one of the best moves randomly @@ -170,12 +187,12 @@ public class ComputerPlayer { bestMove = bestMoves.get(generator.nextInt(bestMoves.size())); if (SuicideChess.postThinkingOutput()) { - System.out.println(maxDepth+extraSymbol+"\t"+bestScore.getBranchValue()+ "\t"+((int)(thinkingEndTime.getTime()-thinkingBeginingTime.getTime())/10)+ //search time in centiseconds "\t"+nodesSearched+"\t"+bestScore.getPrincipalVariation()); } + //if found a win for black or white. if((bitboard.getCurrentPlayer()==Piece.BLACK && bestScore.getBranchValue()==Board.BLACK_WINS) || (bitboard.getCurrentPlayer()==Piece.WHITE @@ -184,17 +201,21 @@ public class ComputerPlayer { } if(SuicideChess.PRINCIPAL_VARIATION_FIRST) { + //parsing the principal variation to be able to analyse it first String principalVariationString[] = bestScore.getPrincipalVariation().split("\\s"); principalVariation = new Move[principalVariationString.length]; Board playing; //need to update bitboard to be able to generate moves playing = new Board(bitboard); for (int i = 0; i < principalVariationString.length; i++) { + //playing.display(); + //System.out.println(principalVariationString[i]); principalVariation[i] = new Move(principalVariationString[i],playing); playing.doMove(principalVariation[i]); } } } + if(SuicideChess.playInACSII()) { System.out.println("Found "+bestMoves.size()+" good moves."); } @@ -203,16 +224,6 @@ public class ComputerPlayer { } - private static boolean quiescenceSearch; //this will be used to determine is quiescence search is needed. - private static boolean adaptativeDepth; //this will - private static String extraSymbol=""; //display an extra symbol after the depth in the output if doing either quiescence search or adaptative depth - - private static Date thinkingBeginingTime; - private static int maxDepth; - private static ArrayList bestMoves=new ArrayList(); - //private static Move[] killerMoves = new Move[SuicideChess.KILLER_SIZE]; //killer - private static Move[] principalVariation; - //this class is used to return two arguments in the next function, the two arguments being //an integer representing the value of alpha or beta //an integer representing the real value of the branch (alpha-beta only give boundaries) @@ -229,8 +240,11 @@ public class ComputerPlayer { public int getBranchValue() {return this.branchValue;} public String getPrincipalVariation() {return this.principalVariation;} }; + + //Alpha beta. private static ReturnWrapper AlphaBeta(Board bitboard, int currentDepth, boolean inPrincipalVariation, int currentMaxDepth, int alpha, int beta) throws NotAValidSquare, NoPieceOnSquare { nodesSearched++; + if(bitboard.isADraw()) { return new ReturnWrapper(Board.DRAW_BOARD,Board.DRAW_BOARD,""); } @@ -239,25 +253,27 @@ public class ComputerPlayer { //System.out.println("'-> Evaluate: "+bitboard.getBoardValue()); return new ReturnWrapper(bitboard.getBoardValue(),bitboard.getBoardValue(),""); } + + //generate legal moves. Rules.legalMovesForPlayer(bitboard); ArrayList allLegalMoves = Rules.getLegalMovesCapture(); - if (allLegalMoves.size()==0) { + if (allLegalMoves.size()==0) { //if no capture moves if((quiescenceSearch) && (currentDepth >= currentMaxDepth)) { //System.out.println("'-> Evaluate: "+bitboard.getBoardValue()); - return new ReturnWrapper(bitboard.getBoardValue(),bitboard.getBoardValue(),""); + return new ReturnWrapper(bitboard.getBoardValue(),bitboard.getBoardValue(),""); //position is quiet } allLegalMoves = Rules.getLegalMovesNonCapture(); - } else { //if there are captures, see if we can just abandon search here + } else { boolean changedMaxDepth = false; //to make sure that quiescence and adaptative don't interfere if((quiescenceSearch) && (currentDepth >= currentMaxDepth)) { if((currentMaxDepth Evaluate *BLACK WINS*: "+Board.BLACK_WINS); return new ReturnWrapper(Board.BLACK_WINS,Board.BLACK_WINS,""); @@ -295,22 +311,24 @@ public class ComputerPlayer { continue; } else { boardCopy.doMove(principalVariation[currentDepth]); + //System.out.println(i+"bdoingMove"+currentDepth+" "+principalVariation[currentDepth]); returnValue = AlphaBeta(boardCopy,currentDepth+1,true,currentMaxDepth,Board.MIN_VALUE,beta); } } else { //and then don't do it again. - if(SuicideChess.PRINCIPAL_VARIATION_FIRST && (principalVariation.length > currentDepth)) { + if(inPrincipalVariation && (principalVariation.length > currentDepth)) { if(principalVariation[currentDepth].isSimpleEqualTo(allLegalMoves.get(i))) { continue; } } boardCopy.doMove(allLegalMoves.get(i)); + //System.out.println(i+"bdoingMove"+currentDepth+" "+allLegalMoves.get(i)); returnValue = AlphaBeta(boardCopy,currentDepth+1,false,currentMaxDepth,Board.MIN_VALUE,beta); } - //System.out.println("Analysing "+currentDepth+":"+allLegalMoves.get(i)); currentScore = returnValue.getBranchValue(); + //if(currentDepth==0 || currentDepth==1) System.out.println(returnValue.getPrincipalVariation()+" "+currentScore); currentAlphaBeta = returnValue.getAlphaBeta(); //System.out.println("| CurrentScore, BestScore:" + currentScore + ", " + bestScoreSoFar); @@ -324,6 +342,7 @@ public class ComputerPlayer { if (currentScore <= bestScoreSoFar) { if (currentScore < bestScoreSoFar) { bestScoreSoFar=currentScore; + //System.out.println(i+" "+currentScore+" "+bestScoreSoFar); if (i!=-1) { bestVariationSoFar = allLegalMoves.get(i).toString()+" "+returnValue.getPrincipalVariation(); } else { @@ -373,22 +392,24 @@ public class ComputerPlayer { continue; } else { boardCopy.doMove(principalVariation[currentDepth]); + //System.out.println(i+"wdoingMove"+currentDepth+" "+principalVariation[currentDepth]); returnValue = AlphaBeta(boardCopy,currentDepth+1,true,currentMaxDepth,alpha,Board.MAX_VALUE); } } else { //and then don't do it again. - if(SuicideChess.PRINCIPAL_VARIATION_FIRST && (principalVariation.length > currentDepth)) { + if(inPrincipalVariation && (principalVariation.length > currentDepth)) { if(principalVariation[currentDepth].isSimpleEqualTo(allLegalMoves.get(i))) { continue; } } boardCopy.doMove(allLegalMoves.get(i)); + //System.out.println(i+"wdoingMove"+currentDepth+" "+allLegalMoves.get(i)+" "+nodesSearched); returnValue = AlphaBeta(boardCopy,currentDepth+1,false,currentMaxDepth,alpha,Board.MAX_VALUE); } //System.out.println("Analysing "+currentDepth+":"+allLegalMoves.get(i)); - currentScore = returnValue.getBranchValue(); + //if(currentDepth==0 || currentDepth==1) System.out.println(returnValue.getPrincipalVariation()+" "+currentScore); currentAlphaBeta = returnValue.getAlphaBeta(); //System.out.println("| CurrentScore, BestScore:" + currentScore + ", " + bestScoreSoFar); @@ -399,9 +420,11 @@ public class ComputerPlayer { alpha = currentAlphaBeta; } //calculating branch value + if (currentScore >= bestScoreSoFar) { if (currentScore > bestScoreSoFar) { bestScoreSoFar=currentScore; + //System.out.println(i+" "+currentScore+" "+bestScoreSoFar); if (i!=-1) { bestVariationSoFar = allLegalMoves.get(i).toString()+" "+returnValue.getPrincipalVariation(); } else { diff --git a/src/suicideChess/OpeningBook.java b/src/suicideChess/OpeningBook.java index 8462a09..b4749d2 100644 --- a/src/suicideChess/OpeningBook.java +++ b/src/suicideChess/OpeningBook.java @@ -99,7 +99,7 @@ public class OpeningBook { /** * Returns a move from the book if available, given a bitboard. * @param bitboard - * @return + * @return A Move * @throws NotAValidMoveException * @throws NotAValidSquare * @throws NoOpeningMovesLeft diff --git a/src/suicideChess/SuicideChess.java b/src/suicideChess/SuicideChess.java index 7ea1fc8..3b3c871 100644 --- a/src/suicideChess/SuicideChess.java +++ b/src/suicideChess/SuicideChess.java @@ -58,7 +58,7 @@ public class SuicideChess { /** * Quiescence search -> don't evaluate if captures are possible. */ - public static final boolean QUIESCENCE_SEARCH = true; + public static final boolean QUIESCENCE_SEARCH = false; /** * Quiescence limit (ie. if more than that many possibilities of capturing, don't analyse further. @@ -79,7 +79,7 @@ public class SuicideChess { /** * Adaptative branchin limit */ - public static final int ADAPTATIVE_BRANCHING_LIMIT = 3; + public static final int ADAPTATIVE_BRANCHING_LIMIT = 2; ///** // * Killer size (nb of killer moves remembered) @@ -94,7 +94,7 @@ public class SuicideChess { /** * The name to be displayed */ - public static final String NAME = "djib's SuShi v0.9.2"; + public static final String NAME = "djib's SuShi v1.0.0"; /** * Displays informations in the console.