From 35bd334b3044bc52ccbc3a8d653097c0f94bf67a Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sat, 1 Nov 2008 13:56:01 +0100 Subject: [PATCH 01/16] Update README to Stockfish Remove Glaurung references. Signed-off-by: Marco Costalba --- Readme.txt | 273 +++++------------------------------------------------ 1 file changed, 22 insertions(+), 251 deletions(-) diff --git a/Readme.txt b/Readme.txt index defd2fc8..377d44aa 100644 --- a/Readme.txt +++ b/Readme.txt @@ -1,21 +1,14 @@ 1. Introduction --------------- -Glaurung is a free UCI chess engine. It is not a complete chess -program, but requires some UCI compatible GUI (like XBoard with -PolyGlot, eboard, José, Arena, Sigma Chess, Shredder, Chess Partner, -or Fritz) in order to be used comfortably. Read the documentation for -your GUI of choice for information about how to use Glaurung with your -GUI. - -Glaurung 2 is a completely rewritten version of Glaurung. Apart from -the parallel search code, almost no code is shared with Glaurung -1.2.1, the previous stable version. The new program is clearly -stronger than the old, but has a less attractive style of play, -because there are still a few major holes in its evaluation function -(most notably space and development). - -This version of Glaurung supports up to 8 CPUs, but has not been +Stockfish is a free UCI chess engine derived from Glaurung. It is not +a complete chess program, but requires some UCI compatible GUI (like +XBoard with PolyGlot, eboard, Jos�, Arena, Sigma Chess, Shredder, +Chess Partner, or Fritz) in order to be used comfortably. Read the +documentation for your GUI of choice for information about how to use +Stockfish with your GUI. + +This version of Stockfish supports up to 8 CPUs, but has not been tested thoroughly with more than 2. The program tries to detect the number of CPUs on your computer and set the number of search threads accordingly, but please be aware that the detection is not always @@ -39,280 +32,59 @@ This distribution of Glaurung consists of the following files: systems. For further information about how to compile Glaurung yourself, read section 4 below. - * MacOSX/, a subdirectory containing excutables for Apple Macintosh - computers running Mac OS X 10.4 (Tiger) and newer. There are two - executables, one for OS X 10.4, and one for OS X 10.5. The - executable for OS X 10.4 will work in 10.5 as well, but the one - for 10.5 is faster. - - * LinuxX86/, a subdirectory containing 32-bit and 64-bit x86 GNU/Linux - executables. - - * Windows/, a subdirectory containing 32-bit and 64-bit Windows - executables. - - * polyglot.ini, for using Glaurung with Fabien Letouzey's PolyGlot + * polyglot.ini, for using Stockfish with Fabien Letouzey's PolyGlot adapter. 3. Opening books ---------------- -This version of Glaurung has experimental support for PolyGlot opening -books. For information about how to create such books, consult the +This version of Stockfish has experimental support for PolyGlot opening +books. For information about how to create such books, consult the PolyGlot documentation. The book file can be selected by setting the UCI parameter "Book File". -A book file contributed by Salvo Spitaleri can be found on the -Glaurung web page. 4. Compiling it yourself ------------------------ On Unix-like systems, it should usually be possible to compile -Glaurung directly from the source code with the included Makefile. +Stockfish directly from the source code with the included Makefile. The exception is computer with big-endian CPUs, like PowerPC -Macintoshes. Some of the bitboard routines in the current version of -Glaurung are endianness-sensitive, and won't work on a big-endian CPU. +Macintoshes. Some of the bitboard routines in the current version of +Stockfish are endianness-sensitive, and won't work on a big-endian CPU. Ensuring that the line with #define USE_32BIT_ATTACKS" near the top of bitboard.h is commented out should solve this problem. Commenting out the line with "#define USE_32BIT_ATTACKS" near the -There is also a problem with compiling Glaurung on certain 64-bit -systems, regardless of the endianness. If Glaurung segfaults -immediately after startup, try to comment out the line with +There is also a problem with compiling Stockfish on certain 64-bit +systems, regardless of the endianness. If Stockfish segfaults +immediately after startup, try to comment out the line with "#define USE_FOLDED_BITSCAN" near the beginning of bitboard.h and recompile. -Finally, even if Glaurung does work without any changes on your +Finally, even if Stockfish does work without any changes on your computer, it might be possible to improve the performance by changing some of the #define directives in bitboard.h. The default settings are optimized for 64-bit CPUs. On 32-bit CPUs, it is probably better to switch on USE_32BIT_ATTACKS, and to use BITCOUNT_SWAR_32 instead of BITCOUNT_SWAR_64. For computers with very little memory (like handheld devices), it is possible to conserve memory by defining -USE_COMPACT_ROOK_ATTACKS. - - - -5. History ----------- - -2007-05-06: Glaurung 2 - epsilon --------------------------------- - -The first public release, and the first version of my new program -which is able to match the old Glaurung 1.2.1 on a single CPU. Lots -of features and chess knowledge is still missing. - -2007-05-10: Glaurung 2 - epsilon/2 ----------------------------------- - -This version is very close to 2 - epsilon. The major changes are: - - * A number of compatibility problems which appeared when trying to - compile Glaurung 2 - epsilon on various operating systems and CPUs - have been solved. - - * Fixed a major bug in the detection of rooks trapped inside a - friendly king. - - * Added knowledge about several types of drawn endgames. - - * Fixed a few FRC related bugs. FRC now works, but because of - serious holes in the evaluation function the program plays very - badly. - - * A slightly more sophisticated king safety evaluation. - -2007-06-07: Glaurung 2 - epsilon/3 ----------------------------------- - -The first public version with support for multiple CPUs. Unless you -have a dual-core (or better) computer, use Glaurung with a PolyGlot -book, or runs games with ponder on, you may want to skip this version, -which is almost certainly no stronger than 2 - epsilon/2 when running -on a single CPU. The main changes compared to the previous version -are: - - * Parallel search, with support for 1-4 CPUs. The program currently - always allocates a separate pawn hash table and material hash - table for four threads, which is a pure waste of RAM if your - computer has just a single CPU. This will be fixed in a future - version. - - * Fixed a bug in book randomization. When using Polyglot books, the - previous version would always select exactly the same move in the - same position after a restart of the program. Thanks to Pavel - Háse for pointing this out. - - * Fixed a UCI pondering bug: Glaurung no longer instantly prints its - best move when the maximum depth is reached during a ponder - search, as the previous version did. According to the UCI - protocol, it is not allowed to print the best move before the - engine has received the "stop" or "quit" command. - - * Additional search information: The new version displays hash - saturation and the current line(s) of search. - - * Several minor bug fixes and optimizations in the search and - evaluation. - -2007-06-08: Glaurung 2 - epsilon/4 ----------------------------------- - -A bugfix release, with only a single important change: - - * Fixed a very serious pondering bug. As pointed out by Marc - Lacrosse, the previous version would lose on time in almost every - single game with pondering enabled. The new version handles - pondering correctly (or so I hope). When playing with ponder - off, the new version is identical to version 2 - epsilon/3. - -2007-06-25: Glaurung 2 - epsilon/5 ----------------------------------- - -Another minor update, including the following improvements and bug -fixes: - - * As Werner Schüle discovered, the previous version would sometimes - stop thinking and lose on time right before delivering checkmate - (which is of course a very unfortunate moment to lose on time). - I haven't been able to reproduce Werner's problem on my computer - (probably because I run a different OS), but I have fixed the bug - which I suspect caused the time losses. I hope the time losses - will no longer occur with 2 - epsilon/5. - - * The program is now slightly less resource-hungry on computers - with less than 4 CPU cores: The previous version would always - allocated separate pawn and material hash tables for four - threads, even when running on a single-core CPU. The new version - only allocates pawn and material hash tables for the threads - which are actually used. - - * A minor reorganization of the memory layout has made the parallel - search about 10% more efficient (at least on my computer, but the - results are likely to vary considerably on different systems). - - * The Intel Mac OS X binary is much faster than before, thanks to - the Intel C++ compiler (previous versions were compiled with - GCC). - - * A few other very minor bug fixes and enhancements. - -2007-11-21: Glaurung 2.0 ------------------------- - -The first stable (or so I hope) and feature-complete version of -Glaurung 2. The following are the main changes compared to the -previous version: - - * The license has been changed from GPL version 2 to GPL version 3. - - * MultiPV mode. - - * Support for the "searchmoves" option in the UCI "go" command. - This means that it is possible to ask Glaurung to exclude some - moves from its analysis, or to restrict its analysis to just a - handful of moves selected by the user. This feature must also be - supported by the GUI under which Glaurung is run. Glaurung's own - GUI does currently not support this feature. - - * Chess960 support now works. The program still plays this game - very badly, because of lack of opening knowledge. - - * Much more aggressive pruning in the last few plies of the main - search. - - * Somewhat better scaling on multi-CPU systems, and support for up - to 8 CPUs. - - * Lots of new UCI parameters. - - * Improved time managment, especially in games with pondering on - (i.e. when the engine is allowed to think when it's the - opponent's turn to move). - - * Some evaluation improvements, and some new basic endgame - patterns. - - * The program should no longer crash if the game lasts longer than - 1000 plies. - - * Many minor bug fixes and other tiny improvements throughout the - code. - - * More generously commented code, and numerous cosmetic changes in - coding style. - -2007-11-22: Glaurung 2.0.1 --------------------------- - - * Fixed (or so I hope) a bug which would occasionally cause one of - the search threads to get stuck forever in its idle loop. - -2008-05-14: Glaurung 2.1 ------------------------- - -This version contains far too many changes to list them all, but most -of them are minor and cosmetic. The most important and noticable -changes are a lot of new UCI parameters, and many improvements in the -evaluation function. The highlights are: - - * Extensive changes in the evaluation function. The addition of - king safety is the most important improvement, but there are also - numerous little improvements elsewhere in the evaluation. There - is still much work left to do in the evaluation function, though. - Space and development are still missing, and the tuning is likely - to be very poor. Currently, the program is optimized for an - entertaining style rather than maximum strength. - - * More accurate forward pruning. The previous version used the - null move refutation move to improve the pruning accuracy by - means of a very simple trick: It did not allow pruning of any - moves with the piece captured by the null move refutation move. - In Glaurung 2.1, this has been enhanced: It does not allow - pruning of moves which defend the destination square of the null - move refutation move, nor of moves which block the ray of the - piece in the case that the moving piece in the null move - refutation move is a slider. - - * More conservative use of LMR at PV nodes. The previous version - searched the first 6 moves with full depth, 2.1 by default - searches the first 14 moves with full depth (but there is a new - UCI parameter for configuring this). I am not at all sure - whether this is an improvement. More thorough testing is - required. - - * Feedback from the evaluation to the search. The search passes an - object of type 'EvalInfo' to the eval, and the eval fills this - struct with various potentially useful information (like the sets - of squares attacked by each piece type, the middle game and - endgame components of the eval, etc.). At the moment, almost - none of this information is actually used by the search. The - only exception is that the evaluation function is now used to - adjust the futility pruning margin in the quiescence search. - - * Less extensions. This hurts the programs performance a lot in most - test suites, but I hope it improves the branching factor in deep - searches. - - * A very long list of new UCI parameters, especially for tuning the - evaluation. +USE_COMPACT_ROOK_ATTACKS. 6. Terms of use --------------- -Glaurung is free, and distributed under the GNU General Public License +Stockfish is free, and distributed under the GNU General Public License (GPL). Essentially, this means that you are free to do almost exactly what you want with the program, including distributing it among your friends, making it available for download from your web site, selling it (either by itself or as part of some bigger software package), or using it as the starting point for a software project of your own. -The only real limitation is that whenever you distribute Glaurung in +The only real limitation is that whenever you distribute Stockfish in some way, you must always include the full source code, or a pointer to where the source code can be found. If you make any changes to the source code, these changes must also be made available under the GPL. @@ -324,5 +96,4 @@ Copying.txt. 7. Feedback ----------- -The author's e-mail address is tord@glaurungchess.com - +The author's e-mail address is mcostalba@gmail.com -- 2.39.2 From b5232e2da3fc773a1a362e3dc19295bb3448ad79 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sat, 1 Nov 2008 12:52:40 +0100 Subject: [PATCH 02/16] Fix a couple of gcc warnings in position.cpp Signed-off-by: Marco Costalba --- src/position.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/position.cpp b/src/position.cpp index 71a30746..958a9397 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -410,6 +410,7 @@ bool Position::piece_attacks_square(Square f, Square t) const { case WR: case BR: return piece_attacks_square(f, t); case WQ: case BQ: return piece_attacks_square(f, t); case WK: case BK: return piece_attacks_square(f, t); + default: break; } return false; } @@ -437,6 +438,7 @@ bool Position::move_attacks_square(Move m, Square s) const { case WR: case BR: return piece_attacks_square(t, s); case WQ: case BQ: return piece_attacks_square(t, s); case WK: case BK: return piece_attacks_square(t, s); + default: break; } return false; } @@ -643,6 +645,9 @@ bool Position::move_is_check(Move m, Bitboard dcCandidates) const { return bit_is_set(rook_attacks_bb(rto, b), ksq); } return false; + + default: // NO_PIECE_TYPE + break; } assert(false); return false; @@ -1113,7 +1118,7 @@ void Position::do_promotion_move(Move m, UndoInfo &u) { castleRights &= castleRightsMask[to]; key ^= zobCastle[castleRights]; - // Reset rule 50 counter + // Reset rule 50 counter rule50 = 0; // Update checkers BB -- 2.39.2 From 55b6464d4096edae032c67d829acff69705b22a6 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sat, 1 Nov 2008 19:44:17 +0100 Subject: [PATCH 03/16] search: micro optimization Signed-off-by: Marco Costalba --- src/search.cpp | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 888c0d78..02907a80 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -894,12 +894,8 @@ namespace { assert(ply >= 0 && ply < PLY_MAX); assert(threadID >= 0 && threadID < ActiveThreads); - EvalInfo ei; - // Initialize, and make an early exit in case of an aborted search, // an instant draw, maximum ply reached, etc. - Value oldAlpha = alpha; - if (AbortSearch || thread_should_stop(threadID)) return Value(0); @@ -911,19 +907,21 @@ namespace { if (pos.is_draw()) return VALUE_DRAW; + EvalInfo ei; + if (ply >= PLY_MAX - 1) return evaluate(pos, ei, threadID); // Mate distance pruning + Value oldAlpha = alpha; alpha = Max(value_mated_in(ply), alpha); beta = Min(value_mate_in(ply+1), beta); if (alpha >= beta) return alpha; - // Transposition table lookup. At PV nodes, we don't use the TT for + // Transposition table lookup. At PV nodes, we don't use the TT for // pruning, but only for move ordering. const TTEntry* tte = TT.retrieve(pos); - Move ttMove = (tte ? tte->move() : MOVE_NONE); // Go with internal iterative deepening if we don't have a TT move @@ -934,7 +932,7 @@ namespace { } // Initialize a MovePicker object for the current position, and prepare - // to search all moves: + // to search all moves MovePicker mp = MovePicker(pos, true, ttMove, ss[ply].mateKiller, ss[ply].killer1, ss[ply].killer2, depth); @@ -942,6 +940,7 @@ namespace { int moveCount = 0; Value value, bestValue = -VALUE_INFINITE; Bitboard dcCandidates = mp.discovered_check_candidates(); + bool isCheck = pos.is_check(); bool mateThreat = MateThreatExtension[1] > Depth(0) && pos.has_mate_threat(opposite_color(pos.side_to_move())); @@ -953,15 +952,19 @@ namespace { { assert(move_is_ok(move)); - bool singleReply = (pos.is_check() && mp.number_of_moves() == 1); + bool singleReply = (isCheck && mp.number_of_moves() == 1); bool moveIsCheck = pos.move_is_check(move, dcCandidates); bool moveIsCapture = pos.move_is_capture(move); bool moveIsPassedPawnPush = pos.move_is_passed_pawn_push(move); movesSearched[moveCount++] = ss[ply].currentMove = move; - ss[ply].currentMoveCaptureValue = move_is_ep(move) ? - PawnValueMidgame : pos.midgame_value_of_piece_on(move_to(move)); + if (moveIsCapture) + ss[ply].currentMoveCaptureValue = pos.midgame_value_of_piece_on(move_to(move)); + else if (move_is_ep(move)) + ss[ply].currentMoveCaptureValue = PawnValueMidgame; + else + ss[ply].currentMoveCaptureValue = Value(0); // Decide the new search depth Depth ext = extension(pos, move, true, moveIsCheck, singleReply, mateThreat); @@ -1051,7 +1054,7 @@ namespace { // All legal moves have been searched. A special case: If there were // no legal moves, it must be mate or stalemate: if (moveCount == 0) - return (pos.is_check() ? value_mated_in(ply) : VALUE_DRAW); + return (isCheck ? value_mated_in(ply) : VALUE_DRAW); // If the search is not aborted, update the transposition table, // history counters, and killer moves. @@ -1118,7 +1121,6 @@ namespace { // Transposition table lookup const TTEntry* tte = TT.retrieve(pos); - Move ttMove = (tte ? tte->move() : MOVE_NONE); if (tte && ok_to_use_TT(tte, depth, beta, ply)) @@ -1129,10 +1131,11 @@ namespace { Value approximateEval = quick_evaluate(pos); bool mateThreat = false; + bool isCheck = pos.is_check(); // Null move search if ( allowNullmove - && !pos.is_check() + && !isCheck && ok_to_do_nullmove(pos) && approximateEval >= beta - NullMoveMargin) { @@ -1196,7 +1199,6 @@ namespace { Value value, bestValue = -VALUE_INFINITE; Bitboard dcCandidates = mp.discovered_check_candidates(); Value futilityValue = VALUE_NONE; - bool isCheck = pos.is_check(); bool useFutilityPruning = UseFutilityPruning && depth < SelectiveDepth && !isCheck; @@ -1302,7 +1304,7 @@ namespace { } // All legal moves have been searched. A special case: If there were - // no legal moves, it must be mate or stalemate: + // no legal moves, it must be mate or stalemate. if (moveCount == 0) return (pos.is_check() ? value_mated_in(ply) : VALUE_DRAW); @@ -1361,7 +1363,7 @@ namespace { if (tte && ok_to_use_TT(tte, depth, beta, ply)) return value_from_tt(tte->value(), ply); - // Evaluate the position statically: + // Evaluate the position statically Value staticValue = evaluate(pos, ei, threadID); if (ply == PLY_MAX - 1) -- 2.39.2 From d087b0a34a6aaa0fc31d2fa256b02861d0351256 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sat, 1 Nov 2008 18:28:49 +0100 Subject: [PATCH 04/16] Delay SEE for scoring captures Do not calculate SEE on all the moves in MovePicker::score_captures() but delay until pick_move_from_list() when only the best ones are double checked against their see value. If a beta cut-off occurs then we avoid calculating SEE on all the moves, but just the picked ones. Signed-off-by: Marco Costalba --- src/movepick.cpp | 46 ++++++++++++++++++---------------------------- 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index 187a3c51..c71572e7 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -206,27 +206,22 @@ void MovePicker::score_captures() { // Suprisingly, this appears to perform slightly better than SEE based // move ordering. The reason is probably that in a position with a winning // capture, capturing a more valuable (but sufficiently defended) piece - // first usually doesn't hurt. The opponent will have to recapture, and + // first usually doesn't hurt. The opponent will have to recapture, and // the hanging piece will still be hanging (except in the unusual cases // where it is possible to recapture with the hanging piece). Exchanging // big pieces before capturing a hanging piece probably helps to reduce - // the subtree size. + // the subtree size. Instead of calculating SEE here to filter out + // loosing captures, we delay the filtering in pick_move_from_list() Move m; - int seeValue; for (int i = 0; i < numOfMoves; i++) { m = moves[i].move; - seeValue = pos.see(m); - if (seeValue >= 0) - { - if (move_promotion(m)) - moves[i].score = QueenValueMidgame; - else - moves[i].score = int(pos.midgame_value_of_piece_on(move_to(m))) - -int(pos.type_of_piece_on(move_from(m))); - } else - moves[i].score = seeValue; + if (move_promotion(m)) + moves[i].score = QueenValueMidgame; + else + moves[i].score = int(pos.midgame_value_of_piece_on(move_to(m))) + -int(pos.type_of_piece_on(move_from(m))); } } @@ -325,26 +320,21 @@ Move MovePicker::pick_move_from_list() { while (movesPicked < numOfMoves) { - int bestScore = -10000000; - bestIndex = -1; - for (int i = movesPicked; i < numOfMoves; i++) + bestIndex = find_best_index(); + + if (bestIndex != -1) // Found a possibly good capture { - if (moves[i].score < 0) + move = moves[bestIndex].move; + int seeValue = pos.see(move); + if (seeValue < 0) { // Losing capture, move it to the badCaptures[] array assert(numOfBadCaptures < 63); - badCaptures[numOfBadCaptures++] = moves[i]; - moves[i--] = moves[--numOfMoves]; - } - else if (moves[i].score > bestScore) - { - bestIndex = i; - bestScore = moves[i].score; + moves[bestIndex].score = seeValue; + badCaptures[numOfBadCaptures++] = moves[bestIndex]; + moves[bestIndex] = moves[--numOfMoves]; + continue; } - } - if (bestIndex != -1) // Found a good capture - { - move = moves[bestIndex].move; moves[bestIndex] = moves[movesPicked++]; if ( move != ttMove && move != mateKiller -- 2.39.2 From 3e275680d5e9a2b335cddd4bd96bed494987933d Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sun, 2 Nov 2008 08:47:27 +0100 Subject: [PATCH 05/16] Use MVV/LVA in score_evasions() Signed-off-by: Marco Costalba --- src/movepick.cpp | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index c71572e7..59855dba 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -251,21 +251,26 @@ void MovePicker::score_noncaptures() { } } -void MovePicker::score_evasions() { - - for (int i = 0; i < numOfMoves; i++) - { - Move m = moves[i].move; - if (m == ttMove) - moves[i].score = 2*HistoryMax; - else if (!pos.square_is_empty(move_to(m))) - { - int seeScore = pos.see(m); - moves[i].score = (seeScore >= 0)? seeScore + HistoryMax : seeScore; - } else - moves[i].score = H.move_ordering_score(pos.piece_on(move_from(m)), m); - } - // FIXME try psqt also here +void MovePicker::score_evasions() { + + Move m; + int hs; + + // Use MVV/LVA ordering + for (int i = 0; i < numOfMoves; i++) + { + m = moves[i].move; + + if (m == ttMove) + hs = 2*HistoryMax; + else if (!pos.square_is_empty(move_to(m))) + hs = int(pos.midgame_value_of_piece_on(move_to(m))) + -int(pos.type_of_piece_on(move_from(m))) + HistoryMax; + else + hs = H.move_ordering_score(pos.piece_on(move_from(m)), m); + + moves[i].score = hs; + } } void MovePicker::score_qcaptures() { -- 2.39.2 From 2fa9d25e8241e3cd8f53275aae05c959c555ba5a Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sun, 2 Nov 2008 15:35:02 +0100 Subject: [PATCH 06/16] Disable LSN filtering as defualt for release Signed-off-by: Marco Costalba --- src/ucioption.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ucioption.cpp b/src/ucioption.cpp index 919271a9..e34c0e77 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -127,7 +127,7 @@ namespace { o.push_back(Option("Futility Margin 2", 300, 0, 1000)); o.push_back(Option("Maximum Razoring Depth", 3, 0, 4)); o.push_back(Option("Razoring Margin", 300, 150, 600)); - o.push_back(Option("LSN filtering", true)); + o.push_back(Option("LSN filtering", false)); o.push_back(Option("LSN Time Margin (sec)", 4, 1, 10)); o.push_back(Option("LSN Value Margin", 200, 100, 600)); o.push_back(Option("Randomness", 0, 0, 10)); -- 2.39.2 From 8097e99c699bdc8a62365a9841fc7cce1c3c15a0 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sun, 2 Nov 2008 15:35:32 +0100 Subject: [PATCH 07/16] Stockfish 1.0 Signed-off-by: Marco Costalba --- Readme.txt | 12 ++++++------ src/Makefile | 11 ++++++----- src/misc.h | 2 +- src/search.cpp | 6 +++--- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Readme.txt b/Readme.txt index 377d44aa..dc76d742 100644 --- a/Readme.txt +++ b/Readme.txt @@ -1,9 +1,9 @@ 1. Introduction --------------- -Stockfish is a free UCI chess engine derived from Glaurung. It is not -a complete chess program, but requires some UCI compatible GUI (like -XBoard with PolyGlot, eboard, Jos�, Arena, Sigma Chess, Shredder, +Stockfish is a free UCI chess engine derived from Glaurung 2.1. It is +not a complete chess program, but requires some UCI compatible GUI +(like XBoard with PolyGlot, eboard, Jos�, Arena, Sigma Chess, Shredder, Chess Partner, or Fritz) in order to be used comfortably. Read the documentation for your GUI of choice for information about how to use Stockfish with your GUI. @@ -20,7 +20,7 @@ cores on your computer. 2. Files -------- -This distribution of Glaurung consists of the following files: +This distribution of Stockfish consists of the following files: * Readme.txt, the file you are currently reading. @@ -28,8 +28,8 @@ This distribution of Glaurung consists of the following files: License. * src/, a subdirectory containing the full source code, including a - Makefile that can be used to compile Glaurung on Unix-like - systems. For further information about how to compile Glaurung + Makefile that can be used to compile Stockfish on Unix-like + systems. For further information about how to compile Stockfish yourself, read section 4 below. * polyglot.ini, for using Stockfish with Fabien Letouzey's PolyGlot diff --git a/src/Makefile b/src/Makefile index b55ef7ea..ec143d60 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,14 +1,15 @@ -# Glaurung, a UCI chess playing engine. +# Stockfish, a UCI chess playing engine derived from Glaurung 2.1 # Copyright (C) 2004-2007 Tord Romstad +# Copyright (C) 2008 Marco Costalba -# This file is part of Glaurung. +# This file is part of Stockfish. # -# Glaurung is free software: you can redistribute it and/or modify +# Stockfish is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # -# Glaurung is distributed in the hope that it will be useful, +# Stockfish is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. @@ -21,7 +22,7 @@ ### Files ### -EXE = glaurung +EXE = stockfish OBJS = bitboard.o color.o pawns.o material.o endgame.o evaluate.o main.o \ misc.o move.o movegen.o history.o movepick.o search.o piece.o \ diff --git a/src/misc.h b/src/misc.h index 3b141983..9b3f3f40 100644 --- a/src/misc.h +++ b/src/misc.h @@ -37,7 +37,7 @@ /// Version number. If this is left empty, the current date (in the format /// YYMMDD) is used as a version number. -const std::string EngineVersion = ""; +const std::string EngineVersion = "1.0"; //// diff --git a/src/search.cpp b/src/search.cpp index 02907a80..cdc34ba6 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -960,11 +960,11 @@ namespace { movesSearched[moveCount++] = ss[ply].currentMove = move; if (moveIsCapture) - ss[ply].currentMoveCaptureValue = pos.midgame_value_of_piece_on(move_to(move)); + ss[ply].currentMoveCaptureValue = pos.midgame_value_of_piece_on(move_to(move)); else if (move_is_ep(move)) - ss[ply].currentMoveCaptureValue = PawnValueMidgame; + ss[ply].currentMoveCaptureValue = PawnValueMidgame; else - ss[ply].currentMoveCaptureValue = Value(0); + ss[ply].currentMoveCaptureValue = Value(0); // Decide the new search depth Depth ext = extension(pos, move, true, moveIsCheck, singleReply, mateThreat); -- 2.39.2 From 1a158c0cf056930de3c08389ab2db0f75a3f6723 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sun, 2 Nov 2008 15:58:10 +0100 Subject: [PATCH 08/16] Revert movepick optimizations before to release More testing is needed and better do not risk just before release. Reverted: Disable LSN filtering as defualt for release Use MVV/LVA in score_evasions() Signed-off-by: Marco Costalba --- src/movepick.cpp | 81 +++++++++++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 38 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index 59855dba..187a3c51 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -206,22 +206,27 @@ void MovePicker::score_captures() { // Suprisingly, this appears to perform slightly better than SEE based // move ordering. The reason is probably that in a position with a winning // capture, capturing a more valuable (but sufficiently defended) piece - // first usually doesn't hurt. The opponent will have to recapture, and + // first usually doesn't hurt. The opponent will have to recapture, and // the hanging piece will still be hanging (except in the unusual cases // where it is possible to recapture with the hanging piece). Exchanging // big pieces before capturing a hanging piece probably helps to reduce - // the subtree size. Instead of calculating SEE here to filter out - // loosing captures, we delay the filtering in pick_move_from_list() + // the subtree size. Move m; + int seeValue; for (int i = 0; i < numOfMoves; i++) { m = moves[i].move; - if (move_promotion(m)) - moves[i].score = QueenValueMidgame; - else - moves[i].score = int(pos.midgame_value_of_piece_on(move_to(m))) - -int(pos.type_of_piece_on(move_from(m))); + seeValue = pos.see(m); + if (seeValue >= 0) + { + if (move_promotion(m)) + moves[i].score = QueenValueMidgame; + else + moves[i].score = int(pos.midgame_value_of_piece_on(move_to(m))) + -int(pos.type_of_piece_on(move_from(m))); + } else + moves[i].score = seeValue; } } @@ -251,26 +256,21 @@ void MovePicker::score_noncaptures() { } } -void MovePicker::score_evasions() { - - Move m; - int hs; - - // Use MVV/LVA ordering - for (int i = 0; i < numOfMoves; i++) - { - m = moves[i].move; - - if (m == ttMove) - hs = 2*HistoryMax; - else if (!pos.square_is_empty(move_to(m))) - hs = int(pos.midgame_value_of_piece_on(move_to(m))) - -int(pos.type_of_piece_on(move_from(m))) + HistoryMax; - else - hs = H.move_ordering_score(pos.piece_on(move_from(m)), m); - - moves[i].score = hs; - } +void MovePicker::score_evasions() { + + for (int i = 0; i < numOfMoves; i++) + { + Move m = moves[i].move; + if (m == ttMove) + moves[i].score = 2*HistoryMax; + else if (!pos.square_is_empty(move_to(m))) + { + int seeScore = pos.see(m); + moves[i].score = (seeScore >= 0)? seeScore + HistoryMax : seeScore; + } else + moves[i].score = H.move_ordering_score(pos.piece_on(move_from(m)), m); + } + // FIXME try psqt also here } void MovePicker::score_qcaptures() { @@ -325,21 +325,26 @@ Move MovePicker::pick_move_from_list() { while (movesPicked < numOfMoves) { - bestIndex = find_best_index(); - - if (bestIndex != -1) // Found a possibly good capture + int bestScore = -10000000; + bestIndex = -1; + for (int i = movesPicked; i < numOfMoves; i++) { - move = moves[bestIndex].move; - int seeValue = pos.see(move); - if (seeValue < 0) + if (moves[i].score < 0) { // Losing capture, move it to the badCaptures[] array assert(numOfBadCaptures < 63); - moves[bestIndex].score = seeValue; - badCaptures[numOfBadCaptures++] = moves[bestIndex]; - moves[bestIndex] = moves[--numOfMoves]; - continue; + badCaptures[numOfBadCaptures++] = moves[i]; + moves[i--] = moves[--numOfMoves]; } + else if (moves[i].score > bestScore) + { + bestIndex = i; + bestScore = moves[i].score; + } + } + if (bestIndex != -1) // Found a good capture + { + move = moves[bestIndex].move; moves[bestIndex] = moves[movesPicked++]; if ( move != ttMove && move != mateKiller -- 2.39.2 From c595185b3c2dc3e5e95c6c6da728adb289a14bb9 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sun, 2 Nov 2008 18:32:56 +0100 Subject: [PATCH 09/16] Restore LSN filtering Signed-off-by: Marco Costalba --- src/ucioption.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ucioption.cpp b/src/ucioption.cpp index e34c0e77..919271a9 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -127,7 +127,7 @@ namespace { o.push_back(Option("Futility Margin 2", 300, 0, 1000)); o.push_back(Option("Maximum Razoring Depth", 3, 0, 4)); o.push_back(Option("Razoring Margin", 300, 150, 600)); - o.push_back(Option("LSN filtering", false)); + o.push_back(Option("LSN filtering", true)); o.push_back(Option("LSN Time Margin (sec)", 4, 1, 10)); o.push_back(Option("LSN Value Margin", 200, 100, 600)); o.push_back(Option("Randomness", 0, 0, 10)); -- 2.39.2 From 046fd4926f8a9b6bbdb13e75723704c1422f54cd Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Mon, 3 Nov 2008 19:55:59 +0100 Subject: [PATCH 10/16] Restore development versioning Signed-off-by: Marco Costalba --- src/misc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/misc.h b/src/misc.h index 9b3f3f40..3b141983 100644 --- a/src/misc.h +++ b/src/misc.h @@ -37,7 +37,7 @@ /// Version number. If this is left empty, the current date (in the format /// YYMMDD) is used as a version number. -const std::string EngineVersion = "1.0"; +const std::string EngineVersion = ""; //// -- 2.39.2 From ff0d9dad2b7befd3df30033a20a4817378b59b94 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Mon, 3 Nov 2008 19:59:58 +0100 Subject: [PATCH 11/16] Fix a serious bug in TranspositionTable::retrieve() Reported by Tord Romstad. Signed-off-by: Marco Costalba --- src/tt.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tt.cpp b/src/tt.cpp index d7037a30..4ac685d5 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -144,9 +144,8 @@ const TTEntry* TranspositionTable::retrieve(const Position &pos) const { TTEntry *tte = first_entry(pos); - for (int i = 0; i < 4; i++) + for (int i = 0; i < 4; i++, tte++) { - tte += i; if (tte->key() == pos.get_key()) return tte; } -- 2.39.2 From 787d3585548ed7dac06597780a7d0adb64482d41 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Mon, 3 Nov 2008 22:05:41 +0100 Subject: [PATCH 12/16] Fix compile under Ubuntu 64bit Some missing includes. Signed-off-by: Marco Costalba --- src/history.cpp | 1 + src/material.cpp | 1 + src/pawns.cpp | 1 + src/square.h | 1 + src/tt.cpp | 1 + 5 files changed, 5 insertions(+) diff --git a/src/history.cpp b/src/history.cpp index d5632986..52e36219 100644 --- a/src/history.cpp +++ b/src/history.cpp @@ -23,6 +23,7 @@ //// #include +#include #include "history.h" diff --git a/src/material.cpp b/src/material.cpp index 9f0fb9ed..595eee29 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -23,6 +23,7 @@ //// #include +#include #include #include "material.h" diff --git a/src/pawns.cpp b/src/pawns.cpp index 0089c42d..6fdd5c13 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -23,6 +23,7 @@ //// #include +#include #include "pawns.h" diff --git a/src/square.h b/src/square.h index ff31e865..ed0b289b 100644 --- a/src/square.h +++ b/src/square.h @@ -25,6 +25,7 @@ //// Includes //// +#include // for abs() #include #include "color.h" diff --git a/src/tt.cpp b/src/tt.cpp index 4ac685d5..97ca23dc 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -24,6 +24,7 @@ #include #include +#include #include "tt.h" -- 2.39.2 From ec236924331beb1664d3b5f73f8eb4827827fe3b Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Mon, 3 Nov 2008 22:25:28 +0100 Subject: [PATCH 13/16] Stockfish 1.01 Signed-off-by: Marco Costalba --- src/misc.h | 2 +- src/ucioption.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/misc.h b/src/misc.h index 3b141983..7a6e82b6 100644 --- a/src/misc.h +++ b/src/misc.h @@ -37,7 +37,7 @@ /// Version number. If this is left empty, the current date (in the format /// YYMMDD) is used as a version number. -const std::string EngineVersion = ""; +const std::string EngineVersion = "1.01"; //// diff --git a/src/ucioption.cpp b/src/ucioption.cpp index 919271a9..e34c0e77 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -127,7 +127,7 @@ namespace { o.push_back(Option("Futility Margin 2", 300, 0, 1000)); o.push_back(Option("Maximum Razoring Depth", 3, 0, 4)); o.push_back(Option("Razoring Margin", 300, 150, 600)); - o.push_back(Option("LSN filtering", true)); + o.push_back(Option("LSN filtering", false)); o.push_back(Option("LSN Time Margin (sec)", 4, 1, 10)); o.push_back(Option("LSN Value Margin", 200, 100, 600)); o.push_back(Option("Randomness", 0, 0, 10)); -- 2.39.2 From a28c17ecb60918bae546ea6aa5b596b7a56d603e Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Tue, 4 Nov 2008 20:59:11 +0100 Subject: [PATCH 14/16] Fix a missed initialization in get_option_value() Spotted and reported by Dann Corbit. Signed-off-by: Marco Costalba --- src/ucioption.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ucioption.cpp b/src/ucioption.cpp index e34c0e77..79f98868 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -176,7 +176,7 @@ namespace { template T get_option_value(const std::string& optionName) { - T ret; + T ret = T(); Options::iterator it = option_with_name(optionName); if (it != options.end()) -- 2.39.2 From 6cc11272e2834516cb331e1c229128002646fe29 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Tue, 4 Nov 2008 21:13:00 +0100 Subject: [PATCH 15/16] Restore development versioning and LSN filtering Signed-off-by: Marco Costalba --- src/misc.h | 2 +- src/ucioption.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/misc.h b/src/misc.h index 7a6e82b6..3b141983 100644 --- a/src/misc.h +++ b/src/misc.h @@ -37,7 +37,7 @@ /// Version number. If this is left empty, the current date (in the format /// YYMMDD) is used as a version number. -const std::string EngineVersion = "1.01"; +const std::string EngineVersion = ""; //// diff --git a/src/ucioption.cpp b/src/ucioption.cpp index 79f98868..f23a29ee 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -127,7 +127,7 @@ namespace { o.push_back(Option("Futility Margin 2", 300, 0, 1000)); o.push_back(Option("Maximum Razoring Depth", 3, 0, 4)); o.push_back(Option("Razoring Margin", 300, 150, 600)); - o.push_back(Option("LSN filtering", false)); + o.push_back(Option("LSN filtering", true)); o.push_back(Option("LSN Time Margin (sec)", 4, 1, 10)); o.push_back(Option("LSN Value Margin", 200, 100, 600)); o.push_back(Option("Randomness", 0, 0, 10)); -- 2.39.2 From 3f610e2b13340ca65d0f9d63aa0cb8da92e80117 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sat, 8 Nov 2008 09:29:07 +0100 Subject: [PATCH 16/16] Introduce LastIterations variable Is set during the last iteration. Sometime also during the second last. During the last iteration is set in the 95% of cases. During the second last is set in the 40% of cases. Signed-off-by: Marco Costalba --- src/search.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index cdc34ba6..8da12118 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -144,7 +144,7 @@ namespace { bool UseFutilityPruning = true; // Margins for futility pruning in the quiescence search, at frontier - // nodes, and at pre-frontier nodes: + // nodes, and at pre-frontier nodes Value FutilityMargin0 = Value(0x80); Value FutilityMargin1 = Value(0x100); Value FutilityMargin2 = Value(0x300); @@ -167,21 +167,22 @@ namespace { Depth PawnEndgameExtension[2] = {OnePly, OnePly}; Depth MateThreatExtension[2] = {Depth(0), Depth(0)}; - // Search depth at iteration 1: + // Search depth at iteration 1 const Depth InitialDepth = OnePly /*+ OnePly/2*/; // Node counters int NodesSincePoll; int NodesBetweenPolls = 30000; - // Iteration counter: + // Iteration counter int Iteration; + bool LastIterations; // Scores and number of times the best move changed for each iteration: Value ValueByIteration[PLY_MAX_PLUS_2]; int BestMoveChangesByIteration[PLY_MAX_PLUS_2]; - // MultiPV mode: + // MultiPV mode int MultiPV = 1; // Time managment variables @@ -617,6 +618,7 @@ namespace { ValueByIteration[0] = Value(0); ValueByIteration[1] = rml.get_move_score(0); Iteration = 1; + LastIterations = false; EasyMove = rml.scan_for_easy_move(); @@ -675,6 +677,9 @@ namespace { if (ExtraSearchTime > 0 && TimeAdvantage > 2 * MaxSearchTime) ExtraSearchTime += MaxSearchTime / 2; + // Try to guess if the current iteration is the last one or the last two + LastIterations = (current_search_time() > ((MaxSearchTime + ExtraSearchTime)*58) / 128); + // Stop search if most of MaxSearchTime is consumed at the end of the // iteration. We probably don't have enough time to search the first // move at the next iteration anyway. -- 2.39.2