diff --git a/Sources/Bitboard/src/bagaturchess/bitboard/impl1/internal/MoveGenerator.java b/Sources/Bitboard/src/bagaturchess/bitboard/impl1/internal/MoveGenerator.java index ef4754c9..6a9e4659 100644 --- a/Sources/Bitboard/src/bagaturchess/bitboard/impl1/internal/MoveGenerator.java +++ b/Sources/Bitboard/src/bagaturchess/bitboard/impl1/internal/MoveGenerator.java @@ -14,6 +14,7 @@ import java.util.Random; import bagaturchess.bitboard.common.Properties; +import bagaturchess.bitboard.impl.utils.VarStatistic; public final class MoveGenerator { @@ -42,6 +43,10 @@ public final class MoveGenerator { private final ContinuationHistory[] HH_ContinuationHistory = new ContinuationHistory[2]; private final ContinuationHistory[] BF_ContinuationHistory = new ContinuationHistory[2]; + private final int[][] LMR_ALL = new int[2][64 * 64]; + private final int[][] LMR_ABOVE_ALPHA = new int[2][64 * 64]; + private static int LMR_STAT_MULTIPLIER = 1000; + private Random randomizer = new Random(); private long randomizer_counter; @@ -66,6 +71,10 @@ public void clearHistoryHeuristics() { Arrays.fill(HH_MOVES[BLACK], 0); Arrays.fill(BF_MOVES[WHITE], 1); Arrays.fill(BF_MOVES[BLACK], 1); + Arrays.fill(LMR_ALL[WHITE], 1); + Arrays.fill(LMR_ALL[BLACK], 1); + Arrays.fill(LMR_ABOVE_ALPHA[WHITE], 0); + Arrays.fill(LMR_ABOVE_ALPHA[BLACK], 0); Arrays.fill(HH_MOVES1[WHITE][0], 0); Arrays.fill(HH_MOVES1[WHITE][PAWN], 0); @@ -97,7 +106,7 @@ public void clearHistoryHeuristics() { Arrays.fill(BF_MOVES1[BLACK][BISHOP], 1); Arrays.fill(BF_MOVES1[BLACK][ROOK], 1); Arrays.fill(BF_MOVES1[BLACK][QUEEN], 1); - Arrays.fill(BF_MOVES1[BLACK][KING], 1); + Arrays.fill(BF_MOVES1[BLACK][KING], 1); currentPly = 0; } @@ -121,11 +130,15 @@ public int getHHScore(final int color, final int fromToIndex, final int pieceTyp int value1 = 100 * HH_MOVES[color][fromToIndex] / BF_MOVES[color][fromToIndex]; int value2 = 100 * HH_MOVES1[color][pieceType][toIndex] / BF_MOVES1[color][pieceType][toIndex]; int value3 = USE_ContinuationHistory ? getContinuationHistoryScore(color, pieceType, toIndex, parentMove) : 0; - if (USE_ContinuationHistory) { + + /*if (USE_ContinuationHistory) { return value3; } else { return Math.max(value1, Math.max(value2, value3)); } + */ + + return (value1 + value2 + value3) / 3; } @@ -135,6 +148,39 @@ private int getContinuationHistoryScore(final int color, final int pieceType, fi } + public void addLMR_All(final int color, final int move, final int depth) { + LMR_ALL[color][MoveUtil.getFromToIndex(move)] += depth * depth; + } + + + public void addLMR_AboveAlpha(final int color, final int move, final int depth) { + LMR_ABOVE_ALPHA[color][MoveUtil.getFromToIndex(move)] += depth * depth; + } + + + public int getLMR_Rate(final int color, final int move) { + + int fromToIndex = MoveUtil.getFromToIndex(move); + + return LMR_STAT_MULTIPLIER * LMR_ABOVE_ALPHA[color][fromToIndex] / LMR_ALL[color][fromToIndex]; + } + + + public VarStatistic updateLMRAboveAlpha_Stats(final int color, VarStatistic stats) { + + stats.clear(); + + for (int fromToIndex = 0; fromToIndex < LMR_ALL[color].length; fromToIndex++) { + + int rate = LMR_STAT_MULTIPLIER * LMR_ABOVE_ALPHA[color][fromToIndex] / LMR_ALL[color][fromToIndex]; + + stats.addValue(rate); + } + + return stats; + } + + public void addKillerMove(final int move, final int ply) { if (EngineConstants.ENABLE_KILLER_MOVES) { if (KILLER_MOVE_1[ply] != move) { @@ -297,7 +343,7 @@ public void sort() { randomizer_counter++; if (randomizer_counter % 100 == 0) { - if (false) randomize(moveScores, moves, left, nextToGenerate[currentPly] - 1); + randomize(moveScores, moves, left, nextToGenerate[currentPly] - 1); } for (int i = left, j = i; i < nextToGenerate[currentPly] - 1; j = ++i) { diff --git a/Sources/EnginesRunner/src/bagaturchess/engines/run/MTDSchedulerMain.java b/Sources/EnginesRunner/src/bagaturchess/engines/run/MTDSchedulerMain.java index 1ff58a7d..47400ea4 100644 --- a/Sources/EnginesRunner/src/bagaturchess/engines/run/MTDSchedulerMain.java +++ b/Sources/EnginesRunner/src/bagaturchess/engines/run/MTDSchedulerMain.java @@ -205,9 +205,9 @@ public static void main(String[] args) { //BoardUtils.playGameUCI(bitboard, "c2c4 e7e6 a1c2 h7h6 c1d3 g8h7 c2e3 g7g5 f2f3 c7c6 d1c2 a7a5 h2h4 g5h4 g1f2 h8d4 h1h2 d7d6 f1h1 d8g5 b2b3 h7d3 c2d3 d4c5 e3g4 c5b4 f3f4 g5e7 f2h4 f7f5 g4e3 b4a3 h4f2 a3a2 h2h6 a8c7 h6g7 e8d7 g7a1 a2a1 e1c1"); //1rn2r2/1pnkb3/2ppp3/p4p2/2P2P2/1P1BN3/3PPBP1/q1KR3R w - - 0 22 moves c2c4 e7e6 a1c2 h7h6 c1d3 g8h7 c2e3 g7g5 f2f3 c7c6 d1c2 a7a5 h2h4 g5h4 g1f2 h8d4 h1h2 d7d6 f1h1 d8g5 b2b3 h7d3 c2d3 d4c5 e3g4 c5b4 f3f4 g5e7 f2h4 f7f5 g4e3 b4a3 h4f2 a3a2 h2h6 a8c7 h6g7 e8d7 g7a1 a2a1 e1c1 - IBitBoard bitboard = BoardUtils.createBoard_WithPawnsCache("brqnkbnr/pppppppp/8/8/8/8/PPPPPPPP/BRQNKBNR w HBhb - 0 1", cfg.getBoardConfig()); - BoardUtils.playGameUCI(bitboard, "g1f3 d8e6 e2e3 g8f6 f1e2 g7g6 c2c4 b7b6 b2b3 f8g7 a1b2 c7c5 e1g1 e8h8 h2h3 a7a6 d1c3 d7d5 c4d5 f6d5 c3d5 a8d5 h3h4 f8d8 h4h5 d5e4 d2d3 e4d3 e2d3 d8d3 b2g7 g8g7 h5g6 h7g6 e3e4 c8c7 c1h6 g7h6"); - + IBitBoard bitboard = BoardUtils.createBoard_WithPawnsCache("1r1k3r/pbpn3p/1p1n1p1q/P3p3/4P2N/1PN5/2PP1Q1P/R1K1R2B b Eb - 3 14", cfg.getBoardConfig()); + //IBitBoard bitboard = BoardUtils.createBoard_WithPawnsCache("1rk4r/pbpn3p/1p1n1p1q/P3p3/4P2N/1PN5/2PP1Q1P/R1K1R2B w - - 4 15", cfg.getBoardConfig()); + //BoardUtils.playGameUCI(bitboard, "g1f3 d8e6 e2e3 g8f6 f1e2 g7g6 c2c4 b7b6 b2b3 f8g7 a1b2 c7c5 e1g1 e8h8 h2h3 a7a6 d1c3 d7d5 c4d5 f6d5 c3d5 a8d5 h3h4 f8d8 h4h5 d5e4 d2d3 e4d3 e2d3 d8d3 b2g7 g8g7 h5g6 h7g6 e3e4 c8c7 c1h6 g7h6"); System.out.println(bitboard); //IBitBoard bitboard = BoardUtils.createBoard_WithPawnsCache("bqnrnkrb/pppppppp/8/8/8/8/PPPPPPPP/BQNRNKRB b KQkq - 1 1", cfg.getBoardConfig()); @@ -229,6 +229,9 @@ public static void main(String[] args) { int cur_move = 0; while ((cur_move = movesBuffer.next()) != 0) { + if (bitboard.getMoveOps().isCastling(cur_move)) { + System.out.println("CASTLING:"); + } System.out.println(bitboard.getMoveOps().moveToString(cur_move)); } */ diff --git a/Sources/Resources/doc/engine/txt/release_notes_BagaturEngine.txt b/Sources/Resources/doc/engine/txt/release_notes_BagaturEngine.txt index b9df4caa..25852156 100644 --- a/Sources/Resources/doc/engine/txt/release_notes_BagaturEngine.txt +++ b/Sources/Resources/doc/engine/txt/release_notes_BagaturEngine.txt @@ -1,3 +1,6 @@ +Version 3.4f (24 July 2022) + * Fix for FRC: send castling moves to GUI always as "king capture own rook" + Version 3.4e (14 July 2022) * Fixes for FRC: prevent king being attacked after castling (e.g. 1rn2r2/1pnkb3/2ppp3/p4p2/2P2P2/1P1BN3/3PPBP1/q1KR3R w - - 0 22) * Add one more way for FRC castling notation in addition to "capture own rook or equal from_to square" - when king move has file difference bigger then 1, like in classic chess diff --git a/Sources/Search/src/bagaturchess/search/impl/alg/impl1/Search_PVS_NWS.java b/Sources/Search/src/bagaturchess/search/impl/alg/impl1/Search_PVS_NWS.java index a53da5d7..cf42fd28 100644 --- a/Sources/Search/src/bagaturchess/search/impl/alg/impl1/Search_PVS_NWS.java +++ b/Sources/Search/src/bagaturchess/search/impl/alg/impl1/Search_PVS_NWS.java @@ -32,6 +32,7 @@ import bagaturchess.bitboard.impl1.internal.Assert; import bagaturchess.bitboard.impl1.internal.CheckUtil; import bagaturchess.bitboard.impl1.internal.ChessBoard; +import bagaturchess.bitboard.impl1.internal.ChessConstants; import bagaturchess.bitboard.impl1.internal.EngineConstants; import bagaturchess.bitboard.impl1.internal.MaterialUtil; import bagaturchess.bitboard.impl1.internal.MoveGenerator; @@ -91,7 +92,8 @@ public class Search_PVS_NWS extends SearchImpl { private long lastSentMinorInfo_nodesCount; private VarStatistic historyAVGScores; - + private VarStatistic lmrAboveAlphaAVGScores_white; + private VarStatistic lmrAboveAlphaAVGScores_black; private boolean USE_DTZ_CACHE = false; @@ -120,10 +122,13 @@ public void newSearch() { ((BoardImpl) env.getBitboard()).getMoveGenerator().clearHistoryHeuristics(); - lastSentMinorInfo_nodesCount = 0; - lastSentMinorInfo_timestamp = 0; + lastSentMinorInfo_nodesCount = 0; + lastSentMinorInfo_timestamp = 0; + + historyAVGScores = new VarStatistic(); - historyAVGScores = new VarStatistic(); + lmrAboveAlphaAVGScores_white = new VarStatistic(); + lmrAboveAlphaAVGScores_black = new VarStatistic(); if (ChannelManager.getChannel() != null) { @@ -161,6 +166,11 @@ public int nullwin_search(ISearchMediator mediator, PVManager pvman, ISearchInfo } + private VarStatistic getLMRStats(int color) { + + return color == ChessConstants.WHITE ? lmrAboveAlphaAVGScores_white : lmrAboveAlphaAVGScores_black; + } + public int search(ISearchMediator mediator, ISearchInfo info, PVManager pvman, IEvaluator evaluator, ChessBoard cb, MoveGenerator moveGen, final int ply, int depth, int alpha, int beta, boolean isPv, int excludedMove) { @@ -745,14 +755,15 @@ If the engine needs to know the DTZ value (which is only necessary when a TB roo int reduction = 1; if (depth >= 2 && movesPerformed_attacks + movesPerformed_quiet > 1 - //&& movesPerformed_quiet > 1 && phase == PHASE_QUIET && moveGen.getScore() <= historyAVGScores.getEntropy() + //&& moveGen.getLMR_Rate(cb.colorToMoveInverse, move) <= getLMRStats(cb.colorToMoveInverse).getEntropy() + getLMRStats(cb.colorToMoveInverse).getDisperse() ) { reduction = LMR_TABLE[Math.min(depth, 63)][Math.min(movesPerformed_attacks + movesPerformed_quiet, 63)]; if (!isPv) { + reduction += 1; } @@ -763,21 +774,40 @@ If the engine needs to know the DTZ value (which is only necessary when a TB roo } try { + if (EngineConstants.ENABLE_LMR && reduction != 1) { + + moveGen.addLMR_All(cb.colorToMoveInverse, move, depth); + score = -search(mediator, info, pvman, evaluator, cb, moveGen, ply + 1, depth - reduction, -alpha - 1, -alpha, false, 0); + + if (score > alpha) { + + moveGen.addLMR_AboveAlpha(cb.colorToMoveInverse, move, depth); + + moveGen.updateLMRAboveAlpha_Stats(cb.colorToMoveInverse, getLMRStats(cb.colorToMoveInverse)); + + //System.out.println(getLMRStats(cb.colorToMoveInverse).getEntropy()); + } } if (EngineConstants.ENABLE_PVS && score > alpha && movesPerformed_attacks + movesPerformed_quiet > 1) { + score = -search(mediator, info, pvman, evaluator, cb, moveGen, ply + 1, depth - 1 - multiCutReduction, -alpha - 1, -alpha, false, 0); } if (score > alpha) { + if (move == ttMove) { + score = -search(mediator, info, pvman, evaluator, cb, moveGen, ply + 1, depth - 1 + singularMoveExtension - multiCutReduction, -beta, -alpha, isPv, 0); + } else { + score = -search(mediator, info, pvman, evaluator, cb, moveGen, ply + 1, depth - 1 - multiCutReduction, -beta, -alpha, isPv, 0); } } + } catch(SearchInterruptedException sie) { moveGen.endPly(); throw sie; diff --git a/Sources/UCI/src/bagaturchess/uci/impl/Protocol.java b/Sources/UCI/src/bagaturchess/uci/impl/Protocol.java index 262191d4..2143dad4 100644 --- a/Sources/UCI/src/bagaturchess/uci/impl/Protocol.java +++ b/Sources/UCI/src/bagaturchess/uci/impl/Protocol.java @@ -30,7 +30,7 @@ public class Protocol { - public static final String COMMAND_TO_GUI_ID_VERSION_STR = "3.4e"; + public static final String COMMAND_TO_GUI_ID_VERSION_STR = "3.4f"; public static final String COMMAND_TO_ENGINE_UCI_STR = "uci"; public static final String COMMAND_TO_ENGINE_ISREADY_STR = "isready";