stockfish-3.0.0+git20130508/0000755000175000017500000000000012142540127014471 5ustar oliveroliverstockfish-3.0.0+git20130508/Readme.md0000644000175000017500000000601012142540127016205 0ustar oliveroliver### Overview Stockfish is a free UCI chess engine derived from Glaurung 2.1. It is not a complete chess program and requires some UCI-compatible GUI (e.g. XBoard with PolyGlot, eboard, 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 it. This version of Stockfish supports up to 64 CPUs, but has not been tested thoroughly with more than 4. The program tries to detect the number of CPUs on your computer and sets the number of search threads accordingly, but please be aware that the detection is not always correct. It is therefore recommended to inspect the value of the *Threads* UCI parameter, and to make sure it equals the number of CPU cores on your computer. If you are using more than eight threads, it is recommended to raise the value of the *Min Split Depth* UCI parameter to 7. ### Files This distribution of Stockfish consists of the following files: * Readme.md, the file you are currently reading. * Copying.txt, a text file containing the GNU General Public License. * src/, a subdirectory containing the full source code, including a Makefile that can be used to compile Stockfish on Unix-like systems. For further information about how to compile Stockfish yourself read section below. * polyglot.ini, for using Stockfish with Fabien Letouzey's PolyGlot adapter. ### Opening books This version of Stockfish has 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 *Book File* UCI parameter. ### Compiling it yourself On Unix-like systems, it should be possible to compile Stockfish directly from the source code with the included Makefile. Stockfish has support for 32 or 64-bit CPUs, the hardware POPCNT instruction, big-endian machines such as Power PC, and other platforms. In general it is recommended to run `make help` to see a list of make targets with corresponding descriptions. When not using Makefile to compile (for instance with Microsoft MSVC) you need to manually set/unset some switches in the compiler command line; see file *types.h* for a quick reference. ### Terms of use 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 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. For full details, read the copy of the GPL found in the file named *Copying.txt* stockfish-3.0.0+git20130508/polyglot.ini0000644000175000017500000000140212142540127017040 0ustar oliveroliver[PolyGlot] EngineDir = . EngineCommand = ./stockfish Book = false BookFile = book.bin Log = false LogFile = stockfish.log Resign = true ResignScore = 600 [Engine] Use Search Log = false Search Log Filename = SearchLog.txt Book File = book.bin Best Book Move = false Contempt Factor = 0 Mobility (Middle Game) = 100 Mobility (Endgame) = 100 Passed Pawns (Middle Game) = 100 Passed Pawns (Endgame) = 100 Space = 100 Aggressiveness = 100 Cowardice = 100 Min Split Depth = 4 Max Threads per Split Point = 5 Threads = 1 Use Sleeping Threads = true Hash = 128 Ponder = true OwnBook = false MultiPV = 1 Skill Level = 20 Emergency Move Horizon = 40 Emergency Base Time = 200 Emergency Move Time = 70 Minimum Thinking Time = 20 UCI_Chess960 = false UCI_AnalyseMode = false stockfish-3.0.0+git20130508/src/0000755000175000017500000000000012142540127015260 5ustar oliveroliverstockfish-3.0.0+git20130508/src/movepick.h0000644000175000017500000000637712142540127017263 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #if !defined MOVEPICK_H_INCLUDED #define MOVEPICK_H_INCLUDED #include // For std::max #include // For memset #include "movegen.h" #include "position.h" #include "search.h" #include "types.h" /// The Stats struct stores moves statistics. According to the template parameter /// the class can store both History and Gains type statistics. History records /// how often different moves have been successful or unsuccessful during the /// current search and is used for reduction and move ordering decisions. Gains /// records the move's best evaluation gain from one ply to the next and is used /// for pruning decisions. Entries are stored according only to moving piece and /// destination square, in particular two moves with different origin but same /// destination and same piece will be considered identical. template struct Stats { static const Value Max = Value(2000); const Value* operator[](Piece p) const { return &table[p][0]; } void clear() { memset(table, 0, sizeof(table)); } void update(Piece p, Square to, Value v) { if (Gain) table[p][to] = std::max(v, table[p][to] - 1); else if (abs(table[p][to] + v) < Max) table[p][to] += v; } private: Value table[PIECE_NB][SQUARE_NB]; }; typedef Stats History; typedef Stats Gains; /// MovePicker class is used to pick one pseudo legal move at a time from the /// current position. The most important method is next_move(), which returns a /// new pseudo legal move each time it is called, until there are no moves left, /// when MOVE_NONE is returned. In order to improve the efficiency of the alpha /// beta algorithm, MovePicker attempts to return the moves which are most likely /// to get a cut-off first. class MovePicker { MovePicker& operator=(const MovePicker&); // Silence a warning under MSVC public: MovePicker(const Position&, Move, Depth, const History&, Search::Stack*, Value); MovePicker(const Position&, Move, Depth, const History&, Square); MovePicker(const Position&, Move, const History&, PieceType); template Move next_move(); private: template void score(); void generate_next(); const Position& pos; const History& Hist; Search::Stack* ss; Depth depth; Move ttMove; MoveStack killers[2]; Square recaptureSquare; int captureThreshold, phase; MoveStack *cur, *end, *endQuiets, *endBadCaptures; MoveStack moves[MAX_MOVES]; }; #endif // !defined(MOVEPICK_H_INCLUDED) stockfish-3.0.0+git20130508/src/notation.h0000644000175000017500000000247012142540127017267 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #if !defined(NOTATION_H_INCLUDED) #define NOTATION_H_INCLUDED #include #include "types.h" class Position; std::string score_to_uci(Value v, Value alpha = -VALUE_INFINITE, Value beta = VALUE_INFINITE); Move move_from_uci(const Position& pos, std::string& str); const std::string move_to_uci(Move m, bool chess960); const std::string move_to_san(Position& pos, Move m); std::string pretty_pv(Position& pos, int depth, Value score, int64_t msecs, Move pv[]); #endif // !defined(NOTATION_H_INCLUDED) stockfish-3.0.0+git20130508/src/timeman.cpp0000644000175000017500000001732412142540127017425 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include "search.h" #include "timeman.h" #include "ucioption.h" namespace { /// Constants const int MoveHorizon = 50; // Plan time management at most this many moves ahead const float MaxRatio = 7.0f; // When in trouble, we can step over reserved time with this ratio const float StealRatio = 0.33f; // However we must not steal time from remaining moves over this ratio // MoveImportance[] is based on naive statistical analysis of "how many games are still undecided // after n half-moves". Game is considered "undecided" as long as neither side has >275cp advantage. // Data was extracted from CCRL game database with some simple filtering criteria. const int MoveImportance[512] = { 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7780, 7778, 7778, 7776, 7776, 7776, 7773, 7770, 7768, 7766, 7763, 7757, 7751, 7743, 7735, 7724, 7713, 7696, 7689, 7670, 7656, 7627, 7605, 7571, 7549, 7522, 7493, 7462, 7425, 7385, 7350, 7308, 7272, 7230, 7180, 7139, 7094, 7055, 7010, 6959, 6902, 6841, 6778, 6705, 6651, 6569, 6508, 6435, 6378, 6323, 6253, 6152, 6085, 5995, 5931, 5859, 5794, 5717, 5646, 5544, 5462, 5364, 5282, 5172, 5078, 4988, 4901, 4831, 4764, 4688, 4609, 4536, 4443, 4365, 4293, 4225, 4155, 4085, 4005, 3927, 3844, 3765, 3693, 3634, 3560, 3479, 3404, 3331, 3268, 3207, 3146, 3077, 3011, 2947, 2894, 2828, 2776, 2727, 2676, 2626, 2589, 2538, 2490, 2442, 2394, 2345, 2302, 2243, 2192, 2156, 2115, 2078, 2043, 2004, 1967, 1922, 1893, 1845, 1809, 1772, 1736, 1702, 1674, 1640, 1605, 1566, 1536, 1509, 1479, 1452, 1423, 1388, 1362, 1332, 1304, 1289, 1266, 1250, 1228, 1206, 1180, 1160, 1134, 1118, 1100, 1080, 1068, 1051, 1034, 1012, 1001, 980, 960, 945, 934, 916, 900, 888, 878, 865, 852, 828, 807, 787, 770, 753, 744, 731, 722, 706, 700, 683, 676, 671, 664, 652, 641, 634, 627, 613, 604, 591, 582, 568, 560, 552, 540, 534, 529, 519, 509, 495, 484, 474, 467, 460, 450, 438, 427, 419, 410, 406, 399, 394, 387, 382, 377, 372, 366, 359, 353, 348, 343, 337, 333, 328, 321, 315, 309, 303, 298, 293, 287, 284, 281, 277, 273, 265, 261, 255, 251, 247, 241, 240, 235, 229, 218, 217, 213, 212, 208, 206, 197, 193, 191, 189, 185, 184, 180, 177, 172, 170, 170, 170, 166, 163, 159, 158, 156, 155, 151, 146, 141, 138, 136, 132, 130, 128, 125, 123, 122, 118, 118, 118, 117, 115, 114, 108, 107, 105, 105, 105, 102, 97, 97, 95, 94, 93, 91, 88, 86, 83, 80, 80, 79, 79, 79, 78, 76, 75, 72, 72, 71, 70, 68, 65, 63, 61, 61, 59, 59, 59, 58, 56, 55, 54, 54, 52, 49, 48, 48, 48, 48, 45, 45, 45, 44, 43, 41, 41, 41, 41, 40, 40, 38, 37, 36, 34, 34, 34, 33, 31, 29, 29, 29, 28, 28, 28, 28, 28, 28, 28, 27, 27, 27, 27, 27, 24, 24, 23, 23, 22, 21, 20, 20, 19, 19, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17, 17, 17, 16, 16, 15, 15, 14, 14, 14, 12, 12, 11, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1 }; int move_importance(int ply) { return MoveImportance[std::min(ply, 511)]; } /// Function Prototypes enum TimeType { OptimumTime, MaxTime }; template int remaining(int myTime, int movesToGo, int fullMoveNumber, int slowMover); } void TimeManager::pv_instability(int curChanges, int prevChanges) { unstablePVExtraTime = curChanges * (optimumSearchTime / 2) + prevChanges * (optimumSearchTime / 3); } void TimeManager::init(const Search::LimitsType& limits, int currentPly, Color us) { /* We support four different kind of time controls: increment == 0 && movesToGo == 0 means: x basetime [sudden death!] increment == 0 && movesToGo != 0 means: x moves in y minutes increment > 0 && movesToGo == 0 means: x basetime + z increment increment > 0 && movesToGo != 0 means: x moves in y minutes + z increment Time management is adjusted by following UCI parameters: emergencyMoveHorizon: Be prepared to always play at least this many moves emergencyBaseTime : Always attempt to keep at least this much time (in ms) at clock emergencyMoveTime : Plus attempt to keep at least this much time for each remaining emergency move minThinkingTime : No matter what, use at least this much thinking before doing the move */ int hypMTG, hypMyTime, t1, t2; // Read uci parameters int emergencyMoveHorizon = Options["Emergency Move Horizon"]; int emergencyBaseTime = Options["Emergency Base Time"]; int emergencyMoveTime = Options["Emergency Move Time"]; int minThinkingTime = Options["Minimum Thinking Time"]; int slowMover = Options["Slow Mover"]; // Initialize to maximum values but unstablePVExtraTime that is reset unstablePVExtraTime = 0; optimumSearchTime = maximumSearchTime = limits.time[us]; // We calculate optimum time usage for different hypothetic "moves to go"-values and choose the // minimum of calculated search time values. Usually the greatest hypMTG gives the minimum values. for (hypMTG = 1; hypMTG <= (limits.movestogo ? std::min(limits.movestogo, MoveHorizon) : MoveHorizon); hypMTG++) { // Calculate thinking time for hypothetic "moves to go"-value hypMyTime = limits.time[us] + limits.inc[us] * (hypMTG - 1) - emergencyBaseTime - emergencyMoveTime * std::min(hypMTG, emergencyMoveHorizon); hypMyTime = std::max(hypMyTime, 0); t1 = minThinkingTime + remaining(hypMyTime, hypMTG, currentPly, slowMover); t2 = minThinkingTime + remaining(hypMyTime, hypMTG, currentPly, slowMover); optimumSearchTime = std::min(optimumSearchTime, t1); maximumSearchTime = std::min(maximumSearchTime, t2); } if (Options["Ponder"]) optimumSearchTime += optimumSearchTime / 4; // Make sure that maxSearchTime is not over absoluteMaxSearchTime optimumSearchTime = std::min(optimumSearchTime, maximumSearchTime); } namespace { template int remaining(int myTime, int movesToGo, int currentPly, int slowMover) { const float TMaxRatio = (T == OptimumTime ? 1 : MaxRatio); const float TStealRatio = (T == OptimumTime ? 0 : StealRatio); int thisMoveImportance = move_importance(currentPly) * slowMover / 100; int otherMovesImportance = 0; for (int i = 1; i < movesToGo; i++) otherMovesImportance += move_importance(currentPly + 2 * i); float ratio1 = (TMaxRatio * thisMoveImportance) / float(TMaxRatio * thisMoveImportance + otherMovesImportance); float ratio2 = (thisMoveImportance + TStealRatio * otherMovesImportance) / float(thisMoveImportance + otherMovesImportance); return int(floor(myTime * std::min(ratio1, ratio2))); } } stockfish-3.0.0+git20130508/src/bitboard.cpp0000644000175000017500000002535512142540127017564 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include "bitboard.h" #include "bitcount.h" #include "misc.h" #include "rkiss.h" CACHE_LINE_ALIGNMENT Bitboard RMasks[SQUARE_NB]; Bitboard RMagics[SQUARE_NB]; Bitboard* RAttacks[SQUARE_NB]; unsigned RShifts[SQUARE_NB]; Bitboard BMasks[SQUARE_NB]; Bitboard BMagics[SQUARE_NB]; Bitboard* BAttacks[SQUARE_NB]; unsigned BShifts[SQUARE_NB]; Bitboard SquareBB[SQUARE_NB]; Bitboard FileBB[FILE_NB]; Bitboard RankBB[RANK_NB]; Bitboard AdjacentFilesBB[FILE_NB]; Bitboard ThisAndAdjacentFilesBB[FILE_NB]; Bitboard InFrontBB[COLOR_NB][RANK_NB]; Bitboard StepAttacksBB[PIECE_NB][SQUARE_NB]; Bitboard BetweenBB[SQUARE_NB][SQUARE_NB]; Bitboard DistanceRingsBB[SQUARE_NB][8]; Bitboard ForwardBB[COLOR_NB][SQUARE_NB]; Bitboard PassedPawnMask[COLOR_NB][SQUARE_NB]; Bitboard AttackSpanMask[COLOR_NB][SQUARE_NB]; Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB]; int SquareDistance[SQUARE_NB][SQUARE_NB]; namespace { // De Bruijn sequences. See chessprogramming.wikispaces.com/BitScan const uint64_t DeBruijn_64 = 0x3F79D71B4CB0A89ULL; const uint32_t DeBruijn_32 = 0x783A9B23; CACHE_LINE_ALIGNMENT int MS1BTable[256]; Square BSFTable[SQUARE_NB]; Bitboard RTable[0x19000]; // Storage space for rook attacks Bitboard BTable[0x1480]; // Storage space for bishop attacks typedef unsigned (Fn)(Square, Bitboard); void init_magics(Bitboard table[], Bitboard* attacks[], Bitboard magics[], Bitboard masks[], unsigned shifts[], Square deltas[], Fn index); FORCE_INLINE unsigned bsf_index(Bitboard b) { // Matt Taylor's folding for 32 bit systems, extended to 64 bits by Kim Walisch b ^= (b - 1); return Is64Bit ? (b * DeBruijn_64) >> 58 : ((unsigned(b) ^ unsigned(b >> 32)) * DeBruijn_32) >> 26; } } /// lsb()/msb() finds the least/most significant bit in a nonzero bitboard. /// pop_lsb() finds and clears the least significant bit in a nonzero bitboard. #if !defined(USE_BSFQ) Square lsb(Bitboard b) { return BSFTable[bsf_index(b)]; } Square pop_lsb(Bitboard* b) { Bitboard bb = *b; *b = bb & (bb - 1); return BSFTable[bsf_index(bb)]; } Square msb(Bitboard b) { unsigned b32; int result = 0; if (b > 0xFFFFFFFF) { b >>= 32; result = 32; } b32 = unsigned(b); if (b32 > 0xFFFF) { b32 >>= 16; result += 16; } if (b32 > 0xFF) { b32 >>= 8; result += 8; } return (Square)(result + MS1BTable[b32]); } #endif // !defined(USE_BSFQ) /// Bitboards::print() prints a bitboard in an easily readable format to the /// standard output. This is sometimes useful for debugging. void Bitboards::print(Bitboard b) { sync_cout; for (Rank rank = RANK_8; rank >= RANK_1; rank--) { std::cout << "+---+---+---+---+---+---+---+---+" << '\n'; for (File file = FILE_A; file <= FILE_H; file++) std::cout << "| " << (b & (file | rank) ? "X " : " "); std::cout << "|\n"; } std::cout << "+---+---+---+---+---+---+---+---+" << sync_endl; } /// Bitboards::init() initializes various bitboard arrays. It is called during /// program initialization. void Bitboards::init() { for (int k = 0, i = 0; i < 8; i++) while (k < (2 << i)) MS1BTable[k++] = i; for (int i = 0; i < 64; i++) BSFTable[bsf_index(1ULL << i)] = Square(i); for (Square s = SQ_A1; s <= SQ_H8; s++) SquareBB[s] = 1ULL << s; FileBB[FILE_A] = FileABB; RankBB[RANK_1] = Rank1BB; for (int i = 1; i < 8; i++) { FileBB[i] = FileBB[i - 1] << 1; RankBB[i] = RankBB[i - 1] << 8; } for (File f = FILE_A; f <= FILE_H; f++) { AdjacentFilesBB[f] = (f > FILE_A ? FileBB[f - 1] : 0) | (f < FILE_H ? FileBB[f + 1] : 0); ThisAndAdjacentFilesBB[f] = FileBB[f] | AdjacentFilesBB[f]; } for (Rank r = RANK_1; r < RANK_8; r++) InFrontBB[WHITE][r] = ~(InFrontBB[BLACK][r + 1] = InFrontBB[BLACK][r] | RankBB[r]); for (Color c = WHITE; c <= BLACK; c++) for (Square s = SQ_A1; s <= SQ_H8; s++) { ForwardBB[c][s] = InFrontBB[c][rank_of(s)] & FileBB[file_of(s)]; PassedPawnMask[c][s] = InFrontBB[c][rank_of(s)] & ThisAndAdjacentFilesBB[file_of(s)]; AttackSpanMask[c][s] = InFrontBB[c][rank_of(s)] & AdjacentFilesBB[file_of(s)]; } for (Square s1 = SQ_A1; s1 <= SQ_H8; s1++) for (Square s2 = SQ_A1; s2 <= SQ_H8; s2++) SquareDistance[s1][s2] = std::max(file_distance(s1, s2), rank_distance(s1, s2)); for (Square s1 = SQ_A1; s1 <= SQ_H8; s1++) for (int d = 1; d < 8; d++) for (Square s2 = SQ_A1; s2 <= SQ_H8; s2++) if (SquareDistance[s1][s2] == d) DistanceRingsBB[s1][d - 1] |= s2; int steps[][9] = { {}, { 7, 9 }, { 17, 15, 10, 6, -6, -10, -15, -17 }, {}, {}, {}, { 9, 7, -7, -9, 8, 1, -1, -8 } }; for (Color c = WHITE; c <= BLACK; c++) for (PieceType pt = PAWN; pt <= KING; pt++) for (Square s = SQ_A1; s <= SQ_H8; s++) for (int k = 0; steps[pt][k]; k++) { Square to = s + Square(c == WHITE ? steps[pt][k] : -steps[pt][k]); if (is_ok(to) && square_distance(s, to) < 3) StepAttacksBB[make_piece(c, pt)][s] |= to; } Square RDeltas[] = { DELTA_N, DELTA_E, DELTA_S, DELTA_W }; Square BDeltas[] = { DELTA_NE, DELTA_SE, DELTA_SW, DELTA_NW }; init_magics(RTable, RAttacks, RMagics, RMasks, RShifts, RDeltas, magic_index); init_magics(BTable, BAttacks, BMagics, BMasks, BShifts, BDeltas, magic_index); for (Square s = SQ_A1; s <= SQ_H8; s++) { PseudoAttacks[QUEEN][s] = PseudoAttacks[BISHOP][s] = attacks_bb(s, 0); PseudoAttacks[QUEEN][s] |= PseudoAttacks[ ROOK][s] = attacks_bb< ROOK>(s, 0); } for (Square s1 = SQ_A1; s1 <= SQ_H8; s1++) for (Square s2 = SQ_A1; s2 <= SQ_H8; s2++) if (PseudoAttacks[QUEEN][s1] & s2) { Square delta = (s2 - s1) / square_distance(s1, s2); for (Square s = s1 + delta; s != s2; s += delta) BetweenBB[s1][s2] |= s; } } namespace { Bitboard sliding_attack(Square deltas[], Square sq, Bitboard occupied) { Bitboard attack = 0; for (int i = 0; i < 4; i++) for (Square s = sq + deltas[i]; is_ok(s) && square_distance(s, s - deltas[i]) == 1; s += deltas[i]) { attack |= s; if (occupied & s) break; } return attack; } Bitboard pick_random(RKISS& rk, int booster) { // Values s1 and s2 are used to rotate the candidate magic of a // quantity known to be the optimal to quickly find the magics. int s1 = booster & 63, s2 = (booster >> 6) & 63; Bitboard m = rk.rand(); m = (m >> s1) | (m << (64 - s1)); m &= rk.rand(); m = (m >> s2) | (m << (64 - s2)); return m & rk.rand(); } // init_magics() computes all rook and bishop attacks at startup. Magic // bitboards are used to look up attacks of sliding pieces. As a reference see // chessprogramming.wikispaces.com/Magic+Bitboards. In particular, here we // use the so called "fancy" approach. void init_magics(Bitboard table[], Bitboard* attacks[], Bitboard magics[], Bitboard masks[], unsigned shifts[], Square deltas[], Fn index) { int MagicBoosters[][8] = { { 3191, 2184, 1310, 3618, 2091, 1308, 2452, 3996 }, { 1059, 3608, 605, 3234, 3326, 38, 2029, 3043 } }; RKISS rk; Bitboard occupancy[4096], reference[4096], edges, b; int i, size, booster; // attacks[s] is a pointer to the beginning of the attacks table for square 's' attacks[SQ_A1] = table; for (Square s = SQ_A1; s <= SQ_H8; s++) { // Board edges are not considered in the relevant occupancies edges = ((Rank1BB | Rank8BB) & ~rank_bb(s)) | ((FileABB | FileHBB) & ~file_bb(s)); // Given a square 's', the mask is the bitboard of sliding attacks from // 's' computed on an empty board. The index must be big enough to contain // all the attacks for each possible subset of the mask and so is 2 power // the number of 1s of the mask. Hence we deduce the size of the shift to // apply to the 64 or 32 bits word to get the index. masks[s] = sliding_attack(deltas, s, 0) & ~edges; shifts[s] = (Is64Bit ? 64 : 32) - popcount(masks[s]); // Use Carry-Rippler trick to enumerate all subsets of masks[s] and // store the corresponding sliding attack bitboard in reference[]. b = size = 0; do { occupancy[size] = b; reference[size++] = sliding_attack(deltas, s, b); b = (b - masks[s]) & masks[s]; } while (b); // Set the offset for the table of the next square. We have individual // table sizes for each square with "Fancy Magic Bitboards". if (s < SQ_H8) attacks[s + 1] = attacks[s] + size; booster = MagicBoosters[Is64Bit][rank_of(s)]; // Find a magic for square 's' picking up an (almost) random number // until we find the one that passes the verification test. do { do magics[s] = pick_random(rk, booster); while (popcount((magics[s] * masks[s]) >> 56) < 6); memset(attacks[s], 0, size * sizeof(Bitboard)); // A good magic must map every possible occupancy to an index that // looks up the correct sliding attack in the attacks[s] database. // Note that we build up the database for square 's' as a side // effect of verifying the magic. for (i = 0; i < size; i++) { Bitboard& attack = attacks[s][index(s, occupancy[i])]; if (attack && attack != reference[i]) break; assert(reference[i] != 0); attack = reference[i]; } } while (i != size); } } } stockfish-3.0.0+git20130508/src/platform.h0000644000175000017500000001037612142540127017264 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #if !defined(PLATFORM_H_INCLUDED) #define PLATFORM_H_INCLUDED #if defined(_MSC_VER) // Disable some silly and noisy warning from MSVC compiler #pragma warning(disable: 4127) // Conditional expression is constant #pragma warning(disable: 4146) // Unary minus operator applied to unsigned type #pragma warning(disable: 4800) // Forcing value to bool 'true' or 'false' #pragma warning(disable: 4996) // Function _ftime() may be unsafe // MSVC does not support typedef signed __int8 int8_t; typedef unsigned __int8 uint8_t; typedef signed __int16 int16_t; typedef unsigned __int16 uint16_t; typedef signed __int32 int32_t; typedef unsigned __int32 uint32_t; typedef signed __int64 int64_t; typedef unsigned __int64 uint64_t; #else # include # include // Used by sysconf(_SC_NPROCESSORS_ONLN) #endif #if !defined(_WIN32) // Linux - Unix # include typedef timeval sys_time_t; inline void system_time(sys_time_t* t) { gettimeofday(t, NULL); } inline int64_t time_to_msec(const sys_time_t& t) { return t.tv_sec * 1000LL + t.tv_usec / 1000; } # include typedef pthread_mutex_t Lock; typedef pthread_cond_t WaitCondition; typedef pthread_t NativeHandle; typedef void*(*pt_start_fn)(void*); # define lock_init(x) pthread_mutex_init(&(x), NULL) # define lock_grab(x) pthread_mutex_lock(&(x)) # define lock_release(x) pthread_mutex_unlock(&(x)) # define lock_destroy(x) pthread_mutex_destroy(&(x)) # define cond_destroy(x) pthread_cond_destroy(&(x)) # define cond_init(x) pthread_cond_init(&(x), NULL) # define cond_signal(x) pthread_cond_signal(&(x)) # define cond_wait(x,y) pthread_cond_wait(&(x),&(y)) # define cond_timedwait(x,y,z) pthread_cond_timedwait(&(x),&(y),z) # define thread_create(x,f,t) !pthread_create(&(x),NULL,(pt_start_fn)f,t) # define thread_join(x) pthread_join(x, NULL) #else // Windows and MinGW # include typedef _timeb sys_time_t; inline void system_time(sys_time_t* t) { _ftime(t); } inline int64_t time_to_msec(const sys_time_t& t) { return t.time * 1000LL + t.millitm; } #if !defined(NOMINMAX) # define NOMINMAX // disable macros min() and max() #endif #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN #undef NOMINMAX // We use critical sections on Windows to support Windows XP and older versions, // unfortunatly cond_wait() is racy between lock_release() and WaitForSingleObject() // but apart from this they have the same speed performance of SRW locks. typedef CRITICAL_SECTION Lock; typedef HANDLE WaitCondition; typedef HANDLE NativeHandle; // On Windows 95 and 98 parameter lpThreadId my not be null inline DWORD* dwWin9xKludge() { static DWORD dw; return &dw; } # define lock_init(x) InitializeCriticalSection(&(x)) # define lock_grab(x) EnterCriticalSection(&(x)) # define lock_release(x) LeaveCriticalSection(&(x)) # define lock_destroy(x) DeleteCriticalSection(&(x)) # define cond_init(x) { x = CreateEvent(0, FALSE, FALSE, 0); } # define cond_destroy(x) CloseHandle(x) # define cond_signal(x) SetEvent(x) # define cond_wait(x,y) { lock_release(y); WaitForSingleObject(x, INFINITE); lock_grab(y); } # define cond_timedwait(x,y,z) { lock_release(y); WaitForSingleObject(x,z); lock_grab(y); } # define thread_create(x,f,t) (x = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)f,t,0,dwWin9xKludge()), x != NULL) # define thread_join(x) { WaitForSingleObject(x, INFINITE); CloseHandle(x); } #endif #endif // !defined(PLATFORM_H_INCLUDED) stockfish-3.0.0+git20130508/src/uci.cpp0000644000175000017500000001646412142540127016557 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include "evaluate.h" #include "notation.h" #include "position.h" #include "search.h" #include "thread.h" #include "tt.h" #include "ucioption.h" using namespace std; extern void benchmark(const Position& pos, istream& is); namespace { // FEN string of the initial position, normal chess const char* StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; // Keep track of position keys along the setup moves (from start position to the // position just before to start searching). Needed by repetition draw detection. Search::StateStackPtr SetupStates; void set_option(istringstream& up); void set_position(Position& pos, istringstream& up); void go(const Position& pos, istringstream& up); } /// Wait for a command from the user, parse this text string as an UCI command, /// and call the appropriate functions. Also intercepts EOF from stdin to ensure /// that we exit gracefully if the GUI dies unexpectedly. In addition to the UCI /// commands, the function also supports a few debug commands. void UCI::loop(const string& args) { Position pos(StartFEN, false, Threads.main_thread()); // The root position string token, cmd = args; do { if (args.empty() && !getline(cin, cmd)) // Block here waiting for input cmd = "quit"; istringstream is(cmd); is >> skipws >> token; if (token == "quit" || token == "stop" || token == "ponderhit") { // GUI sends 'ponderhit' to tell us to ponder on the same move the // opponent has played. In case Signals.stopOnPonderhit is set we are // waiting for 'ponderhit' to stop the search (for instance because we // already ran out of time), otherwise we should continue searching but // switching from pondering to normal search. if (token != "ponderhit" || Search::Signals.stopOnPonderhit) { Search::Signals.stop = true; Threads.main_thread()->notify_one(); // Could be sleeping } else Search::Limits.ponder = false; } else if (token == "perft" && (is >> token)) // Read perft depth { stringstream ss; ss << Options["Hash"] << " " << Options["Threads"] << " " << token << " current perft"; benchmark(pos, ss); } else if (token == "key") sync_cout << hex << uppercase << setfill('0') << "position key: " << setw(16) << pos.key() << "\nmaterial key: " << setw(16) << pos.material_key() << "\npawn key: " << setw(16) << pos.pawn_key() << dec << sync_endl; else if (token == "uci") sync_cout << "id name " << engine_info(true) << "\n" << Options << "\nuciok" << sync_endl; else if (token == "ucinewgame") TT.clear(); else if (token == "go") go(pos, is); else if (token == "position") set_position(pos, is); else if (token == "setoption") set_option(is); else if (token == "flip") pos.flip(); else if (token == "bench") benchmark(pos, is); else if (token == "d") sync_cout << pos.pretty() << sync_endl; else if (token == "isready") sync_cout << "readyok" << sync_endl; else if (token == "eval") sync_cout << Eval::trace(pos) << sync_endl; else sync_cout << "Unknown command: " << cmd << sync_endl; } while (token != "quit" && args.empty()); // Args have one-shot behaviour Threads.wait_for_think_finished(); // Cannot quit while search is running } namespace { // set_position() is called when engine receives the "position" UCI command. // The function sets up the position described in the given fen string ("fen") // or the starting position ("startpos") and then makes the moves given in the // following move list ("moves"). void set_position(Position& pos, istringstream& is) { Move m; string token, fen; is >> token; if (token == "startpos") { fen = StartFEN; is >> token; // Consume "moves" token if any } else if (token == "fen") while (is >> token && token != "moves") fen += token + " "; else return; pos.set(fen, Options["UCI_Chess960"], Threads.main_thread()); SetupStates = Search::StateStackPtr(new std::stack()); // Parse move list (if any) while (is >> token && (m = move_from_uci(pos, token)) != MOVE_NONE) { SetupStates->push(StateInfo()); pos.do_move(m, SetupStates->top()); } } // set_option() is called when engine receives the "setoption" UCI command. The // function updates the UCI option ("name") to the given value ("value"). void set_option(istringstream& is) { string token, name, value; is >> token; // Consume "name" token // Read option name (can contain spaces) while (is >> token && token != "value") name += string(" ", !name.empty()) + token; // Read option value (can contain spaces) while (is >> token) value += string(" ", !value.empty()) + token; if (Options.count(name)) Options[name] = value; else sync_cout << "No such option: " << name << sync_endl; } // go() is called when engine receives the "go" UCI command. The function sets // the thinking time and other parameters from the input string, and starts // the search. void go(const Position& pos, istringstream& is) { Search::LimitsType limits; vector searchMoves; string token; while (is >> token) { if (token == "searchmoves") while (is >> token) searchMoves.push_back(move_from_uci(pos, token)); else if (token == "wtime") is >> limits.time[WHITE]; else if (token == "btime") is >> limits.time[BLACK]; else if (token == "winc") is >> limits.inc[WHITE]; else if (token == "binc") is >> limits.inc[BLACK]; else if (token == "movestogo") is >> limits.movestogo; else if (token == "depth") is >> limits.depth; else if (token == "nodes") is >> limits.nodes; else if (token == "movetime") is >> limits.movetime; else if (token == "mate") is >> limits.mate; else if (token == "infinite") limits.infinite = true; else if (token == "ponder") limits.ponder = true; } Threads.start_thinking(pos, limits, searchMoves, SetupStates); } } stockfish-3.0.0+git20130508/src/movegen.h0000644000175000017500000000337412142540127017100 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #if !defined(MOVEGEN_H_INCLUDED) #define MOVEGEN_H_INCLUDED #include "types.h" enum GenType { CAPTURES, QUIETS, QUIET_CHECKS, EVASIONS, NON_EVASIONS, LEGAL }; class Position; template MoveStack* generate(const Position& pos, MoveStack* mlist); /// The MoveList struct is a simple wrapper around generate(), sometimes comes /// handy to use this class instead of the low level generate() function. template struct MoveList { explicit MoveList(const Position& pos) : cur(mlist), last(generate(pos, mlist)) {} void operator++() { cur++; } bool end() const { return cur == last; } Move move() const { return cur->move; } size_t size() const { return last - mlist; } bool contains(Move m) const { for (const MoveStack* it(mlist); it != last; ++it) if (it->move == m) return true; return false; } private: MoveStack mlist[MAX_MOVES]; MoveStack *cur, *last; }; #endif // !defined(MOVEGEN_H_INCLUDED) stockfish-3.0.0+git20130508/src/search.h0000644000175000017500000000645512142540127016710 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #if !defined(SEARCH_H_INCLUDED) #define SEARCH_H_INCLUDED #include #include #include #include #include "misc.h" #include "position.h" #include "types.h" struct SplitPoint; namespace Search { /// The Stack struct keeps track of the information we need to remember from /// nodes shallower and deeper in the tree during the search. Each search thread /// has its own array of Stack objects, indexed by the current ply. struct Stack { SplitPoint* splitPoint; int ply; Move currentMove; Move excludedMove; Move killers[2]; Depth reduction; Value staticEval; Value evalMargin; int skipNullMove; int futilityMoveCount; }; /// RootMove struct is used for moves at the root of the tree. For each root /// move we store a score, a node count, and a PV (really a refutation in the /// case of moves which fail low). Score is normally set at -VALUE_INFINITE for /// all non-pv moves. struct RootMove { RootMove(Move m) : score(-VALUE_INFINITE), prevScore(-VALUE_INFINITE) { pv.push_back(m); pv.push_back(MOVE_NONE); } bool operator<(const RootMove& m) const { return score > m.score; } // Ascending sort bool operator==(const Move& m) const { return pv[0] == m; } void extract_pv_from_tt(Position& pos); void insert_pv_in_tt(Position& pos); Value score; Value prevScore; std::vector pv; }; /// The LimitsType struct stores information sent by GUI about available time /// to search the current move, maximum depth/time, if we are in analysis mode /// or if we have to ponder while is our opponent's side to move. struct LimitsType { LimitsType() { memset(this, 0, sizeof(LimitsType)); } bool use_time_management() const { return !(mate | movetime | depth | nodes | infinite); } int time[COLOR_NB], inc[COLOR_NB], movestogo, depth, nodes, movetime, mate, infinite, ponder; }; /// The SignalsType struct stores volatile flags updated during the search /// typically in an async fashion, for instance to stop the search by the GUI. struct SignalsType { bool stopOnPonderhit, firstRootMove, stop, failedLowAtRoot; }; typedef std::auto_ptr > StateStackPtr; extern volatile SignalsType Signals; extern LimitsType Limits; extern std::vector RootMoves; extern Position RootPos; extern Color RootColor; extern Time::point SearchTime; extern StateStackPtr SetupStates; extern void init(); extern size_t perft(Position& pos, Depth depth); extern void think(); } // namespace Search #endif // !defined(SEARCH_H_INCLUDED) stockfish-3.0.0+git20130508/src/misc.h0000644000175000017500000000361612142540127016372 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #if !defined(MISC_H_INCLUDED) #define MISC_H_INCLUDED #include #include #include #include "types.h" extern const std::string engine_info(bool to_uci = false); extern int cpu_count(); extern void timed_wait(WaitCondition&, Lock&, int); extern void prefetch(char* addr); extern void start_logger(bool b); extern void dbg_hit_on(bool b); extern void dbg_hit_on_c(bool c, bool b); extern void dbg_mean_of(int v); extern void dbg_print(); struct Log : public std::ofstream { Log(const std::string& f = "log.txt") : std::ofstream(f.c_str(), std::ios::out | std::ios::app) {} ~Log() { if (is_open()) close(); } }; namespace Time { typedef int64_t point; point now(); } template struct HashTable { HashTable() : e(Size, Entry()) {} Entry* operator[](Key k) { return &e[(uint32_t)k & (Size - 1)]; } private: std::vector e; }; enum SyncCout { io_lock, io_unlock }; std::ostream& operator<<(std::ostream&, SyncCout); #define sync_cout std::cout << io_lock #define sync_endl std::endl << io_unlock #endif // !defined(MISC_H_INCLUDED) stockfish-3.0.0+git20130508/src/movepick.cpp0000644000175000017500000002574212142540127017613 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "movepick.h" #include "thread.h" namespace { enum Sequencer { MAIN_SEARCH, CAPTURES_S1, KILLERS_S1, QUIETS_1_S1, QUIETS_2_S1, BAD_CAPTURES_S1, EVASION, EVASIONS_S2, QSEARCH_0, CAPTURES_S3, QUIET_CHECKS_S3, QSEARCH_1, CAPTURES_S4, PROBCUT, CAPTURES_S5, RECAPTURE, CAPTURES_S6, STOP }; // Our insertion sort, guaranteed to be stable, as is needed void insertion_sort(MoveStack* begin, MoveStack* end) { MoveStack tmp, *p, *q; for (p = begin + 1; p < end; ++p) { tmp = *p; for (q = p; q != begin && *(q-1) < tmp; --q) *q = *(q-1); *q = tmp; } } // Unary predicate used by std::partition to split positive scores from remaining // ones so to sort separately the two sets, and with the second sort delayed. inline bool has_positive_score(const MoveStack& ms) { return ms.score > 0; } // Picks and moves to the front the best move in the range [begin, end), // it is faster than sorting all the moves in advance when moves are few, as // normally are the possible captures. inline MoveStack* pick_best(MoveStack* begin, MoveStack* end) { std::swap(*begin, *std::max_element(begin, end)); return begin; } } /// Constructors of the MovePicker class. As arguments we pass information /// to help it to return the presumably good moves first, to decide which /// moves to return (in the quiescence search, for instance, we only want to /// search captures, promotions and some checks) and about how important good /// move ordering is at the current node. MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const History& h, Search::Stack* s, Value beta) : pos(p), Hist(h), depth(d) { assert(d > DEPTH_ZERO); captureThreshold = 0; cur = end = moves; endBadCaptures = moves + MAX_MOVES - 1; ss = s; if (p.checkers()) phase = EVASION; else { phase = MAIN_SEARCH; killers[0].move = ss->killers[0]; killers[1].move = ss->killers[1]; // Consider sligtly negative captures as good if at low depth and far from beta if (ss && ss->staticEval < beta - PawnValueMg && d < 3 * ONE_PLY) captureThreshold = -PawnValueMg; // Consider negative captures as good if still enough to reach beta else if (ss && ss->staticEval > beta) captureThreshold = beta - ss->staticEval; } ttMove = (ttm && pos.is_pseudo_legal(ttm) ? ttm : MOVE_NONE); end += (ttMove != MOVE_NONE); } MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const History& h, Square sq) : pos(p), Hist(h), cur(moves), end(moves) { assert(d <= DEPTH_ZERO); if (p.checkers()) phase = EVASION; else if (d > DEPTH_QS_NO_CHECKS) phase = QSEARCH_0; else if (d > DEPTH_QS_RECAPTURES) { phase = QSEARCH_1; // Skip TT move if is not a capture or a promotion, this avoids qsearch // tree explosion due to a possible perpetual check or similar rare cases // when TT table is full. if (ttm && !pos.is_capture_or_promotion(ttm)) ttm = MOVE_NONE; } else { phase = RECAPTURE; recaptureSquare = sq; ttm = MOVE_NONE; } ttMove = (ttm && pos.is_pseudo_legal(ttm) ? ttm : MOVE_NONE); end += (ttMove != MOVE_NONE); } MovePicker::MovePicker(const Position& p, Move ttm, const History& h, PieceType pt) : pos(p), Hist(h), cur(moves), end(moves) { assert(!pos.checkers()); phase = PROBCUT; // In ProbCut we generate only captures better than parent's captured piece captureThreshold = PieceValue[MG][pt]; ttMove = (ttm && pos.is_pseudo_legal(ttm) ? ttm : MOVE_NONE); if (ttMove && (!pos.is_capture(ttMove) || pos.see(ttMove) <= captureThreshold)) ttMove = MOVE_NONE; end += (ttMove != MOVE_NONE); } /// score() assign a numerical move ordering score to each move in a move list. /// The moves with highest scores will be picked first. template<> void MovePicker::score() { // Winning and equal captures in the main search are ordered by MVV/LVA. // 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 // 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. // In main search we want to push captures with negative SEE values to // badCaptures[] array, but instead of doing it now we delay till when // the move has been picked up in pick_move_from_list(), this way we save // some SEE calls in case we get a cutoff (idea from Pablo Vazquez). Move m; for (MoveStack* it = moves; it != end; ++it) { m = it->move; it->score = PieceValue[MG][pos.piece_on(to_sq(m))] - type_of(pos.piece_moved(m)); if (type_of(m) == PROMOTION) it->score += PieceValue[MG][promotion_type(m)] - PieceValue[MG][PAWN]; else if (type_of(m) == ENPASSANT) it->score += PieceValue[MG][PAWN]; } } template<> void MovePicker::score() { Move m; for (MoveStack* it = moves; it != end; ++it) { m = it->move; it->score = Hist[pos.piece_moved(m)][to_sq(m)]; } } template<> void MovePicker::score() { // Try good captures ordered by MVV/LVA, then non-captures if destination square // is not under attack, ordered by history value, then bad-captures and quiet // moves with a negative SEE. This last group is ordered by the SEE score. Move m; int seeScore; for (MoveStack* it = moves; it != end; ++it) { m = it->move; if ((seeScore = pos.see_sign(m)) < 0) it->score = seeScore - History::Max; // At the bottom else if (pos.is_capture(m)) it->score = PieceValue[MG][pos.piece_on(to_sq(m))] - type_of(pos.piece_moved(m)) + History::Max; else it->score = Hist[pos.piece_moved(m)][to_sq(m)]; } } /// generate_next() generates, scores and sorts the next bunch of moves, when /// there are no more moves to try for the current phase. void MovePicker::generate_next() { cur = moves; switch (++phase) { case CAPTURES_S1: case CAPTURES_S3: case CAPTURES_S4: case CAPTURES_S5: case CAPTURES_S6: end = generate(pos, moves); score(); return; case KILLERS_S1: cur = killers; end = cur + 2; return; case QUIETS_1_S1: endQuiets = end = generate(pos, moves); score(); end = std::partition(cur, end, has_positive_score); insertion_sort(cur, end); return; case QUIETS_2_S1: cur = end; end = endQuiets; if (depth >= 3 * ONE_PLY) insertion_sort(cur, end); return; case BAD_CAPTURES_S1: // Just pick them in reverse order to get MVV/LVA ordering cur = moves + MAX_MOVES - 1; end = endBadCaptures; return; case EVASIONS_S2: end = generate(pos, moves); if (end > moves + 1) score(); return; case QUIET_CHECKS_S3: end = generate(pos, moves); return; case EVASION: case QSEARCH_0: case QSEARCH_1: case PROBCUT: case RECAPTURE: phase = STOP; case STOP: end = cur + 1; // Avoid another next_phase() call return; default: assert(false); } } /// next_move() is the most important method of the MovePicker class. It returns /// a new pseudo legal move every time is called, until there are no more moves /// left. It picks the move with the biggest score from a list of generated moves /// taking care not returning the ttMove if has already been searched previously. template<> Move MovePicker::next_move() { Move move; while (true) { while (cur == end) generate_next(); switch (phase) { case MAIN_SEARCH: case EVASION: case QSEARCH_0: case QSEARCH_1: case PROBCUT: cur++; return ttMove; case CAPTURES_S1: move = pick_best(cur++, end)->move; if (move != ttMove) { assert(captureThreshold <= 0); // Otherwise we cannot use see_sign() if (pos.see_sign(move) >= captureThreshold) return move; // Losing capture, move it to the tail of the array (endBadCaptures--)->move = move; } break; case KILLERS_S1: move = (cur++)->move; if ( move != MOVE_NONE && pos.is_pseudo_legal(move) && move != ttMove && !pos.is_capture(move)) return move; break; case QUIETS_1_S1: case QUIETS_2_S1: move = (cur++)->move; if ( move != ttMove && move != killers[0].move && move != killers[1].move) return move; break; case BAD_CAPTURES_S1: return (cur--)->move; case EVASIONS_S2: case CAPTURES_S3: case CAPTURES_S4: move = pick_best(cur++, end)->move; if (move != ttMove) return move; break; case CAPTURES_S5: move = pick_best(cur++, end)->move; if (move != ttMove && pos.see(move) > captureThreshold) return move; break; case CAPTURES_S6: move = pick_best(cur++, end)->move; if (to_sq(move) == recaptureSquare) return move; break; case QUIET_CHECKS_S3: move = (cur++)->move; if (move != ttMove) return move; break; case STOP: return MOVE_NONE; default: assert(false); } } } /// Version of next_move() to use at split point nodes where the move is grabbed /// from the split point's shared MovePicker object. This function is not thread /// safe so must be lock protected by the caller. template<> Move MovePicker::next_move() { return ss->splitPoint->movePicker->next_move(); } stockfish-3.0.0+git20130508/src/movegen.cpp0000644000175000017500000003516012142540127017431 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "movegen.h" #include "position.h" /// Simple macro to wrap a very common while loop, no facny, no flexibility, /// hardcoded names 'mlist' and 'from'. #define SERIALIZE(b) while (b) (*mlist++).move = make_move(from, pop_lsb(&b)) /// Version used for pawns, where the 'from' square is given as a delta from the 'to' square #define SERIALIZE_PAWNS(b, d) while (b) { Square to = pop_lsb(&b); \ (*mlist++).move = make_move(to - (d), to); } namespace { template MoveStack* generate_castle(const Position& pos, MoveStack* mlist, Color us) { if (pos.castle_impeded(us, Side) || !pos.can_castle(make_castle_right(us, Side))) return mlist; // After castling, the rook and king final positions are the same in Chess960 // as they would be in standard chess. Square kfrom = pos.king_square(us); Square rfrom = pos.castle_rook_square(us, Side); Square kto = relative_square(us, Side == KING_SIDE ? SQ_G1 : SQ_C1); Bitboard enemies = pos.pieces(~us); assert(!pos.checkers()); const int K = Chess960 ? kto > kfrom ? -1 : 1 : Side == KING_SIDE ? -1 : 1; for (Square s = kto; s != kfrom; s += (Square)K) if (pos.attackers_to(s) & enemies) return mlist; // Because we generate only legal castling moves we need to verify that // when moving the castling rook we do not discover some hidden checker. // For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1. if (Chess960 && (pos.attackers_to(kto, pos.pieces() ^ rfrom) & enemies)) return mlist; (*mlist++).move = make(kfrom, rfrom); if (Checks && !pos.move_gives_check((mlist - 1)->move, CheckInfo(pos))) mlist--; return mlist; } template inline Bitboard move_pawns(Bitboard p) { return Delta == DELTA_N ? p << 8 : Delta == DELTA_S ? p >> 8 : Delta == DELTA_NE ? (p & ~FileHBB) << 9 : Delta == DELTA_SE ? (p & ~FileHBB) >> 7 : Delta == DELTA_NW ? (p & ~FileABB) << 7 : Delta == DELTA_SW ? (p & ~FileABB) >> 9 : 0; } template inline MoveStack* generate_promotions(MoveStack* mlist, Bitboard pawnsOn7, Bitboard target, const CheckInfo* ci) { Bitboard b = move_pawns(pawnsOn7) & target; while (b) { Square to = pop_lsb(&b); if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS) (*mlist++).move = make(to - Delta, to, QUEEN); if (Type == QUIETS || Type == EVASIONS || Type == NON_EVASIONS) { (*mlist++).move = make(to - Delta, to, ROOK); (*mlist++).move = make(to - Delta, to, BISHOP); (*mlist++).move = make(to - Delta, to, KNIGHT); } // Knight-promotion is the only one that can give a direct check not // already included in the queen-promotion. if (Type == QUIET_CHECKS && (StepAttacksBB[W_KNIGHT][to] & ci->ksq)) (*mlist++).move = make(to - Delta, to, KNIGHT); else (void)ci; // Silence a warning under MSVC } return mlist; } template MoveStack* generate_pawn_moves(const Position& pos, MoveStack* mlist, Bitboard target, const CheckInfo* ci) { // Compute our parametrized parameters at compile time, named according to // the point of view of white side. const Color Them = (Us == WHITE ? BLACK : WHITE); const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB); const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB); const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); const Square UP = (Us == WHITE ? DELTA_N : DELTA_S); const Square RIGHT = (Us == WHITE ? DELTA_NE : DELTA_SW); const Square LEFT = (Us == WHITE ? DELTA_NW : DELTA_SE); Bitboard b1, b2, dc1, dc2, emptySquares; Bitboard pawnsOn7 = pos.pieces(Us, PAWN) & TRank7BB; Bitboard pawnsNotOn7 = pos.pieces(Us, PAWN) & ~TRank7BB; Bitboard enemies = (Type == EVASIONS ? pos.pieces(Them) & target: Type == CAPTURES ? target : pos.pieces(Them)); // Single and double pawn pushes, no promotions if (Type != CAPTURES) { emptySquares = (Type == QUIETS || Type == QUIET_CHECKS ? target : ~pos.pieces()); b1 = move_pawns(pawnsNotOn7) & emptySquares; b2 = move_pawns(b1 & TRank3BB) & emptySquares; if (Type == EVASIONS) // Consider only blocking squares { b1 &= target; b2 &= target; } if (Type == QUIET_CHECKS) { b1 &= pos.attacks_from(ci->ksq, Them); b2 &= pos.attacks_from(ci->ksq, Them); // Add pawn pushes which give discovered check. This is possible only // if the pawn is not on the same file as the enemy king, because we // don't generate captures. Note that a possible discovery check // promotion has been already generated among captures. if (pawnsNotOn7 & ci->dcCandidates) { dc1 = move_pawns(pawnsNotOn7 & ci->dcCandidates) & emptySquares & ~file_bb(ci->ksq); dc2 = move_pawns(dc1 & TRank3BB) & emptySquares; b1 |= dc1; b2 |= dc2; } } SERIALIZE_PAWNS(b1, UP); SERIALIZE_PAWNS(b2, UP + UP); } // Promotions and underpromotions if (pawnsOn7 && (Type != EVASIONS || (target & TRank8BB))) { if (Type == CAPTURES) emptySquares = ~pos.pieces(); if (Type == EVASIONS) emptySquares &= target; mlist = generate_promotions(mlist, pawnsOn7, enemies, ci); mlist = generate_promotions(mlist, pawnsOn7, enemies, ci); mlist = generate_promotions(mlist, pawnsOn7, emptySquares, ci); } // Standard and en-passant captures if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS) { b1 = move_pawns(pawnsNotOn7) & enemies; b2 = move_pawns(pawnsNotOn7) & enemies; SERIALIZE_PAWNS(b1, RIGHT); SERIALIZE_PAWNS(b2, LEFT); if (pos.ep_square() != SQ_NONE) { assert(rank_of(pos.ep_square()) == relative_rank(Us, RANK_6)); // An en passant capture can be an evasion only if the checking piece // is the double pushed pawn and so is in the target. Otherwise this // is a discovery check and we are forced to do otherwise. if (Type == EVASIONS && !(target & (pos.ep_square() - UP))) return mlist; b1 = pawnsNotOn7 & pos.attacks_from(pos.ep_square(), Them); assert(b1); while (b1) (*mlist++).move = make(pop_lsb(&b1), pos.ep_square()); } } return mlist; } template FORCE_INLINE MoveStack* generate_moves(const Position& pos, MoveStack* mlist, Color us, Bitboard target, const CheckInfo* ci) { assert(Pt != KING && Pt != PAWN); const Square* pl = pos.piece_list(us, Pt); for (Square from = *pl; from != SQ_NONE; from = *++pl) { if (Checks) { if ( (Pt == BISHOP || Pt == ROOK || Pt == QUEEN) && !(PseudoAttacks[Pt][from] & target & ci->checkSq[Pt])) continue; if (ci->dcCandidates && (ci->dcCandidates & from)) continue; } Bitboard b = pos.attacks_from(from) & target; if (Checks) b &= ci->checkSq[Pt]; SERIALIZE(b); } return mlist; } template FORCE_INLINE MoveStack* generate_all(const Position& pos, MoveStack* mlist, Color us, Bitboard target, const CheckInfo* ci = NULL) { const bool Checks = Type == QUIET_CHECKS; mlist = (us == WHITE ? generate_pawn_moves(pos, mlist, target, ci) : generate_pawn_moves(pos, mlist, target, ci)); mlist = generate_moves(pos, mlist, us, target, ci); mlist = generate_moves(pos, mlist, us, target, ci); mlist = generate_moves(pos, mlist, us, target, ci); mlist = generate_moves(pos, mlist, us, target, ci); if (Type != QUIET_CHECKS && Type != EVASIONS) { Square from = pos.king_square(us); Bitboard b = pos.attacks_from(from) & target; SERIALIZE(b); } if (Type != CAPTURES && Type != EVASIONS && pos.can_castle(us)) { if (pos.is_chess960()) { mlist = generate_castle(pos, mlist, us); mlist = generate_castle(pos, mlist, us); } else { mlist = generate_castle(pos, mlist, us); mlist = generate_castle(pos, mlist, us); } } return mlist; } } // namespace /// generate generates all pseudo-legal captures and queen /// promotions. Returns a pointer to the end of the move list. /// /// generate generates all pseudo-legal non-captures and /// underpromotions. Returns a pointer to the end of the move list. /// /// generate generates all pseudo-legal captures and /// non-captures. Returns a pointer to the end of the move list. template MoveStack* generate(const Position& pos, MoveStack* mlist) { assert(Type == CAPTURES || Type == QUIETS || Type == NON_EVASIONS); assert(!pos.checkers()); Color us = pos.side_to_move(); Bitboard target = Type == CAPTURES ? pos.pieces(~us) : Type == QUIETS ? ~pos.pieces() : Type == NON_EVASIONS ? ~pos.pieces(us) : 0; return generate_all(pos, mlist, us, target); } // Explicit template instantiations template MoveStack* generate(const Position&, MoveStack*); template MoveStack* generate(const Position&, MoveStack*); template MoveStack* generate(const Position&, MoveStack*); /// generate generates all pseudo-legal non-captures and knight /// underpromotions that give check. Returns a pointer to the end of the move list. template<> MoveStack* generate(const Position& pos, MoveStack* mlist) { assert(!pos.checkers()); CheckInfo ci(pos); Bitboard dc = ci.dcCandidates; while (dc) { Square from = pop_lsb(&dc); PieceType pt = type_of(pos.piece_on(from)); if (pt == PAWN) continue; // Will be generated togheter with direct checks Bitboard b = pos.attacks_from(Piece(pt), from) & ~pos.pieces(); if (pt == KING) b &= ~PseudoAttacks[QUEEN][ci.ksq]; SERIALIZE(b); } return generate_all(pos, mlist, pos.side_to_move(), ~pos.pieces(), &ci); } /// generate generates all pseudo-legal check evasions when the side /// to move is in check. Returns a pointer to the end of the move list. template<> MoveStack* generate(const Position& pos, MoveStack* mlist) { assert(pos.checkers()); Square from, checksq; int checkersCnt = 0; Color us = pos.side_to_move(); Square ksq = pos.king_square(us); Bitboard sliderAttacks = 0; Bitboard b = pos.checkers(); assert(pos.checkers()); // Find squares attacked by slider checkers, we will remove them from the king // evasions so to skip known illegal moves avoiding useless legality check later. do { checkersCnt++; checksq = pop_lsb(&b); assert(color_of(pos.piece_on(checksq)) == ~us); switch (type_of(pos.piece_on(checksq))) { case BISHOP: sliderAttacks |= PseudoAttacks[BISHOP][checksq]; break; case ROOK: sliderAttacks |= PseudoAttacks[ROOK][checksq]; break; case QUEEN: // If queen and king are far or not on a diagonal line we can safely // remove all the squares attacked in the other direction becuase are // not reachable by the king anyway. if (between_bb(ksq, checksq) || !(PseudoAttacks[BISHOP][checksq] & ksq)) sliderAttacks |= PseudoAttacks[QUEEN][checksq]; // Otherwise we need to use real rook attacks to check if king is safe // to move in the other direction. For example: king in B2, queen in A1 // a knight in B1, and we can safely move to C1. else sliderAttacks |= PseudoAttacks[BISHOP][checksq] | pos.attacks_from(checksq); default: break; } } while (b); // Generate evasions for king, capture and non capture moves b = pos.attacks_from(ksq) & ~pos.pieces(us) & ~sliderAttacks; from = ksq; SERIALIZE(b); if (checkersCnt > 1) return mlist; // Double check, only a king move can save the day // Generate blocking evasions or captures of the checking piece Bitboard target = between_bb(checksq, ksq) | pos.checkers(); return generate_all(pos, mlist, us, target); } /// generate generates all the legal moves in the given position template<> MoveStack* generate(const Position& pos, MoveStack* mlist) { MoveStack *end, *cur = mlist; Bitboard pinned = pos.pinned_pieces(); Square ksq = pos.king_square(pos.side_to_move()); end = pos.checkers() ? generate(pos, mlist) : generate(pos, mlist); while (cur != end) if ( (pinned || from_sq(cur->move) == ksq || type_of(cur->move) == ENPASSANT) && !pos.pl_move_is_legal(cur->move, pinned)) cur->move = (--end)->move; else cur++; return end; } stockfish-3.0.0+git20130508/src/timeman.h0000644000175000017500000000266612142540127017075 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #if !defined(TIMEMAN_H_INCLUDED) #define TIMEMAN_H_INCLUDED /// The TimeManager class computes the optimal time to think depending on the /// maximum available time, the move game number and other parameters. class TimeManager { public: void init(const Search::LimitsType& limits, int currentPly, Color us); void pv_instability(int curChanges, int prevChanges); int available_time() const { return optimumSearchTime + unstablePVExtraTime; } int maximum_time() const { return maximumSearchTime; } private: int optimumSearchTime; int maximumSearchTime; int unstablePVExtraTime; }; #endif // !defined(TIMEMAN_H_INCLUDED) stockfish-3.0.0+git20130508/src/endgame.cpp0000644000175000017500000010515612142540127017374 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include "bitboard.h" #include "bitcount.h" #include "endgame.h" #include "movegen.h" using std::string; namespace { // Table used to drive the defending king towards the edge of the board // in KX vs K and KQ vs KR endgames. const int MateTable[SQUARE_NB] = { 100, 90, 80, 70, 70, 80, 90, 100, 90, 70, 60, 50, 50, 60, 70, 90, 80, 60, 40, 30, 30, 40, 60, 80, 70, 50, 30, 20, 20, 30, 50, 70, 70, 50, 30, 20, 20, 30, 50, 70, 80, 60, 40, 30, 30, 40, 60, 80, 90, 70, 60, 50, 50, 60, 70, 90, 100, 90, 80, 70, 70, 80, 90, 100, }; // Table used to drive the defending king towards a corner square of the // right color in KBN vs K endgames. const int KBNKMateTable[SQUARE_NB] = { 200, 190, 180, 170, 160, 150, 140, 130, 190, 180, 170, 160, 150, 140, 130, 140, 180, 170, 155, 140, 140, 125, 140, 150, 170, 160, 140, 120, 110, 140, 150, 160, 160, 150, 140, 110, 120, 140, 160, 170, 150, 140, 125, 140, 140, 155, 170, 180, 140, 130, 140, 150, 160, 170, 180, 190, 130, 140, 150, 160, 170, 180, 190, 200 }; // The attacking side is given a descending bonus based on distance between // the two kings in basic endgames. const int DistanceBonus[8] = { 0, 0, 100, 80, 60, 40, 20, 10 }; // Get the material key of a Position out of the given endgame key code // like "KBPKN". The trick here is to first forge an ad-hoc fen string // and then let a Position object to do the work for us. Note that the // fen string could correspond to an illegal position. Key key(const string& code, Color c) { assert(code.length() > 0 && code.length() < 8); assert(code[0] == 'K'); string sides[] = { code.substr(code.find('K', 1)), // Weaker code.substr(0, code.find('K', 1)) }; // Stronger std::transform(sides[c].begin(), sides[c].end(), sides[c].begin(), tolower); string fen = sides[0] + char('0' + int(8 - code.length())) + sides[1] + "/8/8/8/8/8/8/8 w - - 0 10"; return Position(fen, false, NULL).material_key(); } template void delete_endgame(const typename M::value_type& p) { delete p.second; } } // namespace /// Endgames members definitions Endgames::Endgames() { add("KPK"); add("KNNK"); add("KBNK"); add("KRKP"); add("KRKB"); add("KRKN"); add("KQKP"); add("KQKR"); add("KBBKN"); add("KNPK"); add("KNPKB"); add("KRPKR"); add("KBPKB"); add("KBPKN"); add("KBPPKB"); add("KRPPKRP"); } Endgames::~Endgames() { for_each(m1.begin(), m1.end(), delete_endgame); for_each(m2.begin(), m2.end(), delete_endgame); } template void Endgames::add(const string& code) { map((Endgame*)0)[key(code, WHITE)] = new Endgame(WHITE); map((Endgame*)0)[key(code, BLACK)] = new Endgame(BLACK); } /// Mate with KX vs K. This function is used to evaluate positions with /// King and plenty of material vs a lone king. It simply gives the /// attacking side a bonus for driving the defending king towards the edge /// of the board, and for keeping the distance between the two kings small. template<> Value Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO); assert(pos.piece_count(weakerSide, PAWN) == VALUE_ZERO); // Stalemate detection with lone king if ( pos.side_to_move() == weakerSide && !pos.checkers() && !MoveList(pos).size()) { return VALUE_DRAW; } Square winnerKSq = pos.king_square(strongerSide); Square loserKSq = pos.king_square(weakerSide); Value result = pos.non_pawn_material(strongerSide) + pos.piece_count(strongerSide, PAWN) * PawnValueEg + MateTable[loserKSq] + DistanceBonus[square_distance(winnerKSq, loserKSq)]; if ( pos.piece_count(strongerSide, QUEEN) || pos.piece_count(strongerSide, ROOK) || pos.bishop_pair(strongerSide)) { result += VALUE_KNOWN_WIN; } return strongerSide == pos.side_to_move() ? result : -result; } /// Mate with KBN vs K. This is similar to KX vs K, but we have to drive the /// defending king towards a corner square of the right color. template<> Value Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO); assert(pos.piece_count(weakerSide, PAWN) == VALUE_ZERO); assert(pos.non_pawn_material(strongerSide) == KnightValueMg + BishopValueMg); assert(pos.piece_count(strongerSide, BISHOP) == 1); assert(pos.piece_count(strongerSide, KNIGHT) == 1); assert(pos.piece_count(strongerSide, PAWN) == 0); Square winnerKSq = pos.king_square(strongerSide); Square loserKSq = pos.king_square(weakerSide); Square bishopSq = pos.piece_list(strongerSide, BISHOP)[0]; // kbnk_mate_table() tries to drive toward corners A1 or H8, // if we have a bishop that cannot reach the above squares we // mirror the kings so to drive enemy toward corners A8 or H1. if (opposite_colors(bishopSq, SQ_A1)) { winnerKSq = mirror(winnerKSq); loserKSq = mirror(loserKSq); } Value result = VALUE_KNOWN_WIN + DistanceBonus[square_distance(winnerKSq, loserKSq)] + KBNKMateTable[loserKSq]; return strongerSide == pos.side_to_move() ? result : -result; } /// KP vs K. This endgame is evaluated with the help of a bitbase. template<> Value Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == VALUE_ZERO); assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO); assert(pos.piece_count(strongerSide, PAWN) == 1); assert(pos.piece_count(weakerSide, PAWN) == 0); Square wksq, bksq, wpsq; Color us; if (strongerSide == WHITE) { wksq = pos.king_square(WHITE); bksq = pos.king_square(BLACK); wpsq = pos.piece_list(WHITE, PAWN)[0]; us = pos.side_to_move(); } else { wksq = ~pos.king_square(BLACK); bksq = ~pos.king_square(WHITE); wpsq = ~pos.piece_list(BLACK, PAWN)[0]; us = ~pos.side_to_move(); } if (file_of(wpsq) >= FILE_E) { wksq = mirror(wksq); bksq = mirror(bksq); wpsq = mirror(wpsq); } if (!Bitbases::probe_kpk(wksq, wpsq, bksq, us)) return VALUE_DRAW; Value result = VALUE_KNOWN_WIN + PawnValueEg + Value(rank_of(wpsq)); return strongerSide == pos.side_to_move() ? result : -result; } /// KR vs KP. This is a somewhat tricky endgame to evaluate precisely without /// a bitbase. The function below returns drawish scores when the pawn is /// far advanced with support of the king, while the attacking king is far /// away. template<> Value Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == RookValueMg); assert(pos.piece_count(strongerSide, PAWN) == 0); assert(pos.non_pawn_material(weakerSide) == 0); assert(pos.piece_count(weakerSide, PAWN) == 1); Square wksq, wrsq, bksq, bpsq; int tempo = (pos.side_to_move() == strongerSide); wksq = pos.king_square(strongerSide); wrsq = pos.piece_list(strongerSide, ROOK)[0]; bksq = pos.king_square(weakerSide); bpsq = pos.piece_list(weakerSide, PAWN)[0]; if (strongerSide == BLACK) { wksq = ~wksq; wrsq = ~wrsq; bksq = ~bksq; bpsq = ~bpsq; } Square queeningSq = file_of(bpsq) | RANK_1; Value result; // If the stronger side's king is in front of the pawn, it's a win if (wksq < bpsq && file_of(wksq) == file_of(bpsq)) result = RookValueEg - Value(square_distance(wksq, bpsq)); // If the weaker side's king is too far from the pawn and the rook, // it's a win else if ( square_distance(bksq, bpsq) - (tempo ^ 1) >= 3 && square_distance(bksq, wrsq) >= 3) result = RookValueEg - Value(square_distance(wksq, bpsq)); // If the pawn is far advanced and supported by the defending king, // the position is drawish else if ( rank_of(bksq) <= RANK_3 && square_distance(bksq, bpsq) == 1 && rank_of(wksq) >= RANK_4 && square_distance(wksq, bpsq) - tempo > 2) result = Value(80 - square_distance(wksq, bpsq) * 8); else result = Value(200) - Value(square_distance(wksq, bpsq + DELTA_S) * 8) + Value(square_distance(bksq, bpsq + DELTA_S) * 8) + Value(square_distance(bpsq, queeningSq) * 8); return strongerSide == pos.side_to_move() ? result : -result; } /// KR vs KB. This is very simple, and always returns drawish scores. The /// score is slightly bigger when the defending king is close to the edge. template<> Value Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == RookValueMg); assert(pos.piece_count(strongerSide, PAWN) == 0); assert(pos.non_pawn_material(weakerSide) == BishopValueMg); assert(pos.piece_count(weakerSide, PAWN) == 0); assert(pos.piece_count(weakerSide, BISHOP) == 1); Value result = Value(MateTable[pos.king_square(weakerSide)]); return strongerSide == pos.side_to_move() ? result : -result; } /// KR vs KN. The attacking side has slightly better winning chances than /// in KR vs KB, particularly if the king and the knight are far apart. template<> Value Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == RookValueMg); assert(pos.piece_count(strongerSide, PAWN) == 0); assert(pos.non_pawn_material(weakerSide) == KnightValueMg); assert(pos.piece_count(weakerSide, PAWN) == 0); assert(pos.piece_count(weakerSide, KNIGHT) == 1); const int penalty[8] = { 0, 10, 14, 20, 30, 42, 58, 80 }; Square bksq = pos.king_square(weakerSide); Square bnsq = pos.piece_list(weakerSide, KNIGHT)[0]; Value result = Value(MateTable[bksq] + penalty[square_distance(bksq, bnsq)]); return strongerSide == pos.side_to_move() ? result : -result; } /// KQ vs KP. In general, a win for the stronger side, however, there are a few /// important exceptions. Pawn on 7th rank, A,C,F or H file, with king next can /// be a draw, so we scale down to distance between kings only. template<> Value Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == QueenValueMg); assert(pos.piece_count(strongerSide, PAWN) == 0); assert(pos.non_pawn_material(weakerSide) == 0); assert(pos.piece_count(weakerSide, PAWN) == 1); Square winnerKSq = pos.king_square(strongerSide); Square loserKSq = pos.king_square(weakerSide); Square pawnSq = pos.piece_list(weakerSide, PAWN)[0]; Value result = QueenValueEg - PawnValueEg + DistanceBonus[square_distance(winnerKSq, loserKSq)]; if ( square_distance(loserKSq, pawnSq) == 1 && relative_rank(weakerSide, pawnSq) == RANK_7) { File f = file_of(pawnSq); if (f == FILE_A || f == FILE_C || f == FILE_F || f == FILE_H) result = Value(DistanceBonus[square_distance(winnerKSq, loserKSq)]); } return strongerSide == pos.side_to_move() ? result : -result; } /// KQ vs KR. This is almost identical to KX vs K: We give the attacking /// king a bonus for having the kings close together, and for forcing the /// defending king towards the edge. If we also take care to avoid null move /// for the defending side in the search, this is usually sufficient to be /// able to win KQ vs KR. template<> Value Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == QueenValueMg); assert(pos.piece_count(strongerSide, PAWN) == 0); assert(pos.non_pawn_material(weakerSide) == RookValueMg); assert(pos.piece_count(weakerSide, PAWN) == 0); Square winnerKSq = pos.king_square(strongerSide); Square loserKSq = pos.king_square(weakerSide); Value result = QueenValueEg - RookValueEg + MateTable[loserKSq] + DistanceBonus[square_distance(winnerKSq, loserKSq)]; return strongerSide == pos.side_to_move() ? result : -result; } template<> Value Endgame::operator()(const Position& pos) const { assert(pos.piece_count(strongerSide, BISHOP) == 2); assert(pos.non_pawn_material(strongerSide) == 2*BishopValueMg); assert(pos.piece_count(weakerSide, KNIGHT) == 1); assert(pos.non_pawn_material(weakerSide) == KnightValueMg); assert(!pos.pieces(PAWN)); Value result = BishopValueEg; Square wksq = pos.king_square(strongerSide); Square bksq = pos.king_square(weakerSide); Square nsq = pos.piece_list(weakerSide, KNIGHT)[0]; // Bonus for attacking king close to defending king result += Value(DistanceBonus[square_distance(wksq, bksq)]); // Bonus for driving the defending king and knight apart result += Value(square_distance(bksq, nsq) * 32); // Bonus for restricting the knight's mobility result += Value((8 - popcount(pos.attacks_from(nsq))) * 8); return strongerSide == pos.side_to_move() ? result : -result; } /// K and two minors vs K and one or two minors or K and two knights against /// king alone are always draw. template<> Value Endgame::operator()(const Position&) const { return VALUE_DRAW; } template<> Value Endgame::operator()(const Position&) const { return VALUE_DRAW; } /// K, bishop and one or more pawns vs K. It checks for draws with rook pawns and /// a bishop of the wrong color. If such a draw is detected, SCALE_FACTOR_DRAW /// is returned. If not, the return value is SCALE_FACTOR_NONE, i.e. no scaling /// will be used. template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == BishopValueMg); assert(pos.piece_count(strongerSide, BISHOP) == 1); assert(pos.piece_count(strongerSide, PAWN) >= 1); // No assertions about the material of weakerSide, because we want draws to // be detected even when the weaker side has some pawns. Bitboard pawns = pos.pieces(strongerSide, PAWN); File pawnFile = file_of(pos.piece_list(strongerSide, PAWN)[0]); // All pawns are on a single rook file ? if ( (pawnFile == FILE_A || pawnFile == FILE_H) && !(pawns & ~file_bb(pawnFile))) { Square bishopSq = pos.piece_list(strongerSide, BISHOP)[0]; Square queeningSq = relative_square(strongerSide, pawnFile | RANK_8); Square kingSq = pos.king_square(weakerSide); if ( opposite_colors(queeningSq, bishopSq) && abs(file_of(kingSq) - pawnFile) <= 1) { // The bishop has the wrong color, and the defending king is on the // file of the pawn(s) or the adjacent file. Find the rank of the // frontmost pawn. Rank rank; if (strongerSide == WHITE) { for (rank = RANK_7; !(rank_bb(rank) & pawns); rank--) {} assert(rank >= RANK_2 && rank <= RANK_7); } else { for (rank = RANK_2; !(rank_bb(rank) & pawns); rank++) {} rank = Rank(rank ^ 7); // HACK to get the relative rank assert(rank >= RANK_2 && rank <= RANK_7); } // If the defending king has distance 1 to the promotion square or // is placed somewhere in front of the pawn, it's a draw. if ( square_distance(kingSq, queeningSq) <= 1 || relative_rank(strongerSide, kingSq) >= rank) return SCALE_FACTOR_DRAW; } } // All pawns on same B or G file? Then potential draw if ( (pawnFile == FILE_B || pawnFile == FILE_G) && !(pos.pieces(PAWN) & ~file_bb(pawnFile)) && pos.non_pawn_material(weakerSide) == 0 && pos.piece_count(weakerSide, PAWN) >= 1) { // Get weaker pawn closest to opponent's queening square Bitboard wkPawns = pos.pieces(weakerSide, PAWN); Square weakerPawnSq = strongerSide == WHITE ? msb(wkPawns) : lsb(wkPawns); Square strongerKingSq = pos.king_square(strongerSide); Square weakerKingSq = pos.king_square(weakerSide); Square bishopSq = pos.piece_list(strongerSide, BISHOP)[0]; // Draw if weaker pawn is on rank 7, bishop can't attack the pawn, and // weaker king can stop opposing opponent's king from penetrating. if ( relative_rank(strongerSide, weakerPawnSq) == RANK_7 && opposite_colors(bishopSq, weakerPawnSq) && square_distance(weakerPawnSq, weakerKingSq) <= square_distance(weakerPawnSq, strongerKingSq)) return SCALE_FACTOR_DRAW; } return SCALE_FACTOR_NONE; } /// K and queen vs K, rook and one or more pawns. It tests for fortress draws with /// a rook on the third rank defended by a pawn. template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == QueenValueMg); assert(pos.piece_count(strongerSide, QUEEN) == 1); assert(pos.piece_count(strongerSide, PAWN) == 0); assert(pos.piece_count(weakerSide, ROOK) == 1); assert(pos.piece_count(weakerSide, PAWN) >= 1); Square kingSq = pos.king_square(weakerSide); if ( relative_rank(weakerSide, kingSq) <= RANK_2 && relative_rank(weakerSide, pos.king_square(strongerSide)) >= RANK_4 && (pos.pieces(weakerSide, ROOK) & rank_bb(relative_rank(weakerSide, RANK_3))) && (pos.pieces(weakerSide, PAWN) & rank_bb(relative_rank(weakerSide, RANK_2))) && (pos.attacks_from(kingSq) & pos.pieces(weakerSide, PAWN))) { Square rsq = pos.piece_list(weakerSide, ROOK)[0]; if (pos.attacks_from(rsq, strongerSide) & pos.pieces(weakerSide, PAWN)) return SCALE_FACTOR_DRAW; } return SCALE_FACTOR_NONE; } /// K, rook and one pawn vs K and a rook. This function knows a handful of the /// most important classes of drawn positions, but is far from perfect. It would /// probably be a good idea to add more knowledge in the future. /// /// It would also be nice to rewrite the actual code for this function, /// which is mostly copied from Glaurung 1.x, and not very pretty. template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == RookValueMg); assert(pos.piece_count(strongerSide, PAWN) == 1); assert(pos.non_pawn_material(weakerSide) == RookValueMg); assert(pos.piece_count(weakerSide, PAWN) == 0); Square wksq = pos.king_square(strongerSide); Square wrsq = pos.piece_list(strongerSide, ROOK)[0]; Square wpsq = pos.piece_list(strongerSide, PAWN)[0]; Square bksq = pos.king_square(weakerSide); Square brsq = pos.piece_list(weakerSide, ROOK)[0]; // Orient the board in such a way that the stronger side is white, and the // pawn is on the left half of the board. if (strongerSide == BLACK) { wksq = ~wksq; wrsq = ~wrsq; wpsq = ~wpsq; bksq = ~bksq; brsq = ~brsq; } if (file_of(wpsq) > FILE_D) { wksq = mirror(wksq); wrsq = mirror(wrsq); wpsq = mirror(wpsq); bksq = mirror(bksq); brsq = mirror(brsq); } File f = file_of(wpsq); Rank r = rank_of(wpsq); Square queeningSq = f | RANK_8; int tempo = (pos.side_to_move() == strongerSide); // If the pawn is not too far advanced and the defending king defends the // queening square, use the third-rank defence. if ( r <= RANK_5 && square_distance(bksq, queeningSq) <= 1 && wksq <= SQ_H5 && (rank_of(brsq) == RANK_6 || (r <= RANK_3 && rank_of(wrsq) != RANK_6))) return SCALE_FACTOR_DRAW; // The defending side saves a draw by checking from behind in case the pawn // has advanced to the 6th rank with the king behind. if ( r == RANK_6 && square_distance(bksq, queeningSq) <= 1 && rank_of(wksq) + tempo <= RANK_6 && (rank_of(brsq) == RANK_1 || (!tempo && abs(file_of(brsq) - f) >= 3))) return SCALE_FACTOR_DRAW; if ( r >= RANK_6 && bksq == queeningSq && rank_of(brsq) == RANK_1 && (!tempo || square_distance(wksq, wpsq) >= 2)) return SCALE_FACTOR_DRAW; // White pawn on a7 and rook on a8 is a draw if black's king is on g7 or h7 // and the black rook is behind the pawn. if ( wpsq == SQ_A7 && wrsq == SQ_A8 && (bksq == SQ_H7 || bksq == SQ_G7) && file_of(brsq) == FILE_A && (rank_of(brsq) <= RANK_3 || file_of(wksq) >= FILE_D || rank_of(wksq) <= RANK_5)) return SCALE_FACTOR_DRAW; // If the defending king blocks the pawn and the attacking king is too far // away, it's a draw. if ( r <= RANK_5 && bksq == wpsq + DELTA_N && square_distance(wksq, wpsq) - tempo >= 2 && square_distance(wksq, brsq) - tempo >= 2) return SCALE_FACTOR_DRAW; // Pawn on the 7th rank supported by the rook from behind usually wins if the // attacking king is closer to the queening square than the defending king, // and the defending king cannot gain tempi by threatening the attacking rook. if ( r == RANK_7 && f != FILE_A && file_of(wrsq) == f && wrsq != queeningSq && (square_distance(wksq, queeningSq) < square_distance(bksq, queeningSq) - 2 + tempo) && (square_distance(wksq, queeningSq) < square_distance(bksq, wrsq) + tempo)) return ScaleFactor(SCALE_FACTOR_MAX - 2 * square_distance(wksq, queeningSq)); // Similar to the above, but with the pawn further back if ( f != FILE_A && file_of(wrsq) == f && wrsq < wpsq && (square_distance(wksq, queeningSq) < square_distance(bksq, queeningSq) - 2 + tempo) && (square_distance(wksq, wpsq + DELTA_N) < square_distance(bksq, wpsq + DELTA_N) - 2 + tempo) && ( square_distance(bksq, wrsq) + tempo >= 3 || ( square_distance(wksq, queeningSq) < square_distance(bksq, wrsq) + tempo && (square_distance(wksq, wpsq + DELTA_N) < square_distance(bksq, wrsq) + tempo)))) return ScaleFactor( SCALE_FACTOR_MAX - 8 * square_distance(wpsq, queeningSq) - 2 * square_distance(wksq, queeningSq)); // If the pawn is not far advanced, and the defending king is somewhere in // the pawn's path, it's probably a draw. if (r <= RANK_4 && bksq > wpsq) { if (file_of(bksq) == file_of(wpsq)) return ScaleFactor(10); if ( abs(file_of(bksq) - file_of(wpsq)) == 1 && square_distance(wksq, bksq) > 2) return ScaleFactor(24 - 2 * square_distance(wksq, bksq)); } return SCALE_FACTOR_NONE; } /// K, rook and two pawns vs K, rook and one pawn. There is only a single /// pattern: If the stronger side has no passed pawns and the defending king /// is actively placed, the position is drawish. template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == RookValueMg); assert(pos.piece_count(strongerSide, PAWN) == 2); assert(pos.non_pawn_material(weakerSide) == RookValueMg); assert(pos.piece_count(weakerSide, PAWN) == 1); Square wpsq1 = pos.piece_list(strongerSide, PAWN)[0]; Square wpsq2 = pos.piece_list(strongerSide, PAWN)[1]; Square bksq = pos.king_square(weakerSide); // Does the stronger side have a passed pawn? if ( pos.pawn_is_passed(strongerSide, wpsq1) || pos.pawn_is_passed(strongerSide, wpsq2)) return SCALE_FACTOR_NONE; Rank r = std::max(relative_rank(strongerSide, wpsq1), relative_rank(strongerSide, wpsq2)); if ( file_distance(bksq, wpsq1) <= 1 && file_distance(bksq, wpsq2) <= 1 && relative_rank(strongerSide, bksq) > r) { switch (r) { case RANK_2: return ScaleFactor(10); case RANK_3: return ScaleFactor(10); case RANK_4: return ScaleFactor(15); case RANK_5: return ScaleFactor(20); case RANK_6: return ScaleFactor(40); default: assert(false); } } return SCALE_FACTOR_NONE; } /// K and two or more pawns vs K. There is just a single rule here: If all pawns /// are on the same rook file and are blocked by the defending king, it's a draw. template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == VALUE_ZERO); assert(pos.piece_count(strongerSide, PAWN) >= 2); assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO); assert(pos.piece_count(weakerSide, PAWN) == 0); Square ksq = pos.king_square(weakerSide); Bitboard pawns = pos.pieces(strongerSide, PAWN); // Are all pawns on the 'a' file? if (!(pawns & ~FileABB)) { // Does the defending king block the pawns? if ( square_distance(ksq, relative_square(strongerSide, SQ_A8)) <= 1 || ( file_of(ksq) == FILE_A && !(in_front_bb(strongerSide, ksq) & pawns))) return SCALE_FACTOR_DRAW; } // Are all pawns on the 'h' file? else if (!(pawns & ~FileHBB)) { // Does the defending king block the pawns? if ( square_distance(ksq, relative_square(strongerSide, SQ_H8)) <= 1 || ( file_of(ksq) == FILE_H && !(in_front_bb(strongerSide, ksq) & pawns))) return SCALE_FACTOR_DRAW; } return SCALE_FACTOR_NONE; } /// K, bishop and a pawn vs K and a bishop. There are two rules: If the defending /// king is somewhere along the path of the pawn, and the square of the king is /// not of the same color as the stronger side's bishop, it's a draw. If the two /// bishops have opposite color, it's almost always a draw. template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == BishopValueMg); assert(pos.piece_count(strongerSide, BISHOP) == 1); assert(pos.piece_count(strongerSide, PAWN) == 1); assert(pos.non_pawn_material(weakerSide) == BishopValueMg); assert(pos.piece_count(weakerSide, BISHOP) == 1); assert(pos.piece_count(weakerSide, PAWN) == 0); Square pawnSq = pos.piece_list(strongerSide, PAWN)[0]; Square strongerBishopSq = pos.piece_list(strongerSide, BISHOP)[0]; Square weakerBishopSq = pos.piece_list(weakerSide, BISHOP)[0]; Square weakerKingSq = pos.king_square(weakerSide); // Case 1: Defending king blocks the pawn, and cannot be driven away if ( file_of(weakerKingSq) == file_of(pawnSq) && relative_rank(strongerSide, pawnSq) < relative_rank(strongerSide, weakerKingSq) && ( opposite_colors(weakerKingSq, strongerBishopSq) || relative_rank(strongerSide, weakerKingSq) <= RANK_6)) return SCALE_FACTOR_DRAW; // Case 2: Opposite colored bishops if (opposite_colors(strongerBishopSq, weakerBishopSq)) { // We assume that the position is drawn in the following three situations: // // a. The pawn is on rank 5 or further back. // b. The defending king is somewhere in the pawn's path. // c. The defending bishop attacks some square along the pawn's path, // and is at least three squares away from the pawn. // // These rules are probably not perfect, but in practice they work // reasonably well. if (relative_rank(strongerSide, pawnSq) <= RANK_5) return SCALE_FACTOR_DRAW; else { Bitboard path = forward_bb(strongerSide, pawnSq); if (path & pos.pieces(weakerSide, KING)) return SCALE_FACTOR_DRAW; if ( (pos.attacks_from(weakerBishopSq) & path) && square_distance(weakerBishopSq, pawnSq) >= 3) return SCALE_FACTOR_DRAW; } } return SCALE_FACTOR_NONE; } /// K, bishop and two pawns vs K and bishop. It detects a few basic draws with /// opposite-colored bishops. template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == BishopValueMg); assert(pos.piece_count(strongerSide, BISHOP) == 1); assert(pos.piece_count(strongerSide, PAWN) == 2); assert(pos.non_pawn_material(weakerSide) == BishopValueMg); assert(pos.piece_count(weakerSide, BISHOP) == 1); assert(pos.piece_count(weakerSide, PAWN) == 0); Square wbsq = pos.piece_list(strongerSide, BISHOP)[0]; Square bbsq = pos.piece_list(weakerSide, BISHOP)[0]; if (!opposite_colors(wbsq, bbsq)) return SCALE_FACTOR_NONE; Square ksq = pos.king_square(weakerSide); Square psq1 = pos.piece_list(strongerSide, PAWN)[0]; Square psq2 = pos.piece_list(strongerSide, PAWN)[1]; Rank r1 = rank_of(psq1); Rank r2 = rank_of(psq2); Square blockSq1, blockSq2; if (relative_rank(strongerSide, psq1) > relative_rank(strongerSide, psq2)) { blockSq1 = psq1 + pawn_push(strongerSide); blockSq2 = file_of(psq2) | rank_of(psq1); } else { blockSq1 = psq2 + pawn_push(strongerSide); blockSq2 = file_of(psq1) | rank_of(psq2); } switch (file_distance(psq1, psq2)) { case 0: // Both pawns are on the same file. Easy draw if defender firmly controls // some square in the frontmost pawn's path. if ( file_of(ksq) == file_of(blockSq1) && relative_rank(strongerSide, ksq) >= relative_rank(strongerSide, blockSq1) && opposite_colors(ksq, wbsq)) return SCALE_FACTOR_DRAW; else return SCALE_FACTOR_NONE; case 1: // Pawns on adjacent files. Draw if defender firmly controls the square // in front of the frontmost pawn's path, and the square diagonally behind // this square on the file of the other pawn. if ( ksq == blockSq1 && opposite_colors(ksq, wbsq) && ( bbsq == blockSq2 || (pos.attacks_from(blockSq2) & pos.pieces(weakerSide, BISHOP)) || abs(r1 - r2) >= 2)) return SCALE_FACTOR_DRAW; else if ( ksq == blockSq2 && opposite_colors(ksq, wbsq) && ( bbsq == blockSq1 || (pos.attacks_from(blockSq1) & pos.pieces(weakerSide, BISHOP)))) return SCALE_FACTOR_DRAW; else return SCALE_FACTOR_NONE; default: // The pawns are not on the same file or adjacent files. No scaling. return SCALE_FACTOR_NONE; } } /// K, bisop and a pawn vs K and knight. There is a single rule: If the defending /// king is somewhere along the path of the pawn, and the square of the king is /// not of the same color as the stronger side's bishop, it's a draw. template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == BishopValueMg); assert(pos.piece_count(strongerSide, BISHOP) == 1); assert(pos.piece_count(strongerSide, PAWN) == 1); assert(pos.non_pawn_material(weakerSide) == KnightValueMg); assert(pos.piece_count(weakerSide, KNIGHT) == 1); assert(pos.piece_count(weakerSide, PAWN) == 0); Square pawnSq = pos.piece_list(strongerSide, PAWN)[0]; Square strongerBishopSq = pos.piece_list(strongerSide, BISHOP)[0]; Square weakerKingSq = pos.king_square(weakerSide); if ( file_of(weakerKingSq) == file_of(pawnSq) && relative_rank(strongerSide, pawnSq) < relative_rank(strongerSide, weakerKingSq) && ( opposite_colors(weakerKingSq, strongerBishopSq) || relative_rank(strongerSide, weakerKingSq) <= RANK_6)) return SCALE_FACTOR_DRAW; return SCALE_FACTOR_NONE; } /// K, knight and a pawn vs K. There is a single rule: If the pawn is a rook pawn /// on the 7th rank and the defending king prevents the pawn from advancing, the /// position is drawn. template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == KnightValueMg); assert(pos.piece_count(strongerSide, KNIGHT) == 1); assert(pos.piece_count(strongerSide, PAWN) == 1); assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO); assert(pos.piece_count(weakerSide, PAWN) == 0); Square pawnSq = pos.piece_list(strongerSide, PAWN)[0]; Square weakerKingSq = pos.king_square(weakerSide); if ( pawnSq == relative_square(strongerSide, SQ_A7) && square_distance(weakerKingSq, relative_square(strongerSide, SQ_A8)) <= 1) return SCALE_FACTOR_DRAW; if ( pawnSq == relative_square(strongerSide, SQ_H7) && square_distance(weakerKingSq, relative_square(strongerSide, SQ_H8)) <= 1) return SCALE_FACTOR_DRAW; return SCALE_FACTOR_NONE; } /// K, knight and a pawn vs K and bishop. If knight can block bishop from taking /// pawn, it's a win. Otherwise, drawn. template<> ScaleFactor Endgame::operator()(const Position& pos) const { Square pawnSq = pos.piece_list(strongerSide, PAWN)[0]; Square bishopSq = pos.piece_list(weakerSide, BISHOP)[0]; Square weakerKingSq = pos.king_square(weakerSide); // King needs to get close to promoting pawn to prevent knight from blocking. // Rules for this are very tricky, so just approximate. if (forward_bb(strongerSide, pawnSq) & pos.attacks_from(bishopSq)) return ScaleFactor(square_distance(weakerKingSq, pawnSq)); return SCALE_FACTOR_NONE; } /// K and a pawn vs K and a pawn. This is done by removing the weakest side's /// pawn and probing the KP vs K bitbase: If the weakest side has a draw without /// the pawn, she probably has at least a draw with the pawn as well. The exception /// is when the stronger side's pawn is far advanced and not on a rook file; in /// this case it is often possible to win (e.g. 8/4k3/3p4/3P4/6K1/8/8/8 w - - 0 1). template<> ScaleFactor Endgame::operator()(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == VALUE_ZERO); assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO); assert(pos.piece_count(WHITE, PAWN) == 1); assert(pos.piece_count(BLACK, PAWN) == 1); Square wksq = pos.king_square(strongerSide); Square bksq = pos.king_square(weakerSide); Square wpsq = pos.piece_list(strongerSide, PAWN)[0]; Color us = pos.side_to_move(); if (strongerSide == BLACK) { wksq = ~wksq; bksq = ~bksq; wpsq = ~wpsq; us = ~us; } if (file_of(wpsq) >= FILE_E) { wksq = mirror(wksq); bksq = mirror(bksq); wpsq = mirror(wpsq); } // If the pawn has advanced to the fifth rank or further, and is not a // rook pawn, it's too dangerous to assume that it's at least a draw. if ( rank_of(wpsq) >= RANK_5 && file_of(wpsq) != FILE_A) return SCALE_FACTOR_NONE; // Probe the KPK bitbase with the weakest side's pawn removed. If it's a draw, // it's probably at least a draw even with the pawn. return Bitbases::probe_kpk(wksq, wpsq, bksq, us) ? SCALE_FACTOR_NONE : SCALE_FACTOR_DRAW; } stockfish-3.0.0+git20130508/src/position.h0000644000175000017500000002775012142540127017310 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #if !defined(POSITION_H_INCLUDED) #define POSITION_H_INCLUDED #include #include #include "bitboard.h" #include "types.h" /// The checkInfo struct is initialized at c'tor time and keeps info used /// to detect if a move gives check. class Position; struct Thread; struct CheckInfo { explicit CheckInfo(const Position&); Bitboard dcCandidates; Bitboard pinned; Bitboard checkSq[PIECE_TYPE_NB]; Square ksq; }; /// The StateInfo struct stores information we need to restore a Position /// object to its previous state when we retract a move. Whenever a move /// is made on the board (by calling Position::do_move), a StateInfo object /// must be passed as a parameter. struct StateInfo { Key pawnKey, materialKey; Value npMaterial[COLOR_NB]; int castleRights, rule50, pliesFromNull; Score psqScore; Square epSquare; Key key; Bitboard checkersBB; PieceType capturedType; StateInfo* previous; }; /// When making a move the current StateInfo up to 'key' excluded is copied to /// the new one. Here we calculate the quad words (64bits) needed to be copied. const size_t StateCopySize64 = offsetof(StateInfo, key) / sizeof(uint64_t) + 1; /// The position data structure. A position consists of the following data: /// /// * For each piece type, a bitboard representing the squares occupied /// by pieces of that type. /// * For each color, a bitboard representing the squares occupied by /// pieces of that color. /// * A bitboard of all occupied squares. /// * A bitboard of all checking pieces. /// * A 64-entry array of pieces, indexed by the squares of the board. /// * The current side to move. /// * Information about the castling rights for both sides. /// * The initial files of the kings and both pairs of rooks. This is /// used to implement the Chess960 castling rules. /// * The en passant square (which is SQ_NONE if no en passant capture is /// possible). /// * The squares of the kings for both sides. /// * Hash keys for the position itself, the current pawn structure, and /// the current material situation. /// * Hash keys for all previous positions in the game for detecting /// repetition draws. /// * A counter for detecting 50 move rule draws. class Position { public: Position() {} Position(const Position& p, Thread* t) { *this = p; thisThread = t; } Position(const std::string& f, bool c960, Thread* t) { set(f, c960, t); } Position& operator=(const Position&); // Text input/output void set(const std::string& fen, bool isChess960, Thread* th); const std::string fen() const; const std::string pretty(Move m = MOVE_NONE) const; // Position representation Bitboard pieces() const; Bitboard pieces(PieceType pt) const; Bitboard pieces(PieceType pt1, PieceType pt2) const; Bitboard pieces(Color c) const; Bitboard pieces(Color c, PieceType pt) const; Bitboard pieces(Color c, PieceType pt1, PieceType pt2) const; Piece piece_on(Square s) const; Square king_square(Color c) const; Square ep_square() const; bool is_empty(Square s) const; const Square* piece_list(Color c, PieceType pt) const; int piece_count(Color c, PieceType pt) const; // Castling int can_castle(CastleRight f) const; int can_castle(Color c) const; bool castle_impeded(Color c, CastlingSide s) const; Square castle_rook_square(Color c, CastlingSide s) const; // Checking Bitboard checkers() const; Bitboard discovered_check_candidates() const; Bitboard pinned_pieces() const; // Attacks to/from a given square Bitboard attackers_to(Square s) const; Bitboard attackers_to(Square s, Bitboard occ) const; Bitboard attacks_from(Piece p, Square s) const; static Bitboard attacks_from(Piece p, Square s, Bitboard occ); template Bitboard attacks_from(Square s) const; template Bitboard attacks_from(Square s, Color c) const; // Properties of moves bool move_gives_check(Move m, const CheckInfo& ci) const; bool pl_move_is_legal(Move m, Bitboard pinned) const; bool is_pseudo_legal(const Move m) const; bool is_capture(Move m) const; bool is_capture_or_promotion(Move m) const; bool is_passed_pawn_push(Move m) const; Piece piece_moved(Move m) const; PieceType captured_piece_type() const; // Piece specific bool pawn_is_passed(Color c, Square s) const; bool pawn_on_7th(Color c) const; bool opposite_bishops() const; bool bishop_pair(Color c) const; // Doing and undoing moves void do_move(Move m, StateInfo& st); void do_move(Move m, StateInfo& st, const CheckInfo& ci, bool moveIsCheck); void undo_move(Move m); void do_null_move(StateInfo& st); void undo_null_move(); // Static exchange evaluation int see(Move m, int asymmThreshold = 0) const; int see_sign(Move m) const; // Accessing hash keys Key key() const; Key exclusion_key() const; Key pawn_key() const; Key material_key() const; // Incremental piece-square evaluation Score psq_score() const; Score psq_delta(Piece p, Square from, Square to) const; Value non_pawn_material(Color c) const; // Other properties of the position Color side_to_move() const; int game_ply() const; bool is_chess960() const; Thread* this_thread() const; int64_t nodes_searched() const; void set_nodes_searched(int64_t n); bool is_draw() const; // Position consistency check, for debugging bool pos_is_ok(int* failedStep = NULL) const; void flip(); private: // Initialization helpers (used while setting up a position) void clear(); void put_piece(Piece p, Square s); void set_castle_right(Color c, Square rfrom); // Helper functions void do_castle(Square kfrom, Square kto, Square rfrom, Square rto); template Bitboard hidden_checkers() const; // Computing hash keys from scratch (for initialization and debugging) Key compute_key() const; Key compute_pawn_key() const; Key compute_material_key() const; // Computing incremental evaluation scores and material counts Score compute_psq_score() const; Value compute_non_pawn_material(Color c) const; // Board and pieces Piece board[SQUARE_NB]; Bitboard byTypeBB[PIECE_TYPE_NB]; Bitboard byColorBB[COLOR_NB]; int pieceCount[COLOR_NB][PIECE_TYPE_NB]; Square pieceList[COLOR_NB][PIECE_TYPE_NB][16]; int index[SQUARE_NB]; // Other info int castleRightsMask[SQUARE_NB]; Square castleRookSquare[COLOR_NB][CASTLING_SIDE_NB]; Bitboard castlePath[COLOR_NB][CASTLING_SIDE_NB]; StateInfo startState; int64_t nodes; int gamePly; Color sideToMove; Thread* thisThread; StateInfo* st; int chess960; }; inline int64_t Position::nodes_searched() const { return nodes; } inline void Position::set_nodes_searched(int64_t n) { nodes = n; } inline Piece Position::piece_on(Square s) const { return board[s]; } inline Piece Position::piece_moved(Move m) const { return board[from_sq(m)]; } inline bool Position::is_empty(Square s) const { return board[s] == NO_PIECE; } inline Color Position::side_to_move() const { return sideToMove; } inline Bitboard Position::pieces() const { return byTypeBB[ALL_PIECES]; } inline Bitboard Position::pieces(PieceType pt) const { return byTypeBB[pt]; } inline Bitboard Position::pieces(PieceType pt1, PieceType pt2) const { return byTypeBB[pt1] | byTypeBB[pt2]; } inline Bitboard Position::pieces(Color c) const { return byColorBB[c]; } inline Bitboard Position::pieces(Color c, PieceType pt) const { return byColorBB[c] & byTypeBB[pt]; } inline Bitboard Position::pieces(Color c, PieceType pt1, PieceType pt2) const { return byColorBB[c] & (byTypeBB[pt1] | byTypeBB[pt2]); } inline int Position::piece_count(Color c, PieceType pt) const { return pieceCount[c][pt]; } inline const Square* Position::piece_list(Color c, PieceType pt) const { return pieceList[c][pt]; } inline Square Position::ep_square() const { return st->epSquare; } inline Square Position::king_square(Color c) const { return pieceList[c][KING][0]; } inline int Position::can_castle(CastleRight f) const { return st->castleRights & f; } inline int Position::can_castle(Color c) const { return st->castleRights & ((WHITE_OO | WHITE_OOO) << (2 * c)); } inline bool Position::castle_impeded(Color c, CastlingSide s) const { return byTypeBB[ALL_PIECES] & castlePath[c][s]; } inline Square Position::castle_rook_square(Color c, CastlingSide s) const { return castleRookSquare[c][s]; } template inline Bitboard Position::attacks_from(Square s) const { return Pt == BISHOP || Pt == ROOK ? attacks_bb(s, pieces()) : Pt == QUEEN ? attacks_from(s) | attacks_from(s) : StepAttacksBB[Pt][s]; } template<> inline Bitboard Position::attacks_from(Square s, Color c) const { return StepAttacksBB[make_piece(c, PAWN)][s]; } inline Bitboard Position::attacks_from(Piece p, Square s) const { return attacks_from(p, s, byTypeBB[ALL_PIECES]); } inline Bitboard Position::attackers_to(Square s) const { return attackers_to(s, byTypeBB[ALL_PIECES]); } inline Bitboard Position::checkers() const { return st->checkersBB; } inline Bitboard Position::discovered_check_candidates() const { return hidden_checkers(); } inline Bitboard Position::pinned_pieces() const { return hidden_checkers(); } inline bool Position::pawn_is_passed(Color c, Square s) const { return !(pieces(~c, PAWN) & passed_pawn_mask(c, s)); } inline Key Position::key() const { return st->key; } inline Key Position::exclusion_key() const { return st->key ^ Zobrist::exclusion; } inline Key Position::pawn_key() const { return st->pawnKey; } inline Key Position::material_key() const { return st->materialKey; } inline Score Position::psq_delta(Piece p, Square from, Square to) const { return pieceSquareTable[p][to] - pieceSquareTable[p][from]; } inline Score Position::psq_score() const { return st->psqScore; } inline Value Position::non_pawn_material(Color c) const { return st->npMaterial[c]; } inline bool Position::is_passed_pawn_push(Move m) const { return type_of(piece_moved(m)) == PAWN && pawn_is_passed(sideToMove, to_sq(m)); } inline int Position::game_ply() const { return gamePly; } inline bool Position::opposite_bishops() const { return pieceCount[WHITE][BISHOP] == 1 && pieceCount[BLACK][BISHOP] == 1 && opposite_colors(pieceList[WHITE][BISHOP][0], pieceList[BLACK][BISHOP][0]); } inline bool Position::bishop_pair(Color c) const { return pieceCount[c][BISHOP] >= 2 && opposite_colors(pieceList[c][BISHOP][0], pieceList[c][BISHOP][1]); } inline bool Position::pawn_on_7th(Color c) const { return pieces(c, PAWN) & rank_bb(relative_rank(c, RANK_7)); } inline bool Position::is_chess960() const { return chess960; } inline bool Position::is_capture_or_promotion(Move m) const { assert(is_ok(m)); return type_of(m) ? type_of(m) != CASTLE : !is_empty(to_sq(m)); } inline bool Position::is_capture(Move m) const { // Note that castle is coded as "king captures the rook" assert(is_ok(m)); return (!is_empty(to_sq(m)) && type_of(m) != CASTLE) || type_of(m) == ENPASSANT; } inline PieceType Position::captured_piece_type() const { return st->capturedType; } inline Thread* Position::this_thread() const { return thisThread; } #endif // !defined(POSITION_H_INCLUDED) stockfish-3.0.0+git20130508/src/bitbase.cpp0000644000175000017500000001324412142540127017401 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include "bitboard.h" #include "types.h" namespace { // The possible pawns squares are 24, the first 4 files and ranks from 2 to 7 const unsigned IndexMax = 2*24*64*64; // stm * psq * wksq * bksq = 196608 // Each uint32_t stores results of 32 positions, one per bit uint32_t KPKBitbase[IndexMax / 32]; // A KPK bitbase index is an integer in [0, IndexMax] range // // Information is mapped in a way that minimizes number of iterations: // // bit 0- 5: white king square (from SQ_A1 to SQ_H8) // bit 6-11: black king square (from SQ_A1 to SQ_H8) // bit 12: side to move (WHITE or BLACK) // bit 13-14: white pawn file (from FILE_A to FILE_D) // bit 15-17: white pawn 6 - rank (from 6 - RANK_7 to 6 - RANK_2) unsigned index(Color us, Square bksq, Square wksq, Square psq) { return wksq + (bksq << 6) + (us << 12) + (file_of(psq) << 13) + ((6 - rank_of(psq)) << 15); } enum Result { INVALID = 0, UNKNOWN = 1, DRAW = 2, WIN = 4 }; inline Result& operator|=(Result& r, Result v) { return r = Result(r | v); } struct KPKPosition { operator Result() const { return res; } Result classify_leaf(unsigned idx); Result classify(const std::vector& db) { return us == WHITE ? classify(db) : classify(db); } private: template Result classify(const std::vector& db); Color us; Square bksq, wksq, psq; Result res; }; } // namespace bool Bitbases::probe_kpk(Square wksq, Square wpsq, Square bksq, Color us) { assert(file_of(wpsq) <= FILE_D); unsigned idx = index(us, bksq, wksq, wpsq); return KPKBitbase[idx / 32] & (1 << (idx & 0x1F)); } void Bitbases::init_kpk() { unsigned idx, repeat = 1; std::vector db(IndexMax); // Initialize db with known win / draw positions for (idx = 0; idx < IndexMax; idx++) db[idx].classify_leaf(idx); // Iterate through the positions until no more of the unknown positions can be // changed to either wins or draws (15 cycles needed). while (repeat) for (repeat = idx = 0; idx < IndexMax; idx++) if (db[idx] == UNKNOWN && db[idx].classify(db) != UNKNOWN) repeat = 1; // Map 32 results into one KPKBitbase[] entry for (idx = 0; idx < IndexMax; idx++) if (db[idx] == WIN) KPKBitbase[idx / 32] |= 1 << (idx & 0x1F); } namespace { Result KPKPosition::classify_leaf(unsigned idx) { wksq = Square((idx >> 0) & 0x3F); bksq = Square((idx >> 6) & 0x3F); us = Color((idx >> 12) & 0x01); psq = File((idx >> 13) & 3) | Rank(6 - (idx >> 15)); // Check if two pieces are on the same square or if a king can be captured if ( wksq == psq || wksq == bksq || bksq == psq || (StepAttacksBB[KING][wksq] & bksq) || (us == WHITE && (StepAttacksBB[PAWN][psq] & bksq))) return res = INVALID; if (us == WHITE) { // Immediate win if pawn can be promoted without getting captured if ( rank_of(psq) == RANK_7 && wksq != psq + DELTA_N && ( square_distance(bksq, psq + DELTA_N) > 1 ||(StepAttacksBB[KING][wksq] & (psq + DELTA_N)))) return res = WIN; } // Immediate draw if is stalemate or king captures undefended pawn else if ( !(StepAttacksBB[KING][bksq] & ~(StepAttacksBB[KING][wksq] | StepAttacksBB[PAWN][psq])) || (StepAttacksBB[KING][bksq] & psq & ~StepAttacksBB[KING][wksq])) return res = DRAW; return res = UNKNOWN; } template Result KPKPosition::classify(const std::vector& db) { // White to Move: If one move leads to a position classified as WIN, the result // of the current position is WIN. If all moves lead to positions classified // as DRAW, the current position is classified DRAW otherwise the current // position is classified as UNKNOWN. // // Black to Move: If one move leads to a position classified as DRAW, the result // of the current position is DRAW. If all moves lead to positions classified // as WIN, the position is classified WIN otherwise the current position is // classified UNKNOWN. Result r = INVALID; Bitboard b = StepAttacksBB[KING][Us == WHITE ? wksq : bksq]; while (b) r |= Us == WHITE ? db[index(~Us, bksq, pop_lsb(&b), psq)] : db[index(~Us, pop_lsb(&b), wksq, psq)]; if (Us == WHITE && rank_of(psq) < RANK_7) { Square s = psq + DELTA_N; r |= db[index(BLACK, bksq, wksq, s)]; // Single push if (rank_of(s) == RANK_3 && s != wksq && s != bksq) r |= db[index(BLACK, bksq, wksq, s + DELTA_N)]; // Double push } if (Us == WHITE) return res = r & WIN ? WIN : r & UNKNOWN ? UNKNOWN : DRAW; else return res = r & DRAW ? DRAW : r & UNKNOWN ? UNKNOWN : WIN; } } // namespace stockfish-3.0.0+git20130508/src/main.cpp0000644000175000017500000000256712142540127016722 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include "bitboard.h" #include "evaluate.h" #include "position.h" #include "search.h" #include "thread.h" #include "tt.h" #include "ucioption.h" int main(int argc, char* argv[]) { std::cout << engine_info() << std::endl; UCI::init(Options); Bitboards::init(); Zobrist::init(); Bitbases::init_kpk(); Search::init(); Eval::init(); Threads.init(); TT.set_size(Options["Hash"]); std::string args; for (int i = 1; i < argc; i++) args += std::string(argv[i]) + " "; UCI::loop(args); Threads.exit(); } stockfish-3.0.0+git20130508/src/evaluate.cpp0000644000175000017500000014002512142540127017574 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include "bitcount.h" #include "evaluate.h" #include "material.h" #include "pawns.h" #include "thread.h" #include "ucioption.h" namespace { // Struct EvalInfo contains various information computed and collected // by the evaluation functions. struct EvalInfo { // Pointers to material and pawn hash table entries Material::Entry* mi; Pawns::Entry* pi; // attackedBy[color][piece type] is a bitboard representing all squares // attacked by a given color and piece type, attackedBy[color][ALL_PIECES] // contains all squares attacked by the given color. Bitboard attackedBy[COLOR_NB][PIECE_TYPE_NB]; // kingRing[color] is the zone around the king which is considered // by the king safety evaluation. This consists of the squares directly // adjacent to the king, and the three (or two, for a king on an edge file) // squares two ranks in front of the king. For instance, if black's king // is on g8, kingRing[BLACK] is a bitboard containing the squares f8, h8, // f7, g7, h7, f6, g6 and h6. Bitboard kingRing[COLOR_NB]; // kingAttackersCount[color] is the number of pieces of the given color // which attack a square in the kingRing of the enemy king. int kingAttackersCount[COLOR_NB]; // kingAttackersWeight[color] is the sum of the "weight" of the pieces of the // given color which attack a square in the kingRing of the enemy king. The // weights of the individual piece types are given by the variables // QueenAttackWeight, RookAttackWeight, BishopAttackWeight and // KnightAttackWeight in evaluate.cpp int kingAttackersWeight[COLOR_NB]; // kingAdjacentZoneAttacksCount[color] is the number of attacks to squares // directly adjacent to the king of the given color. Pieces which attack // more than one square are counted multiple times. For instance, if black's // king is on g8 and there's a white knight on g5, this knight adds // 2 to kingAdjacentZoneAttacksCount[BLACK]. int kingAdjacentZoneAttacksCount[COLOR_NB]; }; // Evaluation grain size, must be a power of 2 const int GrainSize = 8; // Evaluation weights, initialized from UCI options enum { Mobility, PassedPawns, Space, KingDangerUs, KingDangerThem }; Score Weights[6]; typedef Value V; #define S(mg, eg) make_score(mg, eg) // Internal evaluation weights. These are applied on top of the evaluation // weights read from UCI parameters. The purpose is to be able to change // the evaluation weights while keeping the default values of the UCI // parameters at 100, which looks prettier. // // Values modified by Joona Kiiski const Score WeightsInternal[] = { S(289, 344), S(221, 273), S(46, 0), S(271, 0), S(307, 0) }; // MobilityBonus[PieceType][attacked] contains mobility bonuses for middle and // end game, indexed by piece type and number of attacked squares not occupied // by friendly pieces. const Score MobilityBonus[][32] = { {}, {}, { S(-38,-33), S(-25,-23), S(-12,-13), S( 0, -3), S(12, 7), S(25, 17), // Knights S( 31, 22), S( 38, 27), S( 38, 27) }, { S(-25,-30), S(-11,-16), S( 3, -2), S(17, 12), S(31, 26), S(45, 40), // Bishops S( 57, 52), S( 65, 60), S( 71, 65), S(74, 69), S(76, 71), S(78, 73), S( 79, 74), S( 80, 75), S( 81, 76), S(81, 76) }, { S(-20,-36), S(-14,-19), S( -8, -3), S(-2, 13), S( 4, 29), S(10, 46), // Rooks S( 14, 62), S( 19, 79), S( 23, 95), S(26,106), S(27,111), S(28,114), S( 29,116), S( 30,117), S( 31,118), S(32,118) }, { S(-10,-18), S( -8,-13), S( -6, -7), S(-3, -2), S(-1, 3), S( 1, 8), // Queens S( 3, 13), S( 5, 19), S( 8, 23), S(10, 27), S(12, 32), S(15, 34), S( 16, 35), S( 17, 35), S( 18, 35), S(20, 35), S(20, 35), S(20, 35), S( 20, 35), S( 20, 35), S( 20, 35), S(20, 35), S(20, 35), S(20, 35), S( 20, 35), S( 20, 35), S( 20, 35), S(20, 35), S(20, 35), S(20, 35), S( 20, 35), S( 20, 35) } }; // OutpostBonus[PieceType][Square] contains outpost bonuses of knights and // bishops, indexed by piece type and square (from white's point of view). const Value OutpostBonus[][SQUARE_NB] = { { // A B C D E F G H V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), // Knights V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(4), V(8), V(8), V(4), V(0), V(0), V(0), V(4),V(17),V(26),V(26),V(17), V(4), V(0), V(0), V(8),V(26),V(35),V(35),V(26), V(8), V(0), V(0), V(4),V(17),V(17),V(17),V(17), V(4), V(0) }, { V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), // Bishops V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(0), V(5), V(5), V(5), V(5), V(0), V(0), V(0), V(5),V(10),V(10),V(10),V(10), V(5), V(0), V(0),V(10),V(21),V(21),V(21),V(21),V(10), V(0), V(0), V(5), V(8), V(8), V(8), V(8), V(5), V(0) } }; // ThreatBonus[attacking][attacked] contains threat bonuses according to // which piece type attacks which one. const Score ThreatBonus[][PIECE_TYPE_NB] = { {}, {}, { S(0, 0), S( 7, 39), S( 0, 0), S(24, 49), S(41,100), S(41,100) }, // KNIGHT { S(0, 0), S( 7, 39), S(24, 49), S( 0, 0), S(41,100), S(41,100) }, // BISHOP { S(0, 0), S( 0, 22), S(15, 49), S(15, 49), S( 0, 0), S(24, 49) }, // ROOK { S(0, 0), S(15, 39), S(15, 39), S(15, 39), S(15, 39), S( 0, 0) } // QUEEN }; // ThreatenedByPawnPenalty[PieceType] contains a penalty according to which // piece type is attacked by an enemy pawn. const Score ThreatenedByPawnPenalty[] = { S(0, 0), S(0, 0), S(56, 70), S(56, 70), S(76, 99), S(86, 118) }; #undef S const Score BishopPinBonus = make_score(66, 11); // Bonus for having the side to move (modified by Joona Kiiski) const Score Tempo = make_score(24, 11); // Rooks and queens on the 7th rank const Score RookOn7thBonus = make_score(11, 20); const Score QueenOn7thBonus = make_score( 3, 8); // Rooks and queens attacking pawns on the same rank const Score RookOnPawnBonus = make_score(10, 28); const Score QueenOnPawnBonus = make_score( 4, 20); // Rooks on open files (modified by Joona Kiiski) const Score RookOpenFileBonus = make_score(43, 21); const Score RookHalfOpenFileBonus = make_score(19, 10); // Penalty for rooks trapped inside a friendly king which has lost the // right to castle. const Value TrappedRookPenalty = Value(180); // Penalty for bishop with pawns on the same coloured squares const Score BishopPawnsPenalty = make_score(8, 12); // Penalty for a bishop on a1/h1 (a8/h8 for black) which is trapped by // a friendly pawn on b2/g2 (b7/g7 for black). This can obviously only // happen in Chess960 games. const Score TrappedBishopA1H1Penalty = make_score(100, 100); // Penalty for an undefended bishop or knight const Score UndefendedMinorPenalty = make_score(25, 10); // The SpaceMask[Color] contains the area of the board which is considered // by the space evaluation. In the middle game, each side is given a bonus // based on how many squares inside this area are safe and available for // friendly minor pieces. const Bitboard SpaceMask[] = { (1ULL << SQ_C2) | (1ULL << SQ_D2) | (1ULL << SQ_E2) | (1ULL << SQ_F2) | (1ULL << SQ_C3) | (1ULL << SQ_D3) | (1ULL << SQ_E3) | (1ULL << SQ_F3) | (1ULL << SQ_C4) | (1ULL << SQ_D4) | (1ULL << SQ_E4) | (1ULL << SQ_F4), (1ULL << SQ_C7) | (1ULL << SQ_D7) | (1ULL << SQ_E7) | (1ULL << SQ_F7) | (1ULL << SQ_C6) | (1ULL << SQ_D6) | (1ULL << SQ_E6) | (1ULL << SQ_F6) | (1ULL << SQ_C5) | (1ULL << SQ_D5) | (1ULL << SQ_E5) | (1ULL << SQ_F5) }; // King danger constants and variables. The king danger scores are taken // from the KingDangerTable[]. Various little "meta-bonuses" measuring // the strength of the enemy attack are added up into an integer, which // is used as an index to KingDangerTable[]. // // KingAttackWeights[PieceType] contains king attack weights by piece type const int KingAttackWeights[] = { 0, 0, 2, 2, 3, 5 }; // Bonuses for enemy's safe checks const int QueenContactCheckBonus = 6; const int RookContactCheckBonus = 4; const int QueenCheckBonus = 3; const int RookCheckBonus = 2; const int BishopCheckBonus = 1; const int KnightCheckBonus = 1; // InitKingDanger[Square] contains penalties based on the position of the // defending king, indexed by king's square (from white's point of view). const int InitKingDanger[] = { 2, 0, 2, 5, 5, 2, 0, 2, 2, 2, 4, 8, 8, 4, 2, 2, 7, 10, 12, 12, 12, 12, 10, 7, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 }; // KingDangerTable[Color][attackUnits] contains the actual king danger // weighted scores, indexed by color and by a calculated integer number. Score KingDangerTable[COLOR_NB][128]; // TracedTerms[Color][PieceType || TracedType] contains a breakdown of the // evaluation terms, used when tracing. Score TracedScores[COLOR_NB][16]; std::stringstream TraceStream; enum TracedType { PST = 8, IMBALANCE = 9, MOBILITY = 10, THREAT = 11, PASSED = 12, UNSTOPPABLE = 13, SPACE = 14, TOTAL = 15 }; // Function prototypes template Value do_evaluate(const Position& pos, Value& margin); template void init_eval_info(const Position& pos, EvalInfo& ei); template Score evaluate_pieces_of_color(const Position& pos, EvalInfo& ei, Score& mobility); template Score evaluate_king(const Position& pos, EvalInfo& ei, Value margins[]); template Score evaluate_threats(const Position& pos, EvalInfo& ei); template int evaluate_space(const Position& pos, EvalInfo& ei); template Score evaluate_passed_pawns(const Position& pos, EvalInfo& ei); Score evaluate_unstoppable_pawns(const Position& pos, EvalInfo& ei); Value interpolate(const Score& v, Phase ph, ScaleFactor sf); Score weight_option(const std::string& mgOpt, const std::string& egOpt, Score internalWeight); double to_cp(Value v); void trace_add(int idx, Score term_w, Score term_b = SCORE_ZERO); void trace_row(const char* name, int idx); } namespace Eval { /// evaluate() is the main evaluation function. It always computes two /// values, an endgame score and a middle game score, and interpolates /// between them based on the remaining material. Value evaluate(const Position& pos, Value& margin) { return do_evaluate(pos, margin); } /// init() computes evaluation weights from the corresponding UCI parameters /// and setup king tables. void init() { Weights[Mobility] = weight_option("Mobility (Middle Game)", "Mobility (Endgame)", WeightsInternal[Mobility]); Weights[PassedPawns] = weight_option("Passed Pawns (Middle Game)", "Passed Pawns (Endgame)", WeightsInternal[PassedPawns]); Weights[Space] = weight_option("Space", "Space", WeightsInternal[Space]); Weights[KingDangerUs] = weight_option("Cowardice", "Cowardice", WeightsInternal[KingDangerUs]); Weights[KingDangerThem] = weight_option("Aggressiveness", "Aggressiveness", WeightsInternal[KingDangerThem]); const int MaxSlope = 30; const int Peak = 1280; for (int t = 0, i = 1; i < 100; i++) { t = std::min(Peak, std::min(int(0.4 * i * i), t + MaxSlope)); KingDangerTable[1][i] = apply_weight(make_score(t, 0), Weights[KingDangerUs]); KingDangerTable[0][i] = apply_weight(make_score(t, 0), Weights[KingDangerThem]); } } /// trace() is like evaluate() but instead of a value returns a string suitable /// to be print on stdout with the detailed descriptions and values of each /// evaluation term. Used mainly for debugging. std::string trace(const Position& pos) { Value margin; std::string totals; Search::RootColor = pos.side_to_move(); TraceStream.str(""); TraceStream << std::showpoint << std::showpos << std::fixed << std::setprecision(2); memset(TracedScores, 0, 2 * 16 * sizeof(Score)); do_evaluate(pos, margin); totals = TraceStream.str(); TraceStream.str(""); TraceStream << std::setw(21) << "Eval term " << "| White | Black | Total \n" << " | MG EG | MG EG | MG EG \n" << "---------------------+-------------+-------------+---------------\n"; trace_row("Material, PST, Tempo", PST); trace_row("Material imbalance", IMBALANCE); trace_row("Pawns", PAWN); trace_row("Knights", KNIGHT); trace_row("Bishops", BISHOP); trace_row("Rooks", ROOK); trace_row("Queens", QUEEN); trace_row("Mobility", MOBILITY); trace_row("King safety", KING); trace_row("Threats", THREAT); trace_row("Passed pawns", PASSED); trace_row("Unstoppable pawns", UNSTOPPABLE); trace_row("Space", SPACE); TraceStream << "---------------------+-------------+-------------+---------------\n"; trace_row("Total", TOTAL); TraceStream << totals; return TraceStream.str(); } } // namespace Eval namespace { template Value do_evaluate(const Position& pos, Value& margin) { assert(!pos.checkers()); EvalInfo ei; Value margins[COLOR_NB]; Score score, mobilityWhite, mobilityBlack; Thread* th = pos.this_thread(); // margins[] store the uncertainty estimation of position's evaluation // that typically is used by the search for pruning decisions. margins[WHITE] = margins[BLACK] = VALUE_ZERO; // Initialize score by reading the incrementally updated scores included // in the position object (material + piece square tables) and adding // Tempo bonus. Score is computed from the point of view of white. score = pos.psq_score() + (pos.side_to_move() == WHITE ? Tempo : -Tempo); // Probe the material hash table ei.mi = Material::probe(pos, th->materialTable, th->endgames); score += ei.mi->material_value(); // If we have a specialized evaluation function for the current material // configuration, call it and return. if (ei.mi->specialized_eval_exists()) { margin = VALUE_ZERO; return ei.mi->evaluate(pos); } // Probe the pawn hash table ei.pi = Pawns::probe(pos, th->pawnsTable); score += ei.pi->pawns_value(); // Initialize attack and king safety bitboards init_eval_info(pos, ei); init_eval_info(pos, ei); // Evaluate pieces and mobility score += evaluate_pieces_of_color(pos, ei, mobilityWhite) - evaluate_pieces_of_color(pos, ei, mobilityBlack); score += apply_weight(mobilityWhite - mobilityBlack, Weights[Mobility]); // Evaluate kings after all other pieces because we need complete attack // information when computing the king safety evaluation. score += evaluate_king(pos, ei, margins) - evaluate_king(pos, ei, margins); // Evaluate tactical threats, we need full attack information including king score += evaluate_threats(pos, ei) - evaluate_threats(pos, ei); // Evaluate passed pawns, we need full attack information including king score += evaluate_passed_pawns(pos, ei) - evaluate_passed_pawns(pos, ei); // If one side has only a king, check whether exists any unstoppable passed pawn if (!pos.non_pawn_material(WHITE) || !pos.non_pawn_material(BLACK)) score += evaluate_unstoppable_pawns(pos, ei); // Evaluate space for both sides, only in middle-game. if (ei.mi->space_weight()) { int s = evaluate_space(pos, ei) - evaluate_space(pos, ei); score += apply_weight(make_score(s * ei.mi->space_weight(), 0), Weights[Space]); } // Scale winning side if position is more drawish that what it appears ScaleFactor sf = eg_value(score) > VALUE_DRAW ? ei.mi->scale_factor(pos, WHITE) : ei.mi->scale_factor(pos, BLACK); // If we don't already have an unusual scale factor, check for opposite // colored bishop endgames, and use a lower scale for those. if ( ei.mi->game_phase() < PHASE_MIDGAME && pos.opposite_bishops() && sf == SCALE_FACTOR_NORMAL) { // Only the two bishops ? if ( pos.non_pawn_material(WHITE) == BishopValueMg && pos.non_pawn_material(BLACK) == BishopValueMg) { // Check for KBP vs KB with only a single pawn that is almost // certainly a draw or at least two pawns. bool one_pawn = (pos.piece_count(WHITE, PAWN) + pos.piece_count(BLACK, PAWN) == 1); sf = one_pawn ? ScaleFactor(8) : ScaleFactor(32); } else // Endgame with opposite-colored bishops, but also other pieces. Still // a bit drawish, but not as drawish as with only the two bishops. sf = ScaleFactor(50); } margin = margins[pos.side_to_move()]; Value v = interpolate(score, ei.mi->game_phase(), sf); // In case of tracing add all single evaluation contributions for both white and black if (Trace) { trace_add(PST, pos.psq_score()); trace_add(IMBALANCE, ei.mi->material_value()); trace_add(PAWN, ei.pi->pawns_value()); trace_add(MOBILITY, apply_weight(mobilityWhite, Weights[Mobility]), apply_weight(mobilityBlack, Weights[Mobility])); trace_add(THREAT, evaluate_threats(pos, ei), evaluate_threats(pos, ei)); trace_add(PASSED, evaluate_passed_pawns(pos, ei), evaluate_passed_pawns(pos, ei)); trace_add(UNSTOPPABLE, evaluate_unstoppable_pawns(pos, ei)); Score w = make_score(ei.mi->space_weight() * evaluate_space(pos, ei), 0); Score b = make_score(ei.mi->space_weight() * evaluate_space(pos, ei), 0); trace_add(SPACE, apply_weight(w, Weights[Space]), apply_weight(b, Weights[Space])); trace_add(TOTAL, score); TraceStream << "\nUncertainty margin: White: " << to_cp(margins[WHITE]) << ", Black: " << to_cp(margins[BLACK]) << "\nScaling: " << std::noshowpos << std::setw(6) << 100.0 * ei.mi->game_phase() / 128.0 << "% MG, " << std::setw(6) << 100.0 * (1.0 - ei.mi->game_phase() / 128.0) << "% * " << std::setw(6) << (100.0 * sf) / SCALE_FACTOR_NORMAL << "% EG.\n" << "Total evaluation: " << to_cp(v); } return pos.side_to_move() == WHITE ? v : -v; } // init_eval_info() initializes king bitboards for given color adding // pawn attacks. To be done at the beginning of the evaluation. template void init_eval_info(const Position& pos, EvalInfo& ei) { const Color Them = (Us == WHITE ? BLACK : WHITE); Bitboard b = ei.attackedBy[Them][KING] = pos.attacks_from(pos.king_square(Them)); ei.attackedBy[Us][PAWN] = ei.pi->pawn_attacks(Us); // Init king safety tables only if we are going to use them if ( pos.piece_count(Us, QUEEN) && pos.non_pawn_material(Us) > QueenValueMg + PawnValueMg) { ei.kingRing[Them] = (b | (Us == WHITE ? b >> 8 : b << 8)); b &= ei.attackedBy[Us][PAWN]; ei.kingAttackersCount[Us] = b ? popcount(b) / 2 : 0; ei.kingAdjacentZoneAttacksCount[Us] = ei.kingAttackersWeight[Us] = 0; } else ei.kingRing[Them] = ei.kingAttackersCount[Us] = 0; } // evaluate_outposts() evaluates bishop and knight outposts squares template Score evaluate_outposts(const Position& pos, EvalInfo& ei, Square s) { const Color Them = (Us == WHITE ? BLACK : WHITE); assert (Piece == BISHOP || Piece == KNIGHT); // Initial bonus based on square Value bonus = OutpostBonus[Piece == BISHOP][relative_square(Us, s)]; // Increase bonus if supported by pawn, especially if the opponent has // no minor piece which can exchange the outpost piece. if (bonus && (ei.attackedBy[Us][PAWN] & s)) { if ( !pos.pieces(Them, KNIGHT) && !(same_color_squares(s) & pos.pieces(Them, BISHOP))) bonus += bonus + bonus / 2; else bonus += bonus / 2; } return make_score(bonus, bonus); } // evaluate_pieces<>() assigns bonuses and penalties to the pieces of a given color template Score evaluate_pieces(const Position& pos, EvalInfo& ei, Score& mobility, Bitboard mobilityArea) { Bitboard b; Square s, ksq; int mob; File f; Score score = SCORE_ZERO; const Color Them = (Us == WHITE ? BLACK : WHITE); const Square* pl = pos.piece_list(Us, Piece); ei.attackedBy[Us][Piece] = 0; while ((s = *pl++) != SQ_NONE) { // Find attacked squares, including x-ray attacks for bishops and rooks if (Piece == KNIGHT || Piece == QUEEN) b = pos.attacks_from(s); else if (Piece == BISHOP) b = attacks_bb(s, pos.pieces() ^ pos.pieces(Us, QUEEN)); else if (Piece == ROOK) b = attacks_bb(s, pos.pieces() ^ pos.pieces(Us, ROOK, QUEEN)); else assert(false); ei.attackedBy[Us][Piece] |= b; if (b & ei.kingRing[Them]) { ei.kingAttackersCount[Us]++; ei.kingAttackersWeight[Us] += KingAttackWeights[Piece]; Bitboard bb = (b & ei.attackedBy[Them][KING]); if (bb) ei.kingAdjacentZoneAttacksCount[Us] += popcount(bb); } mob = (Piece != QUEEN ? popcount(b & mobilityArea) : popcount(b & mobilityArea)); mobility += MobilityBonus[Piece][mob]; // Decrease score if we are attacked by an enemy pawn. Remaining part // of threat evaluation must be done later when we have full attack info. if (ei.attackedBy[Them][PAWN] & s) score -= ThreatenedByPawnPenalty[Piece]; // Otherwise give a bonus if we are a bishop and can pin a piece or // can give a discovered check through an x-ray attack. else if ( Piece == BISHOP && (PseudoAttacks[Piece][pos.king_square(Them)] & s) && !more_than_one(BetweenBB[s][pos.king_square(Them)] & pos.pieces())) score += BishopPinBonus; // Penalty for bishop with same coloured pawns if (Piece == BISHOP) score -= BishopPawnsPenalty * ei.pi->pawns_on_same_color_squares(Us, s); // Bishop and knight outposts squares if ( (Piece == BISHOP || Piece == KNIGHT) && !(pos.pieces(Them, PAWN) & attack_span_mask(Us, s))) score += evaluate_outposts(pos, ei, s); if ((Piece == ROOK || Piece == QUEEN) && relative_rank(Us, s) >= RANK_5) { // Major piece on 7th rank if ( relative_rank(Us, s) == RANK_7 && relative_rank(Us, pos.king_square(Them)) == RANK_8) score += (Piece == ROOK ? RookOn7thBonus : QueenOn7thBonus); // Major piece attacking pawns on the same rank Bitboard pawns = pos.pieces(Them, PAWN) & rank_bb(s); if (pawns) score += (Piece == ROOK ? RookOnPawnBonus : QueenOnPawnBonus) * popcount(pawns); } // Special extra evaluation for bishops if (Piece == BISHOP && pos.is_chess960()) { // An important Chess960 pattern: A cornered bishop blocked by // a friendly pawn diagonally in front of it is a very serious // problem, especially when that pawn is also blocked. if (s == relative_square(Us, SQ_A1) || s == relative_square(Us, SQ_H1)) { Square d = pawn_push(Us) + (file_of(s) == FILE_A ? DELTA_E : DELTA_W); if (pos.piece_on(s + d) == make_piece(Us, PAWN)) { if (!pos.is_empty(s + d + pawn_push(Us))) score -= 2*TrappedBishopA1H1Penalty; else if (pos.piece_on(s + 2*d) == make_piece(Us, PAWN)) score -= TrappedBishopA1H1Penalty; else score -= TrappedBishopA1H1Penalty / 2; } } } // Special extra evaluation for rooks if (Piece == ROOK) { // Open and half-open files f = file_of(s); if (ei.pi->file_is_half_open(Us, f)) { if (ei.pi->file_is_half_open(Them, f)) score += RookOpenFileBonus; else score += RookHalfOpenFileBonus; } if (mob > 6 || ei.pi->file_is_half_open(Us, f)) continue; ksq = pos.king_square(Us); // Penalize rooks which are trapped inside a king. Penalize more if // king has lost right to castle. if ( ((file_of(ksq) < FILE_E) == (file_of(s) < file_of(ksq))) && rank_of(ksq) == rank_of(s) && relative_rank(Us, ksq) == RANK_1 && !ei.pi->has_open_file_on_side(Us, file_of(ksq), file_of(ksq) < FILE_E)) score -= make_score(pos.can_castle(Us) ? (TrappedRookPenalty - mob * 16) / 2 : (TrappedRookPenalty - mob * 16), 0); } } if (Trace) TracedScores[Us][Piece] = score; return score; } // evaluate_threats<>() assigns bonuses according to the type of attacking piece // and the type of attacked one. template Score evaluate_threats(const Position& pos, EvalInfo& ei) { const Color Them = (Us == WHITE ? BLACK : WHITE); Bitboard b, undefendedMinors, weakEnemies; Score score = SCORE_ZERO; // Undefended minors get penalized even if not under attack undefendedMinors = pos.pieces(Them, BISHOP, KNIGHT) & ~ei.attackedBy[Them][ALL_PIECES]; if (undefendedMinors) score += UndefendedMinorPenalty; // Enemy pieces not defended by a pawn and under our attack weakEnemies = pos.pieces(Them) & ~ei.attackedBy[Them][PAWN] & ei.attackedBy[Us][ALL_PIECES]; if (!weakEnemies) return score; // Add bonus according to type of attacked enemy piece and to the // type of attacking piece, from knights to queens. Kings are not // considered because are already handled in king evaluation. for (PieceType pt1 = KNIGHT; pt1 < KING; pt1++) { b = ei.attackedBy[Us][pt1] & weakEnemies; if (b) for (PieceType pt2 = PAWN; pt2 < KING; pt2++) if (b & pos.pieces(pt2)) score += ThreatBonus[pt1][pt2]; } return score; } // evaluate_pieces_of_color<>() assigns bonuses and penalties to all the // pieces of a given color. template Score evaluate_pieces_of_color(const Position& pos, EvalInfo& ei, Score& mobility) { const Color Them = (Us == WHITE ? BLACK : WHITE); Score score = mobility = SCORE_ZERO; // Do not include in mobility squares protected by enemy pawns or occupied by our pieces const Bitboard mobilityArea = ~(ei.attackedBy[Them][PAWN] | pos.pieces(Us, PAWN, KING)); score += evaluate_pieces(pos, ei, mobility, mobilityArea); score += evaluate_pieces(pos, ei, mobility, mobilityArea); score += evaluate_pieces(pos, ei, mobility, mobilityArea); score += evaluate_pieces(pos, ei, mobility, mobilityArea); // Sum up all attacked squares ei.attackedBy[Us][ALL_PIECES] = ei.attackedBy[Us][PAWN] | ei.attackedBy[Us][KNIGHT] | ei.attackedBy[Us][BISHOP] | ei.attackedBy[Us][ROOK] | ei.attackedBy[Us][QUEEN] | ei.attackedBy[Us][KING]; return score; } // evaluate_king<>() assigns bonuses and penalties to a king of a given color template Score evaluate_king(const Position& pos, EvalInfo& ei, Value margins[]) { const Color Them = (Us == WHITE ? BLACK : WHITE); Bitboard undefended, b, b1, b2, safe; int attackUnits; const Square ksq = pos.king_square(Us); // King shelter and enemy pawns storm Score score = ei.pi->king_safety(pos, ksq); // King safety. This is quite complicated, and is almost certainly far // from optimally tuned. if ( ei.kingAttackersCount[Them] >= 2 && ei.kingAdjacentZoneAttacksCount[Them]) { // Find the attacked squares around the king which has no defenders // apart from the king itself undefended = ei.attackedBy[Them][ALL_PIECES] & ei.attackedBy[Us][KING]; undefended &= ~( ei.attackedBy[Us][PAWN] | ei.attackedBy[Us][KNIGHT] | ei.attackedBy[Us][BISHOP] | ei.attackedBy[Us][ROOK] | ei.attackedBy[Us][QUEEN]); // Initialize the 'attackUnits' variable, which is used later on as an // index to the KingDangerTable[] array. The initial value is based on // the number and types of the enemy's attacking pieces, the number of // attacked and undefended squares around our king, the square of the // king, and the quality of the pawn shelter. attackUnits = std::min(25, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2) + 3 * (ei.kingAdjacentZoneAttacksCount[Them] + popcount(undefended)) + InitKingDanger[relative_square(Us, ksq)] - mg_value(score) / 32; // Analyse enemy's safe queen contact checks. First find undefended // squares around the king attacked by enemy queen... b = undefended & ei.attackedBy[Them][QUEEN] & ~pos.pieces(Them); if (b) { // ...then remove squares not supported by another enemy piece b &= ( ei.attackedBy[Them][PAWN] | ei.attackedBy[Them][KNIGHT] | ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][ROOK]); if (b) attackUnits += QueenContactCheckBonus * popcount(b) * (Them == pos.side_to_move() ? 2 : 1); } // Analyse enemy's safe rook contact checks. First find undefended // squares around the king attacked by enemy rooks... b = undefended & ei.attackedBy[Them][ROOK] & ~pos.pieces(Them); // Consider only squares where the enemy rook gives check b &= PseudoAttacks[ROOK][ksq]; if (b) { // ...then remove squares not supported by another enemy piece b &= ( ei.attackedBy[Them][PAWN] | ei.attackedBy[Them][KNIGHT] | ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][QUEEN]); if (b) attackUnits += RookContactCheckBonus * popcount(b) * (Them == pos.side_to_move() ? 2 : 1); } // Analyse enemy's safe distance checks for sliders and knights safe = ~(pos.pieces(Them) | ei.attackedBy[Us][ALL_PIECES]); b1 = pos.attacks_from(ksq) & safe; b2 = pos.attacks_from(ksq) & safe; // Enemy queen safe checks b = (b1 | b2) & ei.attackedBy[Them][QUEEN]; if (b) attackUnits += QueenCheckBonus * popcount(b); // Enemy rooks safe checks b = b1 & ei.attackedBy[Them][ROOK]; if (b) attackUnits += RookCheckBonus * popcount(b); // Enemy bishops safe checks b = b2 & ei.attackedBy[Them][BISHOP]; if (b) attackUnits += BishopCheckBonus * popcount(b); // Enemy knights safe checks b = pos.attacks_from(ksq) & ei.attackedBy[Them][KNIGHT] & safe; if (b) attackUnits += KnightCheckBonus * popcount(b); // To index KingDangerTable[] attackUnits must be in [0, 99] range attackUnits = std::min(99, std::max(0, attackUnits)); // Finally, extract the king danger score from the KingDangerTable[] // array and subtract the score from evaluation. Set also margins[] // value that will be used for pruning because this value can sometimes // be very big, and so capturing a single attacking piece can therefore // result in a score change far bigger than the value of the captured piece. score -= KingDangerTable[Us == Search::RootColor][attackUnits]; margins[Us] += mg_value(KingDangerTable[Us == Search::RootColor][attackUnits]); } if (Trace) TracedScores[Us][KING] = score; return score; } // evaluate_passed_pawns<>() evaluates the passed pawns of the given color template Score evaluate_passed_pawns(const Position& pos, EvalInfo& ei) { const Color Them = (Us == WHITE ? BLACK : WHITE); Bitboard b, squaresToQueen, defendedSquares, unsafeSquares, supportingPawns; Score score = SCORE_ZERO; b = ei.pi->passed_pawns(Us); if (!b) return SCORE_ZERO; do { Square s = pop_lsb(&b); assert(pos.pawn_is_passed(Us, s)); int r = int(relative_rank(Us, s) - RANK_2); int rr = r * (r - 1); // Base bonus based on rank Value mbonus = Value(20 * rr); Value ebonus = Value(10 * (rr + r + 1)); if (rr) { Square blockSq = s + pawn_push(Us); // Adjust bonus based on kings proximity ebonus += Value(square_distance(pos.king_square(Them), blockSq) * 5 * rr); ebonus -= Value(square_distance(pos.king_square(Us), blockSq) * 2 * rr); // If blockSq is not the queening square then consider also a second push if (rank_of(blockSq) != (Us == WHITE ? RANK_8 : RANK_1)) ebonus -= Value(square_distance(pos.king_square(Us), blockSq + pawn_push(Us)) * rr); // If the pawn is free to advance, increase bonus if (pos.is_empty(blockSq)) { squaresToQueen = forward_bb(Us, s); defendedSquares = squaresToQueen & ei.attackedBy[Us][ALL_PIECES]; // If there is an enemy rook or queen attacking the pawn from behind, // add all X-ray attacks by the rook or queen. Otherwise consider only // the squares in the pawn's path attacked or occupied by the enemy. if ( (forward_bb(Them, s) & pos.pieces(Them, ROOK, QUEEN)) && (forward_bb(Them, s) & pos.pieces(Them, ROOK, QUEEN) & pos.attacks_from(s))) unsafeSquares = squaresToQueen; else unsafeSquares = squaresToQueen & (ei.attackedBy[Them][ALL_PIECES] | pos.pieces(Them)); // If there aren't enemy attacks or pieces along the path to queen give // huge bonus. Even bigger if we protect the pawn's path. if (!unsafeSquares) ebonus += Value(rr * (squaresToQueen == defendedSquares ? 17 : 15)); else // OK, there are enemy attacks or pieces (but not pawns). Are those // squares which are attacked by the enemy also attacked by us ? // If yes, big bonus (but smaller than when there are no enemy attacks), // if no, somewhat smaller bonus. ebonus += Value(rr * ((unsafeSquares & defendedSquares) == unsafeSquares ? 13 : 8)); } } // rr != 0 // Increase the bonus if the passed pawn is supported by a friendly pawn // on the same rank and a bit smaller if it's on the previous rank. supportingPawns = pos.pieces(Us, PAWN) & adjacent_files_bb(file_of(s)); if (supportingPawns & rank_bb(s)) ebonus += Value(r * 20); else if (supportingPawns & rank_bb(s - pawn_push(Us))) ebonus += Value(r * 12); // Rook pawns are a special case: They are sometimes worse, and // sometimes better than other passed pawns. It is difficult to find // good rules for determining whether they are good or bad. For now, // we try the following: Increase the value for rook pawns if the // other side has no pieces apart from a knight, and decrease the // value if the other side has a rook or queen. if (file_of(s) == FILE_A || file_of(s) == FILE_H) { if (pos.non_pawn_material(Them) <= KnightValueMg) ebonus += ebonus / 4; else if (pos.pieces(Them, ROOK, QUEEN)) ebonus -= ebonus / 4; } score += make_score(mbonus, ebonus); } while (b); // Add the scores to the middle game and endgame eval return apply_weight(score, Weights[PassedPawns]); } // evaluate_unstoppable_pawns() evaluates the unstoppable passed pawns for both sides, this is quite // conservative and returns a winning score only when we are very sure that the pawn is winning. Score evaluate_unstoppable_pawns(const Position& pos, EvalInfo& ei) { Bitboard b, b2, blockers, supporters, queeningPath, candidates; Square s, blockSq, queeningSquare; Color c, winnerSide, loserSide; bool pathDefended, opposed; int pliesToGo, movesToGo, oppMovesToGo, sacptg, blockersCount, minKingDist, kingptg, d; int pliesToQueen[] = { 256, 256 }; // Step 1. Hunt for unstoppable passed pawns. If we find at least one, // record how many plies are required for promotion. for (c = WHITE; c <= BLACK; c++) { // Skip if other side has non-pawn pieces if (pos.non_pawn_material(~c)) continue; b = ei.pi->passed_pawns(c); while (b) { s = pop_lsb(&b); queeningSquare = relative_square(c, file_of(s) | RANK_8); queeningPath = forward_bb(c, s); // Compute plies to queening and check direct advancement movesToGo = rank_distance(s, queeningSquare) - int(relative_rank(c, s) == RANK_2); oppMovesToGo = square_distance(pos.king_square(~c), queeningSquare) - int(c != pos.side_to_move()); pathDefended = ((ei.attackedBy[c][ALL_PIECES] & queeningPath) == queeningPath); if (movesToGo >= oppMovesToGo && !pathDefended) continue; // Opponent king cannot block because path is defended and position // is not in check. So only friendly pieces can be blockers. assert(!pos.checkers()); assert((queeningPath & pos.pieces()) == (queeningPath & pos.pieces(c))); // Add moves needed to free the path from friendly pieces and retest condition movesToGo += popcount(queeningPath & pos.pieces(c)); if (movesToGo >= oppMovesToGo && !pathDefended) continue; pliesToGo = 2 * movesToGo - int(c == pos.side_to_move()); pliesToQueen[c] = std::min(pliesToQueen[c], pliesToGo); } } // Step 2. If either side cannot promote at least three plies before the other side then situation // becomes too complex and we give up. Otherwise we determine the possibly "winning side" if (abs(pliesToQueen[WHITE] - pliesToQueen[BLACK]) < 3) return SCORE_ZERO; winnerSide = (pliesToQueen[WHITE] < pliesToQueen[BLACK] ? WHITE : BLACK); loserSide = ~winnerSide; // Step 3. Can the losing side possibly create a new passed pawn and thus prevent the loss? b = candidates = pos.pieces(loserSide, PAWN); while (b) { s = pop_lsb(&b); // Compute plies from queening queeningSquare = relative_square(loserSide, file_of(s) | RANK_8); movesToGo = rank_distance(s, queeningSquare) - int(relative_rank(loserSide, s) == RANK_2); pliesToGo = 2 * movesToGo - int(loserSide == pos.side_to_move()); // Check if (without even considering any obstacles) we're too far away or doubled if ( pliesToQueen[winnerSide] + 3 <= pliesToGo || (forward_bb(loserSide, s) & pos.pieces(loserSide, PAWN))) candidates ^= s; } // If any candidate is already a passed pawn it _may_ promote in time. We give up. if (candidates & ei.pi->passed_pawns(loserSide)) return SCORE_ZERO; // Step 4. Check new passed pawn creation through king capturing and pawn sacrifices b = candidates; while (b) { s = pop_lsb(&b); sacptg = blockersCount = 0; minKingDist = kingptg = 256; // Compute plies from queening queeningSquare = relative_square(loserSide, file_of(s) | RANK_8); movesToGo = rank_distance(s, queeningSquare) - int(relative_rank(loserSide, s) == RANK_2); pliesToGo = 2 * movesToGo - int(loserSide == pos.side_to_move()); // Generate list of blocking pawns and supporters supporters = adjacent_files_bb(file_of(s)) & candidates; opposed = forward_bb(loserSide, s) & pos.pieces(winnerSide, PAWN); blockers = passed_pawn_mask(loserSide, s) & pos.pieces(winnerSide, PAWN); assert(blockers); // How many plies does it take to remove all the blocking pawns? while (blockers) { blockSq = pop_lsb(&blockers); movesToGo = 256; // Check pawns that can give support to overcome obstacle, for instance // black pawns: a4, b4 white: b2 then pawn in b4 is giving support. if (!opposed) { b2 = supporters & in_front_bb(winnerSide, blockSq + pawn_push(winnerSide)); while (b2) // This while-loop could be replaced with LSB/MSB (depending on color) { d = square_distance(blockSq, pop_lsb(&b2)) - 2; movesToGo = std::min(movesToGo, d); } } // Check pawns that can be sacrificed against the blocking pawn b2 = attack_span_mask(winnerSide, blockSq) & candidates & ~(1ULL << s); while (b2) // This while-loop could be replaced with LSB/MSB (depending on color) { d = square_distance(blockSq, pop_lsb(&b2)) - 2; movesToGo = std::min(movesToGo, d); } // If obstacle can be destroyed with an immediate pawn exchange / sacrifice, // it's not a real obstacle and we have nothing to add to pliesToGo. if (movesToGo <= 0) continue; // Plies needed to sacrifice against all the blocking pawns sacptg += movesToGo * 2; blockersCount++; // Plies needed for the king to capture all the blocking pawns d = square_distance(pos.king_square(loserSide), blockSq); minKingDist = std::min(minKingDist, d); kingptg = (minKingDist + blockersCount) * 2; } // Check if pawn sacrifice plan _may_ save the day if (pliesToQueen[winnerSide] + 3 > pliesToGo + sacptg) return SCORE_ZERO; // Check if king capture plan _may_ save the day (contains some false positives) if (pliesToQueen[winnerSide] + 3 > pliesToGo + kingptg) return SCORE_ZERO; } // Winning pawn is unstoppable and will promote as first, return big score Score score = make_score(0, (Value) 1280 - 32 * pliesToQueen[winnerSide]); return winnerSide == WHITE ? score : -score; } // evaluate_space() computes the space evaluation for a given side. The // space evaluation is a simple bonus based on the number of safe squares // available for minor pieces on the central four files on ranks 2--4. Safe // squares one, two or three squares behind a friendly pawn are counted // twice. Finally, the space bonus is scaled by a weight taken from the // material hash table. The aim is to improve play on game opening. template int evaluate_space(const Position& pos, EvalInfo& ei) { const Color Them = (Us == WHITE ? BLACK : WHITE); // Find the safe squares for our pieces inside the area defined by // SpaceMask[]. A square is unsafe if it is attacked by an enemy // pawn, or if it is undefended and attacked by an enemy piece. Bitboard safe = SpaceMask[Us] & ~pos.pieces(Us, PAWN) & ~ei.attackedBy[Them][PAWN] & (ei.attackedBy[Us][ALL_PIECES] | ~ei.attackedBy[Them][ALL_PIECES]); // Find all squares which are at most three squares behind some friendly pawn Bitboard behind = pos.pieces(Us, PAWN); behind |= (Us == WHITE ? behind >> 8 : behind << 8); behind |= (Us == WHITE ? behind >> 16 : behind << 16); // Since SpaceMask[Us] is fully on our half of the board assert(unsigned(safe >> (Us == WHITE ? 32 : 0)) == 0); // Count safe + (behind & safe) with a single popcount return popcount((Us == WHITE ? safe << 32 : safe >> 32) | (behind & safe)); } // interpolate() interpolates between a middle game and an endgame score, // based on game phase. It also scales the return value by a ScaleFactor array. Value interpolate(const Score& v, Phase ph, ScaleFactor sf) { assert(mg_value(v) > -VALUE_INFINITE && mg_value(v) < VALUE_INFINITE); assert(eg_value(v) > -VALUE_INFINITE && eg_value(v) < VALUE_INFINITE); assert(ph >= PHASE_ENDGAME && ph <= PHASE_MIDGAME); int ev = (eg_value(v) * int(sf)) / SCALE_FACTOR_NORMAL; int result = (mg_value(v) * int(ph) + ev * int(128 - ph)) / 128; return Value((result + GrainSize / 2) & ~(GrainSize - 1)); } // weight_option() computes the value of an evaluation weight, by combining // two UCI-configurable weights (midgame and endgame) with an internal weight. Score weight_option(const std::string& mgOpt, const std::string& egOpt, Score internalWeight) { // Scale option value from 100 to 256 int mg = Options[mgOpt] * 256 / 100; int eg = Options[egOpt] * 256 / 100; return apply_weight(make_score(mg, eg), internalWeight); } // A couple of little helpers used by tracing code, to_cp() converts a value to // a double in centipawns scale, trace_add() stores white and black scores. double to_cp(Value v) { return double(v) / double(PawnValueMg); } void trace_add(int idx, Score wScore, Score bScore) { TracedScores[WHITE][idx] = wScore; TracedScores[BLACK][idx] = bScore; } // trace_row() is an helper function used by tracing code to register the // values of a single evaluation term. void trace_row(const char* name, int idx) { Score wScore = TracedScores[WHITE][idx]; Score bScore = TracedScores[BLACK][idx]; switch (idx) { case PST: case IMBALANCE: case PAWN: case UNSTOPPABLE: case TOTAL: TraceStream << std::setw(20) << name << " | --- --- | --- --- | " << std::setw(6) << to_cp(mg_value(wScore)) << " " << std::setw(6) << to_cp(eg_value(wScore)) << " \n"; break; default: TraceStream << std::setw(20) << name << " | " << std::noshowpos << std::setw(5) << to_cp(mg_value(wScore)) << " " << std::setw(5) << to_cp(eg_value(wScore)) << " | " << std::setw(5) << to_cp(mg_value(bScore)) << " " << std::setw(5) << to_cp(eg_value(bScore)) << " | " << std::showpos << std::setw(6) << to_cp(mg_value(wScore - bScore)) << " " << std::setw(6) << to_cp(eg_value(wScore - bScore)) << " \n"; } } } stockfish-3.0.0+git20130508/src/ucioption.cpp0000644000175000017500000001404112142540127017775 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include "evaluate.h" #include "misc.h" #include "thread.h" #include "tt.h" #include "ucioption.h" using std::string; UCI::OptionsMap Options; // Global object namespace UCI { /// 'On change' actions, triggered by an option's value change void on_logger(const Option& o) { start_logger(o); } void on_eval(const Option&) { Eval::init(); } void on_threads(const Option&) { Threads.read_uci_options(); } void on_hash_size(const Option& o) { TT.set_size(o); } void on_clear_hash(const Option&) { TT.clear(); } /// Our case insensitive less() function as required by UCI protocol bool ci_less(char c1, char c2) { return tolower(c1) < tolower(c2); } bool CaseInsensitiveLess::operator() (const string& s1, const string& s2) const { return std::lexicographical_compare(s1.begin(), s1.end(), s2.begin(), s2.end(), ci_less); } /// init() initializes the UCI options to their hard coded default values /// and initializes the default value of "Threads" and "Min Split Depth" /// parameters according to the number of CPU cores detected. void init(OptionsMap& o) { int cpus = std::min(cpu_count(), MAX_THREADS); int msd = cpus < 8 ? 4 : 7; o["Use Debug Log"] = Option(false, on_logger); o["Use Search Log"] = Option(false); o["Search Log Filename"] = Option("SearchLog.txt"); o["Book File"] = Option("book.bin"); o["Best Book Move"] = Option(false); o["Contempt Factor"] = Option(0, -50, 50); o["Mobility (Middle Game)"] = Option(100, 0, 200, on_eval); o["Mobility (Endgame)"] = Option(100, 0, 200, on_eval); o["Passed Pawns (Middle Game)"] = Option(100, 0, 200, on_eval); o["Passed Pawns (Endgame)"] = Option(100, 0, 200, on_eval); o["Space"] = Option(100, 0, 200, on_eval); o["Aggressiveness"] = Option(100, 0, 200, on_eval); o["Cowardice"] = Option(100, 0, 200, on_eval); o["Min Split Depth"] = Option(msd, 4, 12, on_threads); o["Max Threads per Split Point"] = Option(5, 4, 8, on_threads); o["Threads"] = Option(cpus, 1, MAX_THREADS, on_threads); o["Use Sleeping Threads"] = Option(true); o["Hash"] = Option(32, 1, 8192, on_hash_size); o["Clear Hash"] = Option(on_clear_hash); o["Ponder"] = Option(true); o["OwnBook"] = Option(false); o["MultiPV"] = Option(1, 1, 500); o["Skill Level"] = Option(20, 0, 20); o["Emergency Move Horizon"] = Option(40, 0, 50); o["Emergency Base Time"] = Option(200, 0, 30000); o["Emergency Move Time"] = Option(70, 0, 5000); o["Minimum Thinking Time"] = Option(20, 0, 5000); o["Slow Mover"] = Option(100, 10, 1000); o["UCI_Chess960"] = Option(false); o["UCI_AnalyseMode"] = Option(false, on_eval); } /// operator<<() is used to print all the options default values in chronological /// insertion order (the idx field) and in the format defined by the UCI protocol. std::ostream& operator<<(std::ostream& os, const OptionsMap& om) { for (size_t idx = 0; idx < om.size(); idx++) for (OptionsMap::const_iterator it = om.begin(); it != om.end(); ++it) if (it->second.idx == idx) { const Option& o = it->second; os << "\noption name " << it->first << " type " << o.type; if (o.type != "button") os << " default " << o.defaultValue; if (o.type == "spin") os << " min " << o.min << " max " << o.max; break; } return os; } /// Option c'tors and conversion operators Option::Option(const char* v, Fn* f) : type("string"), min(0), max(0), idx(Options.size()), on_change(f) { defaultValue = currentValue = v; } Option::Option(bool v, Fn* f) : type("check"), min(0), max(0), idx(Options.size()), on_change(f) { defaultValue = currentValue = (v ? "true" : "false"); } Option::Option(Fn* f) : type("button"), min(0), max(0), idx(Options.size()), on_change(f) {} Option::Option(int v, int minv, int maxv, Fn* f) : type("spin"), min(minv), max(maxv), idx(Options.size()), on_change(f) { std::ostringstream ss; ss << v; defaultValue = currentValue = ss.str(); } Option::operator int() const { assert(type == "check" || type == "spin"); return (type == "spin" ? atoi(currentValue.c_str()) : currentValue == "true"); } Option::operator std::string() const { assert(type == "string"); return currentValue; } /// operator=() updates currentValue and triggers on_change() action. It's up to /// the GUI to check for option's limits, but we could receive the new value from /// the user by console window, so let's check the bounds anyway. Option& Option::operator=(const string& v) { assert(!type.empty()); if ( (type != "button" && v.empty()) || (type == "check" && v != "true" && v != "false") || (type == "spin" && (atoi(v.c_str()) < min || atoi(v.c_str()) > max))) return *this; if (type != "button") currentValue = v; if (on_change) (*on_change)(*this); return *this; } } // namespace UCI stockfish-3.0.0+git20130508/src/psqtab.h0000644000175000017500000001324712142540127016732 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #if !defined(PSQTAB_H_INCLUDED) #define PSQTAB_H_INCLUDED #include "types.h" #define S(mg, eg) make_score(mg, eg) /// PSQT[PieceType][Square] contains Piece-Square scores. For each piece type on /// a given square a (midgame, endgame) score pair is assigned. PSQT is defined /// for white side, for black side the tables are symmetric. static const Score PSQT[][SQUARE_NB] = { { }, { // Pawn S( 0, 0), S( 0, 0), S( 0, 0), S( 0, 0), S(0, 0), S( 0, 0), S( 0, 0), S( 0, 0), S(-28,-8), S(-6,-8), S( 4,-8), S(14,-8), S(14,-8), S( 4,-8), S(-6,-8), S(-28,-8), S(-28,-8), S(-6,-8), S( 9,-8), S(36,-8), S(36,-8), S( 9,-8), S(-6,-8), S(-28,-8), S(-28,-8), S(-6,-8), S(17,-8), S(58,-8), S(58,-8), S(17,-8), S(-6,-8), S(-28,-8), S(-28,-8), S(-6,-8), S(17,-8), S(36,-8), S(36,-8), S(17,-8), S(-6,-8), S(-28,-8), S(-28,-8), S(-6,-8), S( 9,-8), S(14,-8), S(14,-8), S( 9,-8), S(-6,-8), S(-28,-8), S(-28,-8), S(-6,-8), S( 4,-8), S(14,-8), S(14,-8), S( 4,-8), S(-6,-8), S(-28,-8), S( 0, 0), S( 0, 0), S( 0, 0), S( 0, 0), S(0, 0), S( 0, 0), S( 0, 0), S( 0, 0) }, { // Knight S(-135,-104), S(-107,-79), S(-80,-55), S(-67,-42), S(-67,-42), S(-80,-55), S(-107,-79), S(-135,-104), S( -93, -79), S( -67,-55), S(-39,-30), S(-25,-17), S(-25,-17), S(-39,-30), S( -67,-55), S( -93, -79), S( -53, -55), S( -25,-30), S( 1, -6), S( 13, 5), S( 13, 5), S( 1, -6), S( -25,-30), S( -53, -55), S( -25, -42), S( 1,-17), S( 27, 5), S( 41, 18), S( 41, 18), S( 27, 5), S( 1,-17), S( -25, -42), S( -11, -42), S( 13,-17), S( 41, 5), S( 55, 18), S( 55, 18), S( 41, 5), S( 13,-17), S( -11, -42), S( -11, -55), S( 13,-30), S( 41, -6), S( 55, 5), S( 55, 5), S( 41, -6), S( 13,-30), S( -11, -55), S( -53, -79), S( -25,-55), S( 1,-30), S( 13,-17), S( 13,-17), S( 1,-30), S( -25,-55), S( -53, -79), S(-193,-104), S( -67,-79), S(-39,-55), S(-25,-42), S(-25,-42), S(-39,-55), S( -67,-79), S(-193,-104) }, { // Bishop S(-40,-59), S(-40,-42), S(-35,-35), S(-30,-26), S(-30,-26), S(-35,-35), S(-40,-42), S(-40,-59), S(-17,-42), S( 0,-26), S( -4,-18), S( 0,-11), S( 0,-11), S( -4,-18), S( 0,-26), S(-17,-42), S(-13,-35), S( -4,-18), S( 8,-11), S( 4, -4), S( 4, -4), S( 8,-11), S( -4,-18), S(-13,-35), S( -8,-26), S( 0,-11), S( 4, -4), S( 17, 4), S( 17, 4), S( 4, -4), S( 0,-11), S( -8,-26), S( -8,-26), S( 0,-11), S( 4, -4), S( 17, 4), S( 17, 4), S( 4, -4), S( 0,-11), S( -8,-26), S(-13,-35), S( -4,-18), S( 8,-11), S( 4, -4), S( 4, -4), S( 8,-11), S( -4,-18), S(-13,-35), S(-17,-42), S( 0,-26), S( -4,-18), S( 0,-11), S( 0,-11), S( -4,-18), S( 0,-26), S(-17,-42), S(-17,-59), S(-17,-42), S(-13,-35), S( -8,-26), S( -8,-26), S(-13,-35), S(-17,-42), S(-17,-59) }, { // Rook S(-12, 3), S(-7, 3), S(-2, 3), S(2, 3), S(2, 3), S(-2, 3), S(-7, 3), S(-12, 3), S(-12, 3), S(-7, 3), S(-2, 3), S(2, 3), S(2, 3), S(-2, 3), S(-7, 3), S(-12, 3), S(-12, 3), S(-7, 3), S(-2, 3), S(2, 3), S(2, 3), S(-2, 3), S(-7, 3), S(-12, 3), S(-12, 3), S(-7, 3), S(-2, 3), S(2, 3), S(2, 3), S(-2, 3), S(-7, 3), S(-12, 3), S(-12, 3), S(-7, 3), S(-2, 3), S(2, 3), S(2, 3), S(-2, 3), S(-7, 3), S(-12, 3), S(-12, 3), S(-7, 3), S(-2, 3), S(2, 3), S(2, 3), S(-2, 3), S(-7, 3), S(-12, 3), S(-12, 3), S(-7, 3), S(-2, 3), S(2, 3), S(2, 3), S(-2, 3), S(-7, 3), S(-12, 3), S(-12, 3), S(-7, 3), S(-2, 3), S(2, 3), S(2, 3), S(-2, 3), S(-7, 3), S(-12, 3) }, { // Queen S(8,-80), S(8,-54), S(8,-42), S(8,-30), S(8,-30), S(8,-42), S(8,-54), S(8,-80), S(8,-54), S(8,-30), S(8,-18), S(8, -6), S(8, -6), S(8,-18), S(8,-30), S(8,-54), S(8,-42), S(8,-18), S(8, -6), S(8, 6), S(8, 6), S(8, -6), S(8,-18), S(8,-42), S(8,-30), S(8, -6), S(8, 6), S(8, 18), S(8, 18), S(8, 6), S(8, -6), S(8,-30), S(8,-30), S(8, -6), S(8, 6), S(8, 18), S(8, 18), S(8, 6), S(8, -6), S(8,-30), S(8,-42), S(8,-18), S(8, -6), S(8, 6), S(8, 6), S(8, -6), S(8,-18), S(8,-42), S(8,-54), S(8,-30), S(8,-18), S(8, -6), S(8, -6), S(8,-18), S(8,-30), S(8,-54), S(8,-80), S(8,-54), S(8,-42), S(8,-30), S(8,-30), S(8,-42), S(8,-54), S(8,-80) }, { // King S(287, 18), S(311, 77), S(262,105), S(214,135), S(214,135), S(262,105), S(311, 77), S(287, 18), S(262, 77), S(287,135), S(238,165), S(190,193), S(190,193), S(238,165), S(287,135), S(262, 77), S(214,105), S(238,165), S(190,193), S(142,222), S(142,222), S(190,193), S(238,165), S(214,105), S(190,135), S(214,193), S(167,222), S(119,251), S(119,251), S(167,222), S(214,193), S(190,135), S(167,135), S(190,193), S(142,222), S( 94,251), S( 94,251), S(142,222), S(190,193), S(167,135), S(142,105), S(167,165), S(119,193), S( 69,222), S( 69,222), S(119,193), S(167,165), S(142,105), S(119, 77), S(142,135), S( 94,165), S( 46,193), S( 46,193), S( 94,165), S(142,135), S(119, 77), S(94, 18), S(119, 77), S( 69,105), S( 21,135), S( 21,135), S( 69,105), S(119, 77), S( 94, 18) } }; #undef S #endif // !defined(PSQTAB_H_INCLUDED) stockfish-3.0.0+git20130508/src/Makefile0000644000175000017500000003223412142540127016724 0ustar oliveroliver# Stockfish, a UCI chess playing engine derived from Glaurung 2.1 # Copyright (C) 2004-2008 Tord Romstad (Glaurung author) # Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad # # 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. # # 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . ### ========================================================================== ### Section 1. General Configuration ### ========================================================================== ### Establish the operating system name UNAME = $(shell uname) ### Executable name EXE = stockfish ### Installation dir definitions PREFIX = /usr/local # Haiku has a non-standard filesystem layout ifeq ($(UNAME),Haiku) PREFIX=/boot/common endif BINDIR = $(PREFIX)/bin ### Built-in benchmark for pgo-builds PGOBENCH = ./$(EXE) bench 32 1 10 default depth ### Object files OBJS = benchmark.o bitbase.o bitboard.o book.o endgame.o evaluate.o main.o \ material.o misc.o movegen.o movepick.o notation.o pawns.o position.o \ search.o thread.o timeman.o tt.o uci.o ucioption.o ### ========================================================================== ### Section 2. High-level Configuration ### ========================================================================== # # flag --- Comp switch --- Description # ---------------------------------------------------------------------------- # # debug = yes/no --- -DNDEBUG --- Enable/Disable debug mode # optimize = yes/no --- (-O3/-fast etc.) --- Enable/Disable optimizations # arch = (name) --- (-arch) --- Target architecture # os = (name) --- --- Target operating system # bits = 64/32 --- -DIS_64BIT --- 64-/32-bit operating system # prefetch = yes/no --- -DUSE_PREFETCH --- Use prefetch x86 asm-instruction # bsfq = yes/no --- -DUSE_BSFQ --- Use bsfq x86_64 asm-instruction (only # with GCC and ICC 64-bit) # popcnt = yes/no --- -DUSE_POPCNT --- Use popcnt x86_64 asm-instruction # sse = yes/no --- -msse --- Use Intel Streaming SIMD Extensions # # Note that Makefile is space sensitive, so when adding new architectures # or modifying existing flags, you have to make sure there are no extra spaces # at the end of the line for flag values. ### 2.1. General debug = no optimize = yes ### 2.2 Architecture specific # General-section ifeq ($(ARCH),general-64) arch = any os = any bits = 64 prefetch = no bsfq = no popcnt = no sse = no endif ifeq ($(ARCH),general-32) arch = any os = any bits = 32 prefetch = no bsfq = no popcnt = no sse = no endif # x86-section ifeq ($(ARCH),x86-64) arch = x86_64 os = any bits = 64 prefetch = yes bsfq = yes popcnt = no sse = yes endif ifeq ($(ARCH),x86-64-modern) arch = x86_64 os = any bits = 64 prefetch = yes bsfq = yes popcnt = yes sse = yes endif ifeq ($(ARCH),x86-32) arch = i386 os = any bits = 32 prefetch = yes bsfq = no popcnt = no sse = yes endif ifeq ($(ARCH),x86-32-old) arch = i386 os = any bits = 32 prefetch = no bsfq = no popcnt = no sse = no endif #arm section ifeq ($(ARCH),armv7) arch = armv7 os = any bits = 32 prefetch = yes bsfq = yes popcnt = no sse = no endif # osx-section ifeq ($(ARCH),osx-ppc-64) arch = ppc64 os = osx bits = 64 prefetch = no bsfq = no popcnt = no sse = no endif ifeq ($(ARCH),osx-ppc-32) arch = ppc os = osx bits = 32 prefetch = no bsfq = no popcnt = no sse = no endif ifeq ($(ARCH),osx-x86-64) arch = x86_64 os = osx bits = 64 prefetch = yes bsfq = yes popcnt = no sse = yes endif ifeq ($(ARCH),osx-x86-32) arch = i386 os = osx bits = 32 prefetch = yes bsfq = no popcnt = no sse = yes endif ### ========================================================================== ### Section 3. Low-level configuration ### ========================================================================== ### 3.1 Selecting compiler (default = gcc) ifeq ($(COMP),) COMP=gcc endif ifeq ($(COMP),mingw) comp=mingw CXX=g++ profile_prepare = gcc-profile-prepare profile_make = gcc-profile-make profile_use = gcc-profile-use profile_clean = gcc-profile-clean endif ifeq ($(COMP),gcc) comp=gcc CXX=g++ profile_prepare = gcc-profile-prepare profile_make = gcc-profile-make profile_use = gcc-profile-use profile_clean = gcc-profile-clean endif ifeq ($(COMP),icc) comp=icc CXX=icpc profile_prepare = icc-profile-prepare profile_make = icc-profile-make profile_use = icc-profile-use profile_clean = icc-profile-clean endif ifeq ($(COMP),clang) comp=clang CXX=clang++ profile_prepare = gcc-profile-prepare profile_make = gcc-profile-make profile_use = gcc-profile-use profile_clean = gcc-profile-clean endif ### 3.2 General compiler settings CXXFLAGS = -g -Wall -Wcast-qual -fno-exceptions -fno-rtti $(EXTRACXXFLAGS) ifeq ($(comp),gcc) CXXFLAGS += -ansi -pedantic -Wno-long-long -Wextra -Wshadow endif ifeq ($(comp),mingw) CXXFLAGS += -Wextra -Wshadow endif ifeq ($(comp),icc) CXXFLAGS += -wd383,981,1418,1419,1476,10187,10188,11505,11503 -Wcheck -Wabi -Wdeprecated -strict-ansi endif ifeq ($(comp),clang) CXXFLAGS += -ansi -pedantic -Wno-long-long -Wextra -Wshadow endif ifeq ($(os),osx) CXXFLAGS += -arch $(arch) -mmacosx-version-min=10.0 endif ### 3.3 General linker settings LDFLAGS = $(EXTRALDFLAGS) ifeq ($(comp),mingw) LDFLAGS += -static-libstdc++ -static-libgcc endif ### On mingw use Windows threads, otherwise POSIX ifneq ($(comp),mingw) # Haiku has pthreads in its libroot, so only link it in on other platforms ifneq ($(UNAME),Haiku) LDFLAGS += -lpthread endif endif ifeq ($(os),osx) LDFLAGS += -arch $(arch) -mmacosx-version-min=10.0 endif ### 3.4 Debugging ifeq ($(debug),no) CXXFLAGS += -DNDEBUG endif ### 3.5 Optimization ifeq ($(optimize),yes) ifeq ($(comp),gcc) CXXFLAGS += -O3 ifeq ($(os),osx) ifeq ($(arch),i386) CXXFLAGS += -mdynamic-no-pic endif ifeq ($(arch),x86_64) CXXFLAGS += -mdynamic-no-pic endif endif ifeq ($(arch),armv7) CXXFLAGS += -fno-gcse endif endif ifeq ($(comp),mingw) CXXFLAGS += -O3 endif ifeq ($(comp),icc) ifeq ($(os),osx) CXXFLAGS += -fast -mdynamic-no-pic else CXXFLAGS += -O3 endif endif ifeq ($(comp),clang) ### -O4 requires a linker that supports LLVM's LTO CXXFLAGS += -O3 ifeq ($(os),osx) ifeq ($(arch),i386) CXXFLAGS += -mdynamic-no-pic endif ifeq ($(arch),x86_64) CXXFLAGS += -mdynamic-no-pic endif endif endif endif ### 3.6. Bits ifeq ($(bits),64) CXXFLAGS += -DIS_64BIT endif ### 3.7 prefetch ifeq ($(prefetch),yes) ifeq ($(sse),yes) CXXFLAGS += -msse DEPENDFLAGS += -msse endif else CXXFLAGS += -DNO_PREFETCH endif ### 3.8 bsfq ifeq ($(bsfq),yes) CXXFLAGS += -DUSE_BSFQ endif ### 3.9 popcnt ifeq ($(popcnt),yes) CXXFLAGS += -msse3 -DUSE_POPCNT endif ### 3.10 Link Time Optimization, it works since gcc 4.5 but not on mingw. ### This is a mix of compile and link time options because the lto link phase ### needs access to the optimization flags. ifeq ($(comp),gcc) ifeq ($(optimize),yes) GCC_MAJOR := `$(CXX) -dumpversion | cut -f1 -d.` GCC_MINOR := `$(CXX) -dumpversion | cut -f2 -d.` ifeq (1,$(shell expr \( $(GCC_MAJOR) \> 4 \) \| \( $(GCC_MAJOR) \= 4 \& $(GCC_MINOR) \>= 5 \))) CXXFLAGS += -flto LDFLAGS += $(CXXFLAGS) endif endif endif ### ========================================================================== ### Section 4. Public targets ### ========================================================================== help: @echo "" @echo "To compile stockfish, type: " @echo "" @echo "make target ARCH=arch [COMP=comp]" @echo "" @echo "Supported targets:" @echo "" @echo "build > Build unoptimized version" @echo "profile-build > Build PGO-optimized version" @echo "strip > Strip executable" @echo "install > Install executable" @echo "clean > Clean up" @echo "testrun > Make sample run" @echo "" @echo "Supported archs:" @echo "" @echo "x86-64 > x86 64-bit" @echo "x86-64-modern > x86 64-bit with runtime support for popcnt instruction" @echo "x86-32 > x86 32-bit excluding old hardware without SSE-support" @echo "x86-32-old > x86 32-bit including also very old hardware" @echo "osx-ppc-64 > PPC-Mac OS X 64 bit" @echo "osx-ppc-32 > PPC-Mac OS X 32 bit" @echo "osx-x86-64 > x86-Mac OS X 64 bit" @echo "osx-x86-32 > x86-Mac OS X 32 bit" @echo "armv7 > ARMv7 32 bit" @echo "general-64 > unspecified 64-bit" @echo "general-32 > unspecified 32-bit" @echo "" @echo "Supported comps:" @echo "" @echo "gcc > Gnu compiler (default)" @echo "icc > Intel compiler" @echo "mingw > Gnu compiler with MinGW under Windows" @echo "clang > LLVM Clang compiler" @echo "" @echo "Non-standard targets:" @echo "" @echo "make hpux > Compile for HP-UX. Compiler = aCC" @echo "" @echo "Examples. If you don't know what to do, you likely want to run: " @echo "" @echo "make profile-build ARCH=x86-64 (This is for 64-bit systems)" @echo "make profile-build ARCH=x86-32 (This is for 32-bit systems)" @echo "" build: $(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity $(MAKE) ARCH=$(ARCH) COMP=$(COMP) all profile-build: $(MAKE) ARCH=$(ARCH) COMP=$(COMP) config-sanity @echo "" @echo "Step 0/4. Preparing for profile build." $(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_prepare) @echo "" @echo "Step 1/4. Building executable for benchmark ..." @touch *.cpp *.h $(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_make) @echo "" @echo "Step 2/4. Running benchmark for pgo-build ..." @$(PGOBENCH) > /dev/null @echo "" @echo "Step 3/4. Building final executable ..." @touch *.cpp $(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_use) @echo "" @echo "Step 4/4. Deleting profile data ..." $(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_clean) strip: strip $(EXE) install: -mkdir -p -m 755 $(BINDIR) -cp $(EXE) $(BINDIR) -strip $(BINDIR)/$(EXE) clean: $(RM) $(EXE) $(EXE).exe *.o .depend *~ core bench.txt *.gcda testrun: @$(PGOBENCH) default: help ### ========================================================================== ### Section 5. Private targets ### ========================================================================== all: $(EXE) .depend config-sanity: @echo "" @echo "Config:" @echo "debug: '$(debug)'" @echo "optimize: '$(optimize)'" @echo "arch: '$(arch)'" @echo "os: '$(os)'" @echo "bits: '$(bits)'" @echo "prefetch: '$(prefetch)'" @echo "bsfq: '$(bsfq)'" @echo "popcnt: '$(popcnt)'" @echo "sse: '$(sse)'" @echo "" @echo "Flags:" @echo "CXX: $(CXX)" @echo "CXXFLAGS: $(CXXFLAGS)" @echo "LDFLAGS: $(LDFLAGS)" @echo "" @echo "Testing config sanity. If this fails, try 'make help' ..." @echo "" @test "$(debug)" = "yes" || test "$(debug)" = "no" @test "$(optimize)" = "yes" || test "$(optimize)" = "no" @test "$(arch)" = "any" || test "$(arch)" = "x86_64" || test "$(arch)" = "i386" || \ test "$(arch)" = "ppc64" || test "$(arch)" = "ppc" || test "$(arch)" = "armv7" @test "$(os)" = "any" || test "$(os)" = "osx" @test "$(bits)" = "32" || test "$(bits)" = "64" @test "$(prefetch)" = "yes" || test "$(prefetch)" = "no" @test "$(bsfq)" = "yes" || test "$(bsfq)" = "no" @test "$(popcnt)" = "yes" || test "$(popcnt)" = "no" @test "$(sse)" = "yes" || test "$(sse)" = "no" @test "$(comp)" = "gcc" || test "$(comp)" = "icc" || test "$(comp)" = "mingw" || test "$(comp)" = "clang" $(EXE): $(OBJS) $(CXX) -o $@ $(OBJS) $(LDFLAGS) gcc-profile-prepare: $(MAKE) ARCH=$(ARCH) COMP=$(COMP) gcc-profile-clean gcc-profile-make: $(MAKE) ARCH=$(ARCH) COMP=$(COMP) \ EXTRACXXFLAGS='-fprofile-generate' \ EXTRALDFLAGS='-lgcov' \ all gcc-profile-use: $(MAKE) ARCH=$(ARCH) COMP=$(COMP) \ EXTRACXXFLAGS='-fprofile-use' \ EXTRALDFLAGS='-lgcov' \ all gcc-profile-clean: @rm -rf *.gcda *.gcno bench.txt icc-profile-prepare: $(MAKE) ARCH=$(ARCH) COMP=$(COMP) icc-profile-clean @mkdir profdir icc-profile-make: $(MAKE) ARCH=$(ARCH) COMP=$(COMP) \ EXTRACXXFLAGS='-prof-gen=srcpos -prof_dir ./profdir' \ all icc-profile-use: $(MAKE) ARCH=$(ARCH) COMP=$(COMP) \ EXTRACXXFLAGS='-prof_use -prof_dir ./profdir' \ all icc-profile-clean: @rm -rf profdir bench.txt .depend: -@$(CXX) $(DEPENDFLAGS) -MM $(OBJS:.o=.cpp) > $@ 2> /dev/null -include .depend ### ========================================================================== ### Section 6. Non-standard targets ### ========================================================================== hpux: $(MAKE) \ CXX='/opt/aCC/bin/aCC -AA +hpxstd98 -mt +O3 -DNDEBUG -DNO_PREFETCH' \ CXXFLAGS="" \ LDFLAGS="" \ all stockfish-3.0.0+git20130508/src/material.h0000644000175000017500000000564712142540127017243 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #if !defined(MATERIAL_H_INCLUDED) #define MATERIAL_H_INCLUDED #include "endgame.h" #include "misc.h" #include "position.h" #include "types.h" namespace Material { /// Material::Entry contains various information about a material configuration. /// It contains a material balance evaluation, a function pointer to a special /// endgame evaluation function (which in most cases is NULL, meaning that the /// standard evaluation function will be used), and "scale factors". /// /// The scale factors are used to scale the evaluation score up or down. /// For instance, in KRB vs KR endgames, the score is scaled down by a factor /// of 4, which will result in scores of absolute value less than one pawn. struct Entry { Score material_value() const { return make_score(value, value); } int space_weight() const { return spaceWeight; } Phase game_phase() const { return gamePhase; } bool specialized_eval_exists() const { return evaluationFunction != NULL; } Value evaluate(const Position& p) const { return (*evaluationFunction)(p); } ScaleFactor scale_factor(const Position& pos, Color c) const; Key key; int16_t value; uint8_t factor[COLOR_NB]; EndgameBase* evaluationFunction; EndgameBase* scalingFunction[COLOR_NB]; int spaceWeight; Phase gamePhase; }; typedef HashTable Table; Entry* probe(const Position& pos, Table& entries, Endgames& endgames); Phase game_phase(const Position& pos); /// Material::scale_factor takes a position and a color as input, and /// returns a scale factor for the given color. We have to provide the /// position in addition to the color, because the scale factor need not /// to be a constant: It can also be a function which should be applied to /// the position. For instance, in KBP vs K endgames, a scaling function /// which checks for draws with rook pawns and wrong-colored bishops. inline ScaleFactor Entry::scale_factor(const Position& pos, Color c) const { return !scalingFunction[c] || (*scalingFunction[c])(pos) == SCALE_FACTOR_NONE ? ScaleFactor(factor[c]) : (*scalingFunction[c])(pos); } } #endif // !defined(MATERIAL_H_INCLUDED) stockfish-3.0.0+git20130508/src/rkiss.h0000644000175000017500000000470412142540127016571 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . This file is based on original code by Heinz van Saanen and is available under 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. */ #if !defined(RKISS_H_INCLUDED) #define RKISS_H_INCLUDED #include "types.h" /// RKISS is our pseudo random number generator (PRNG) used to compute hash keys. /// George Marsaglia invented the RNG-Kiss-family in the early 90's. This is a /// specific version that Heinz van Saanen derived from some public domain code /// by Bob Jenkins. Following the feature list, as tested by Heinz. /// /// - Quite platform independent /// - Passes ALL dieharder tests! Here *nix sys-rand() e.g. fails miserably:-) /// - ~12 times faster than my *nix sys-rand() /// - ~4 times faster than SSE2-version of Mersenne twister /// - Average cycle length: ~2^126 /// - 64 bit seed /// - Return doubles with a full 53 bit mantissa /// - Thread safe class RKISS { // Keep variables always together struct S { uint64_t a, b, c, d; } s; uint64_t rotate(uint64_t x, uint64_t k) const { return (x << k) | (x >> (64 - k)); } // Return 64 bit unsigned integer in between [0, 2^64 - 1] uint64_t rand64() { const uint64_t e = s.a - rotate(s.b, 7); s.a = s.b ^ rotate(s.c, 13); s.b = s.c + rotate(s.d, 37); s.c = s.d + e; return s.d = e + s.a; } public: RKISS(int seed = 73) { s.a = 0xf1ea5eed; s.b = s.c = s.d = 0xd4e12c77; for (int i = 0; i < seed; i++) // Scramble a few rounds rand64(); } template T rand() { return T(rand64()); } }; #endif // !defined(RKISS_H_INCLUDED) stockfish-3.0.0+git20130508/src/benchmark.cpp0000644000175000017500000001145412142540127017723 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include "misc.h" #include "position.h" #include "search.h" #include "thread.h" #include "tt.h" #include "ucioption.h" using namespace std; static const char* Defaults[] = { "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 10", "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 11", "4rrk1/pp1n3p/3q2pQ/2p1pb2/2PP4/2P3N1/P2B2PP/4RRK1 b - - 7 19", "rq3rk1/ppp2ppp/1bnpb3/3N2B1/3NP3/7P/PPPQ1PP1/2KR3R w - - 7 14", "r1bq1r1k/1pp1n1pp/1p1p4/4p2Q/4Pp2/1BNP4/PPP2PPP/3R1RK1 w - - 2 14", "r3r1k1/2p2ppp/p1p1bn2/8/1q2P3/2NPQN2/PPP3PP/R4RK1 b - - 2 15", "r1bbk1nr/pp3p1p/2n5/1N4p1/2Np1B2/8/PPP2PPP/2KR1B1R w kq - 0 13", "r1bq1rk1/ppp1nppp/4n3/3p3Q/3P4/1BP1B3/PP1N2PP/R4RK1 w - - 1 16", "4r1k1/r1q2ppp/ppp2n2/4P3/5Rb1/1N1BQ3/PPP3PP/R5K1 w - - 1 17", "2rqkb1r/ppp2p2/2npb1p1/1N1Nn2p/2P1PP2/8/PP2B1PP/R1BQK2R b KQ - 0 11", "r1bq1r1k/b1p1npp1/p2p3p/1p6/3PP3/1B2NN2/PP3PPP/R2Q1RK1 w - - 1 16", "3r1rk1/p5pp/bpp1pp2/8/q1PP1P2/b3P3/P2NQRPP/1R2B1K1 b - - 6 22", "r1q2rk1/2p1bppp/2Pp4/p6b/Q1PNp3/4B3/PP1R1PPP/2K4R w - - 2 18", "4k2r/1pb2ppp/1p2p3/1R1p4/3P4/2r1PN2/P4PPP/1R4K1 b - - 3 22", "3q2k1/pb3p1p/4pbp1/2r5/PpN2N2/1P2P2P/5PP1/Q2R2K1 b - - 4 26" }; /// benchmark() runs a simple benchmark by letting Stockfish analyze a set /// of positions for a given limit each. There are five parameters; the /// transposition table size, the number of search threads that should /// be used, the limit value spent for each position (optional, default is /// depth 12), an optional file name where to look for positions in fen /// format (defaults are the positions defined above) and the type of the /// limit value: depth (default), time in secs or number of nodes. void benchmark(const Position& current, istream& is) { string token; Search::LimitsType limits; vector fens; // Assign default values to missing arguments string ttSize = (is >> token) ? token : "32"; string threads = (is >> token) ? token : "1"; string limit = (is >> token) ? token : "12"; string fenFile = (is >> token) ? token : "default"; string limitType = (is >> token) ? token : "depth"; Options["Hash"] = ttSize; Options["Threads"] = threads; TT.clear(); if (limitType == "time") limits.movetime = 1000 * atoi(limit.c_str()); // movetime is in ms else if (limitType == "nodes") limits.nodes = atoi(limit.c_str()); else if (limitType == "mate") limits.mate = atoi(limit.c_str()); else limits.depth = atoi(limit.c_str()); if (fenFile == "default") fens.assign(Defaults, Defaults + 16); else if (fenFile == "current") fens.push_back(current.fen()); else { string fen; ifstream file(fenFile.c_str()); if (!file.is_open()) { cerr << "Unable to open file " << fenFile << endl; return; } while (getline(file, fen)) if (!fen.empty()) fens.push_back(fen); file.close(); } int64_t nodes = 0; Search::StateStackPtr st; Time::point elapsed = Time::now(); for (size_t i = 0; i < fens.size(); i++) { Position pos(fens[i], Options["UCI_Chess960"], Threads.main_thread()); cerr << "\nPosition: " << i + 1 << '/' << fens.size() << endl; if (limitType == "perft") { size_t cnt = Search::perft(pos, limits.depth * ONE_PLY); cerr << "\nPerft " << limits.depth << " leaf nodes: " << cnt << endl; nodes += cnt; } else { Threads.start_thinking(pos, limits, vector(), st); Threads.wait_for_think_finished(); nodes += Search::RootPos.nodes_searched(); } } elapsed = Time::now() - elapsed + 1; // Assure positive to avoid a 'divide by zero' cerr << "\n===========================" << "\nTotal time (ms) : " << elapsed << "\nNodes searched : " << nodes << "\nNodes/second : " << 1000 * nodes / elapsed << endl; } stockfish-3.0.0+git20130508/src/types.h0000644000175000017500000003257312142540127016607 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #if !defined(TYPES_H_INCLUDED) #define TYPES_H_INCLUDED /// For Linux and OSX configuration is done automatically using Makefile. To get /// started type 'make help'. /// /// For Windows, part of the configuration is detected automatically, but some /// switches need to be set manually: /// /// -DNDEBUG | Disable debugging mode. Use always. /// /// -DNO_PREFETCH | Disable use of prefetch asm-instruction. A must if you want /// | the executable to run on some very old machines. /// /// -DUSE_POPCNT | Add runtime support for use of popcnt asm-instruction. Works /// | only in 64-bit mode. For compiling requires hardware with /// | popcnt support. #include #include #include #include #include "platform.h" #if defined(_WIN64) && !defined(IS_64BIT) # include // MSVC popcnt and bsfq instrinsics # define IS_64BIT # define USE_BSFQ #endif #if defined(USE_POPCNT) && defined(_MSC_VER) && defined(__INTEL_COMPILER) # include // Intel header for _mm_popcnt_u64() intrinsic #endif # if !defined(NO_PREFETCH) && (defined(__INTEL_COMPILER) || defined(_MSC_VER)) # include // Intel and Microsoft header for _mm_prefetch() # endif #define CACHE_LINE_SIZE 64 #if defined(_MSC_VER) || defined(__INTEL_COMPILER) # define CACHE_LINE_ALIGNMENT __declspec(align(CACHE_LINE_SIZE)) #else # define CACHE_LINE_ALIGNMENT __attribute__ ((aligned(CACHE_LINE_SIZE))) #endif #if defined(_MSC_VER) # define FORCE_INLINE __forceinline #elif defined(__GNUC__) # define FORCE_INLINE inline __attribute__((always_inline)) #else # define FORCE_INLINE inline #endif #if defined(USE_POPCNT) const bool HasPopCnt = true; #else const bool HasPopCnt = false; #endif #if defined(IS_64BIT) const bool Is64Bit = true; #else const bool Is64Bit = false; #endif typedef uint64_t Key; typedef uint64_t Bitboard; const int MAX_MOVES = 192; const int MAX_PLY = 100; const int MAX_PLY_PLUS_2 = MAX_PLY + 2; const Bitboard FileABB = 0x0101010101010101ULL; const Bitboard FileBBB = FileABB << 1; const Bitboard FileCBB = FileABB << 2; const Bitboard FileDBB = FileABB << 3; const Bitboard FileEBB = FileABB << 4; const Bitboard FileFBB = FileABB << 5; const Bitboard FileGBB = FileABB << 6; const Bitboard FileHBB = FileABB << 7; const Bitboard Rank1BB = 0xFF; const Bitboard Rank2BB = Rank1BB << (8 * 1); const Bitboard Rank3BB = Rank1BB << (8 * 2); const Bitboard Rank4BB = Rank1BB << (8 * 3); const Bitboard Rank5BB = Rank1BB << (8 * 4); const Bitboard Rank6BB = Rank1BB << (8 * 5); const Bitboard Rank7BB = Rank1BB << (8 * 6); const Bitboard Rank8BB = Rank1BB << (8 * 7); /// A move needs 16 bits to be stored /// /// bit 0- 5: destination square (from 0 to 63) /// bit 6-11: origin square (from 0 to 63) /// bit 12-13: promotion piece type - 2 (from KNIGHT-2 to QUEEN-2) /// bit 14-15: special move flag: promotion (1), en passant (2), castle (3) /// /// Special cases are MOVE_NONE and MOVE_NULL. We can sneak these in because in /// any normal move destination square is always different from origin square /// while MOVE_NONE and MOVE_NULL have the same origin and destination square. enum Move { MOVE_NONE = 0, MOVE_NULL = 65 }; enum MoveType { NORMAL = 0, PROMOTION = 1 << 14, ENPASSANT = 2 << 14, CASTLE = 3 << 14 }; enum CastleRight { // Defined as in PolyGlot book hash key CASTLES_NONE = 0, WHITE_OO = 1, WHITE_OOO = 2, BLACK_OO = 4, BLACK_OOO = 8, ALL_CASTLES = 15, CASTLE_RIGHT_NB = 16 }; enum CastlingSide { KING_SIDE, QUEEN_SIDE, CASTLING_SIDE_NB = 2 }; enum Phase { PHASE_ENDGAME = 0, PHASE_MIDGAME = 128, MG = 0, EG = 1, PHASE_NB = 2 }; enum ScaleFactor { SCALE_FACTOR_DRAW = 0, SCALE_FACTOR_NORMAL = 64, SCALE_FACTOR_MAX = 128, SCALE_FACTOR_NONE = 255 }; enum Bound { BOUND_NONE = 0, BOUND_UPPER = 1, BOUND_LOWER = 2, BOUND_EXACT = BOUND_UPPER | BOUND_LOWER }; enum Value { VALUE_ZERO = 0, VALUE_DRAW = 0, VALUE_KNOWN_WIN = 15000, VALUE_MATE = 30000, VALUE_INFINITE = 30001, VALUE_NONE = 30002, VALUE_MATE_IN_MAX_PLY = VALUE_MATE - MAX_PLY, VALUE_MATED_IN_MAX_PLY = -VALUE_MATE + MAX_PLY, VALUE_ENSURE_INTEGER_SIZE_P = INT_MAX, VALUE_ENSURE_INTEGER_SIZE_N = INT_MIN, PawnValueMg = 198, PawnValueEg = 258, KnightValueMg = 817, KnightValueEg = 846, BishopValueMg = 836, BishopValueEg = 857, RookValueMg = 1270, RookValueEg = 1278, QueenValueMg = 2521, QueenValueEg = 2558 }; enum PieceType { NO_PIECE_TYPE = 0, ALL_PIECES = 0, PAWN = 1, KNIGHT = 2, BISHOP = 3, ROOK = 4, QUEEN = 5, KING = 6, PIECE_TYPE_NB = 8 }; enum Piece { NO_PIECE = 0, W_PAWN = 1, W_KNIGHT = 2, W_BISHOP = 3, W_ROOK = 4, W_QUEEN = 5, W_KING = 6, B_PAWN = 9, B_KNIGHT = 10, B_BISHOP = 11, B_ROOK = 12, B_QUEEN = 13, B_KING = 14, PIECE_NB = 16 }; enum Color { WHITE, BLACK, NO_COLOR, COLOR_NB = 2 }; enum Depth { ONE_PLY = 2, DEPTH_ZERO = 0 * ONE_PLY, DEPTH_QS_CHECKS = -1 * ONE_PLY, DEPTH_QS_NO_CHECKS = -2 * ONE_PLY, DEPTH_QS_RECAPTURES = -5 * ONE_PLY, DEPTH_NONE = -127 * ONE_PLY }; enum Square { SQ_A1, SQ_B1, SQ_C1, SQ_D1, SQ_E1, SQ_F1, SQ_G1, SQ_H1, SQ_A2, SQ_B2, SQ_C2, SQ_D2, SQ_E2, SQ_F2, SQ_G2, SQ_H2, SQ_A3, SQ_B3, SQ_C3, SQ_D3, SQ_E3, SQ_F3, SQ_G3, SQ_H3, SQ_A4, SQ_B4, SQ_C4, SQ_D4, SQ_E4, SQ_F4, SQ_G4, SQ_H4, SQ_A5, SQ_B5, SQ_C5, SQ_D5, SQ_E5, SQ_F5, SQ_G5, SQ_H5, SQ_A6, SQ_B6, SQ_C6, SQ_D6, SQ_E6, SQ_F6, SQ_G6, SQ_H6, SQ_A7, SQ_B7, SQ_C7, SQ_D7, SQ_E7, SQ_F7, SQ_G7, SQ_H7, SQ_A8, SQ_B8, SQ_C8, SQ_D8, SQ_E8, SQ_F8, SQ_G8, SQ_H8, SQ_NONE, SQUARE_NB = 64, DELTA_N = 8, DELTA_E = 1, DELTA_S = -8, DELTA_W = -1, DELTA_NN = DELTA_N + DELTA_N, DELTA_NE = DELTA_N + DELTA_E, DELTA_SE = DELTA_S + DELTA_E, DELTA_SS = DELTA_S + DELTA_S, DELTA_SW = DELTA_S + DELTA_W, DELTA_NW = DELTA_N + DELTA_W }; enum File { FILE_A, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H, FILE_NB = 8 }; enum Rank { RANK_1, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8, RANK_NB = 8 }; /// Score enum keeps a midgame and an endgame value in a single integer (enum), /// first LSB 16 bits are used to store endgame value, while upper bits are used /// for midgame value. Compiler is free to choose the enum type as long as can /// keep its data, so ensure Score to be an integer type. enum Score { SCORE_ZERO = 0, SCORE_ENSURE_INTEGER_SIZE_P = INT_MAX, SCORE_ENSURE_INTEGER_SIZE_N = INT_MIN }; inline Score make_score(int mg, int eg) { return Score((mg << 16) + eg); } /// Extracting the signed lower and upper 16 bits it not so trivial because /// according to the standard a simple cast to short is implementation defined /// and so is a right shift of a signed integer. inline Value mg_value(Score s) { return Value(((s + 32768) & ~0xffff) / 0x10000); } /// On Intel 64 bit we have a small speed regression with the standard conforming /// version, so use a faster code in this case that, although not 100% standard /// compliant it seems to work for Intel and MSVC. #if defined(IS_64BIT) && (!defined(__GNUC__) || defined(__INTEL_COMPILER)) inline Value eg_value(Score s) { return Value(int16_t(s & 0xffff)); } #else inline Value eg_value(Score s) { return Value((int)(unsigned(s) & 0x7fffu) - (int)(unsigned(s) & 0x8000u)); } #endif #define ENABLE_SAFE_OPERATORS_ON(T) \ inline T operator+(const T d1, const T d2) { return T(int(d1) + int(d2)); } \ inline T operator-(const T d1, const T d2) { return T(int(d1) - int(d2)); } \ inline T operator*(int i, const T d) { return T(i * int(d)); } \ inline T operator*(const T d, int i) { return T(int(d) * i); } \ inline T operator-(const T d) { return T(-int(d)); } \ inline T& operator+=(T& d1, const T d2) { d1 = d1 + d2; return d1; } \ inline T& operator-=(T& d1, const T d2) { d1 = d1 - d2; return d1; } \ inline T& operator*=(T& d, int i) { d = T(int(d) * i); return d; } #define ENABLE_OPERATORS_ON(T) ENABLE_SAFE_OPERATORS_ON(T) \ inline T operator++(T& d, int) { d = T(int(d) + 1); return d; } \ inline T operator--(T& d, int) { d = T(int(d) - 1); return d; } \ inline T operator/(const T d, int i) { return T(int(d) / i); } \ inline T& operator/=(T& d, int i) { d = T(int(d) / i); return d; } ENABLE_OPERATORS_ON(Value) ENABLE_OPERATORS_ON(PieceType) ENABLE_OPERATORS_ON(Piece) ENABLE_OPERATORS_ON(Color) ENABLE_OPERATORS_ON(Depth) ENABLE_OPERATORS_ON(Square) ENABLE_OPERATORS_ON(File) ENABLE_OPERATORS_ON(Rank) /// Added operators for adding integers to a Value inline Value operator+(Value v, int i) { return Value(int(v) + i); } inline Value operator-(Value v, int i) { return Value(int(v) - i); } ENABLE_SAFE_OPERATORS_ON(Score) /// Only declared but not defined. We don't want to multiply two scores due to /// a very high risk of overflow. So user should explicitly convert to integer. inline Score operator*(Score s1, Score s2); /// Division of a Score must be handled separately for each term inline Score operator/(Score s, int i) { return make_score(mg_value(s) / i, eg_value(s) / i); } /// Weight score v by score w trying to prevent overflow inline Score apply_weight(Score v, Score w) { return make_score((int(mg_value(v)) * mg_value(w)) / 0x100, (int(eg_value(v)) * eg_value(w)) / 0x100); } #undef ENABLE_OPERATORS_ON #undef ENABLE_SAFE_OPERATORS_ON namespace Zobrist { extern Key psq[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB]; extern Key enpassant[FILE_NB]; extern Key castle[CASTLE_RIGHT_NB]; extern Key side; extern Key exclusion; void init(); } CACHE_LINE_ALIGNMENT extern Score pieceSquareTable[PIECE_NB][SQUARE_NB]; extern Value PieceValue[PHASE_NB][PIECE_NB]; extern int SquareDistance[SQUARE_NB][SQUARE_NB]; struct MoveStack { Move move; int score; }; inline bool operator<(const MoveStack& f, const MoveStack& s) { return f.score < s.score; } inline Color operator~(Color c) { return Color(c ^ 1); } inline Square operator~(Square s) { return Square(s ^ 56); // Vertical flip SQ_A1 -> SQ_A8 } inline Square operator|(File f, Rank r) { return Square((r << 3) | f); } inline Value mate_in(int ply) { return VALUE_MATE - ply; } inline Value mated_in(int ply) { return -VALUE_MATE + ply; } inline Piece make_piece(Color c, PieceType pt) { return Piece((c << 3) | pt); } inline CastleRight make_castle_right(Color c, CastlingSide s) { return CastleRight(WHITE_OO << ((s == QUEEN_SIDE) + 2 * c)); } inline PieceType type_of(Piece p) { return PieceType(p & 7); } inline Color color_of(Piece p) { assert(p != NO_PIECE); return Color(p >> 3); } inline bool is_ok(Square s) { return s >= SQ_A1 && s <= SQ_H8; } inline File file_of(Square s) { return File(s & 7); } inline Rank rank_of(Square s) { return Rank(s >> 3); } inline Square mirror(Square s) { return Square(s ^ 7); // Horizontal flip SQ_A1 -> SQ_H1 } inline Square relative_square(Color c, Square s) { return Square(s ^ (c * 56)); } inline Rank relative_rank(Color c, Rank r) { return Rank(r ^ (c * 7)); } inline Rank relative_rank(Color c, Square s) { return relative_rank(c, rank_of(s)); } inline bool opposite_colors(Square s1, Square s2) { int s = int(s1) ^ int(s2); return ((s >> 3) ^ s) & 1; } inline int file_distance(Square s1, Square s2) { return abs(file_of(s1) - file_of(s2)); } inline int rank_distance(Square s1, Square s2) { return abs(rank_of(s1) - rank_of(s2)); } inline int square_distance(Square s1, Square s2) { return SquareDistance[s1][s2]; } inline char file_to_char(File f, bool tolower = true) { return char(f - FILE_A + (tolower ? 'a' : 'A')); } inline char rank_to_char(Rank r) { return char(r - RANK_1 + '1'); } inline Square pawn_push(Color c) { return c == WHITE ? DELTA_N : DELTA_S; } inline Square from_sq(Move m) { return Square((m >> 6) & 0x3F); } inline Square to_sq(Move m) { return Square(m & 0x3F); } inline MoveType type_of(Move m) { return MoveType(m & (3 << 14)); } inline PieceType promotion_type(Move m) { return PieceType(((m >> 12) & 3) + 2); } inline Move make_move(Square from, Square to) { return Move(to | (from << 6)); } template inline Move make(Square from, Square to, PieceType pt = KNIGHT) { return Move(to | (from << 6) | T | ((pt - KNIGHT) << 12)); } inline bool is_ok(Move m) { return from_sq(m) != to_sq(m); // Catches also MOVE_NULL and MOVE_NONE } #include inline const std::string square_to_string(Square s) { char ch[] = { file_to_char(file_of(s)), rank_to_char(rank_of(s)), 0 }; return ch; } #endif // !defined(TYPES_H_INCLUDED) stockfish-3.0.0+git20130508/src/ucioption.h0000644000175000017500000000362112142540127017444 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #if !defined(UCIOPTION_H_INCLUDED) #define UCIOPTION_H_INCLUDED #include #include namespace UCI { class Option; /// Custom comparator because UCI options should be case insensitive struct CaseInsensitiveLess { bool operator() (const std::string&, const std::string&) const; }; /// Our options container is actually a std::map typedef std::map OptionsMap; /// Option class implements an option as defined by UCI protocol class Option { typedef void (Fn)(const Option&); public: Option(Fn* = NULL); Option(bool v, Fn* = NULL); Option(const char* v, Fn* = NULL); Option(int v, int min, int max, Fn* = NULL); Option& operator=(const std::string& v); operator int() const; operator std::string() const; private: friend std::ostream& operator<<(std::ostream&, const OptionsMap&); std::string defaultValue, currentValue, type; int min, max; size_t idx; Fn* on_change; }; void init(OptionsMap&); void loop(const std::string&); } // namespace UCI extern UCI::OptionsMap Options; #endif // !defined(UCIOPTION_H_INCLUDED) stockfish-3.0.0+git20130508/src/notation.cpp0000644000175000017500000001530112142540127017617 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include "movegen.h" #include "notation.h" #include "position.h" using namespace std; static const char* PieceToChar[COLOR_NB] = { " PNBRQK", " pnbrqk" }; /// score_to_uci() converts a value to a string suitable for use with the UCI /// protocol specifications: /// /// cp The score from the engine's point of view in centipawns. /// mate Mate in y moves, not plies. If the engine is getting mated /// use negative values for y. string score_to_uci(Value v, Value alpha, Value beta) { stringstream s; if (abs(v) < VALUE_MATE_IN_MAX_PLY) s << "cp " << v * 100 / int(PawnValueMg); else s << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2; s << (v >= beta ? " lowerbound" : v <= alpha ? " upperbound" : ""); return s.str(); } /// move_to_uci() converts a move to a string in coordinate notation /// (g1f3, a7a8q, etc.). The only special case is castling moves, where we print /// in the e1g1 notation in normal chess mode, and in e1h1 notation in chess960 /// mode. Internally castle moves are always coded as "king captures rook". const string move_to_uci(Move m, bool chess960) { Square from = from_sq(m); Square to = to_sq(m); if (m == MOVE_NONE) return "(none)"; if (m == MOVE_NULL) return "0000"; if (type_of(m) == CASTLE && !chess960) to = (to > from ? FILE_G : FILE_C) | rank_of(from); string move = square_to_string(from) + square_to_string(to); if (type_of(m) == PROMOTION) move += PieceToChar[BLACK][promotion_type(m)]; // Lower case return move; } /// move_from_uci() takes a position and a string representing a move in /// simple coordinate notation and returns an equivalent legal Move if any. Move move_from_uci(const Position& pos, string& str) { if (str.length() == 5) // Junior could send promotion piece in uppercase str[4] = char(tolower(str[4])); for (MoveList ml(pos); !ml.end(); ++ml) if (str == move_to_uci(ml.move(), pos.is_chess960())) return ml.move(); return MOVE_NONE; } /// move_to_san() takes a position and a legal Move as input and returns its /// short algebraic notation representation. const string move_to_san(Position& pos, Move m) { if (m == MOVE_NONE) return "(none)"; if (m == MOVE_NULL) return "(null)"; assert(MoveList(pos).contains(m)); Bitboard others, b; string san; Color us = pos.side_to_move(); Square from = from_sq(m); Square to = to_sq(m); Piece pc = pos.piece_on(from); PieceType pt = type_of(pc); if (type_of(m) == CASTLE) san = to > from ? "O-O" : "O-O-O"; else { if (pt != PAWN) { san = PieceToChar[WHITE][pt]; // Upper case // Disambiguation if we have more then one piece of type 'pt' that can // reach 'to' with a legal move. others = b = (pos.attacks_from(pc, to) & pos.pieces(us, pt)) ^ from; while (b) { Move move = make_move(pop_lsb(&b), to); if (!pos.pl_move_is_legal(move, pos.pinned_pieces())) others ^= from_sq(move); } if (others) { if (!(others & file_bb(from))) san += file_to_char(file_of(from)); else if (!(others & rank_bb(from))) san += rank_to_char(rank_of(from)); else san += square_to_string(from); } } else if (pos.is_capture(m)) san = file_to_char(file_of(from)); if (pos.is_capture(m)) san += 'x'; san += square_to_string(to); if (type_of(m) == PROMOTION) san += string("=") + PieceToChar[WHITE][promotion_type(m)]; } if (pos.move_gives_check(m, CheckInfo(pos))) { StateInfo st; pos.do_move(m, st); san += MoveList(pos).size() ? "+" : "#"; pos.undo_move(m); } return san; } /// pretty_pv() formats human-readable search information, typically to be /// appended to the search log file. It uses the two helpers below to pretty /// format time and score respectively. static string time_to_string(int64_t msecs) { const int MSecMinute = 1000 * 60; const int MSecHour = 1000 * 60 * 60; int64_t hours = msecs / MSecHour; int64_t minutes = (msecs % MSecHour) / MSecMinute; int64_t seconds = ((msecs % MSecHour) % MSecMinute) / 1000; stringstream s; if (hours) s << hours << ':'; s << setfill('0') << setw(2) << minutes << ':' << setw(2) << seconds; return s.str(); } static string score_to_string(Value v) { stringstream s; if (v >= VALUE_MATE_IN_MAX_PLY) s << "#" << (VALUE_MATE - v + 1) / 2; else if (v <= VALUE_MATED_IN_MAX_PLY) s << "-#" << (VALUE_MATE + v) / 2; else s << setprecision(2) << fixed << showpos << float(v) / PawnValueMg; return s.str(); } string pretty_pv(Position& pos, int depth, Value value, int64_t msecs, Move pv[]) { const int64_t K = 1000; const int64_t M = 1000000; std::stack st; Move* m = pv; string san, padding; size_t length; stringstream s; s << setw(2) << depth << setw(8) << score_to_string(value) << setw(8) << time_to_string(msecs); if (pos.nodes_searched() < M) s << setw(8) << pos.nodes_searched() / 1 << " "; else if (pos.nodes_searched() < K * M) s << setw(7) << pos.nodes_searched() / K << "K "; else s << setw(7) << pos.nodes_searched() / M << "M "; padding = string(s.str().length(), ' '); length = padding.length(); while (*m != MOVE_NONE) { san = move_to_san(pos, *m); if (length + san.length() > 80) { s << "\n" + padding; length = padding.length(); } s << san << ' '; length += san.length() + 1; st.push(StateInfo()); pos.do_move(*m++, st.top()); } while (m != pv) pos.undo_move(*--m); return s.str(); } stockfish-3.0.0+git20130508/src/evaluate.h0000644000175000017500000000213212142540127017235 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #if !defined(EVALUATE_H_INCLUDED) #define EVALUATE_H_INCLUDED #include "types.h" class Position; namespace Eval { extern void init(); extern Value evaluate(const Position& pos, Value& margin); extern std::string trace(const Position& pos); } #endif // !defined(EVALUATE_H_INCLUDED) stockfish-3.0.0+git20130508/src/search.cpp0000644000175000017500000017573712142540127017255 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include "book.h" #include "evaluate.h" #include "movegen.h" #include "movepick.h" #include "notation.h" #include "search.h" #include "timeman.h" #include "thread.h" #include "tt.h" #include "ucioption.h" namespace Search { volatile SignalsType Signals; LimitsType Limits; std::vector RootMoves; Position RootPos; Color RootColor; Time::point SearchTime; StateStackPtr SetupStates; } using std::string; using Eval::evaluate; using namespace Search; namespace { // Set to true to force running with one thread. Used for debugging const bool FakeSplit = false; // This is the minimum interval in msec between two check_time() calls const int TimerResolution = 5; // Different node types, used as template parameter enum NodeType { Root, PV, NonPV, SplitPointRoot, SplitPointPV, SplitPointNonPV }; // Dynamic razoring margin based on depth inline Value razor_margin(Depth d) { return Value(512 + 16 * int(d)); } // Futility lookup tables (initialized at startup) and their access functions Value FutilityMargins[16][64]; // [depth][moveNumber] int FutilityMoveCounts[32]; // [depth] inline Value futility_margin(Depth d, int mn) { return d < 7 * ONE_PLY ? FutilityMargins[std::max(int(d), 1)][std::min(mn, 63)] : 2 * VALUE_INFINITE; } // Reduction lookup tables (initialized at startup) and their access function int8_t Reductions[2][64][64]; // [pv][depth][moveNumber] template inline Depth reduction(Depth d, int mn) { return (Depth) Reductions[PvNode][std::min(int(d) / ONE_PLY, 63)][std::min(mn, 63)]; } size_t PVSize, PVIdx; TimeManager TimeMgr; int BestMoveChanges; Value DrawValue[COLOR_NB]; History Hist; Gains Gain; template Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth); template Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth); void id_loop(Position& pos); Value value_to_tt(Value v, int ply); Value value_from_tt(Value v, int ply); bool check_is_dangerous(const Position& pos, Move move, Value futilityBase, Value beta); bool allows(const Position& pos, Move first, Move second); bool refutes(const Position& pos, Move first, Move second); string uci_pv(const Position& pos, int depth, Value alpha, Value beta); struct Skill { Skill(int l) : level(l), best(MOVE_NONE) {} ~Skill() { if (enabled()) // Swap best PV line with the sub-optimal one std::swap(RootMoves[0], *std::find(RootMoves.begin(), RootMoves.end(), best ? best : pick_move())); } bool enabled() const { return level < 20; } bool time_to_pick(int depth) const { return depth == 1 + level; } Move pick_move(); int level; Move best; }; } // namespace /// Search::init() is called during startup to initialize various lookup tables void Search::init() { int d; // depth (ONE_PLY == 2) int hd; // half depth (ONE_PLY == 1) int mc; // moveCount // Init reductions array for (hd = 1; hd < 64; hd++) for (mc = 1; mc < 64; mc++) { double pvRed = log(double(hd)) * log(double(mc)) / 3.0; double nonPVRed = 0.33 + log(double(hd)) * log(double(mc)) / 2.25; Reductions[1][hd][mc] = (int8_t) ( pvRed >= 1.0 ? floor( pvRed * int(ONE_PLY)) : 0); Reductions[0][hd][mc] = (int8_t) (nonPVRed >= 1.0 ? floor(nonPVRed * int(ONE_PLY)) : 0); } // Init futility margins array for (d = 1; d < 16; d++) for (mc = 0; mc < 64; mc++) FutilityMargins[d][mc] = Value(112 * int(log(double(d * d) / 2) / log(2.0) + 1.001) - 8 * mc + 45); // Init futility move count array for (d = 0; d < 32; d++) FutilityMoveCounts[d] = int(3.001 + 0.3 * pow(double(d), 1.8)); } /// Search::perft() is our utility to verify move generation. All the leaf nodes /// up to the given depth are generated and counted and the sum returned. size_t Search::perft(Position& pos, Depth depth) { // At the last ply just return the number of legal moves (leaf nodes) if (depth == ONE_PLY) return MoveList(pos).size(); StateInfo st; size_t cnt = 0; CheckInfo ci(pos); for (MoveList ml(pos); !ml.end(); ++ml) { pos.do_move(ml.move(), st, ci, pos.move_gives_check(ml.move(), ci)); cnt += perft(pos, depth - ONE_PLY); pos.undo_move(ml.move()); } return cnt; } /// Search::think() is the external interface to Stockfish's search, and is /// called by the main thread when the program receives the UCI 'go' command. It /// searches from RootPos and at the end prints the "bestmove" to output. void Search::think() { static PolyglotBook book; // Defined static to initialize the PRNG only once RootColor = RootPos.side_to_move(); TimeMgr.init(Limits, RootPos.game_ply(), RootColor); if (RootMoves.empty()) { RootMoves.push_back(MOVE_NONE); sync_cout << "info depth 0 score " << score_to_uci(RootPos.checkers() ? -VALUE_MATE : VALUE_DRAW) << sync_endl; goto finalize; } if (Options["OwnBook"] && !Limits.infinite && !Limits.mate) { Move bookMove = book.probe(RootPos, Options["Book File"], Options["Best Book Move"]); if (bookMove && std::count(RootMoves.begin(), RootMoves.end(), bookMove)) { std::swap(RootMoves[0], *std::find(RootMoves.begin(), RootMoves.end(), bookMove)); goto finalize; } } if (Options["Contempt Factor"] && !Options["UCI_AnalyseMode"]) { int cf = Options["Contempt Factor"] * PawnValueMg / 100; // From centipawns cf = cf * Material::game_phase(RootPos) / PHASE_MIDGAME; // Scale down with phase DrawValue[ RootColor] = VALUE_DRAW - Value(cf); DrawValue[~RootColor] = VALUE_DRAW + Value(cf); } else DrawValue[WHITE] = DrawValue[BLACK] = VALUE_DRAW; if (Options["Use Search Log"]) { Log log(Options["Search Log Filename"]); log << "\nSearching: " << RootPos.fen() << "\ninfinite: " << Limits.infinite << " ponder: " << Limits.ponder << " time: " << Limits.time[RootColor] << " increment: " << Limits.inc[RootColor] << " moves to go: " << Limits.movestogo << std::endl; } // Reset the threads, still sleeping: will be wake up at split time for (size_t i = 0; i < Threads.size(); i++) Threads[i]->maxPly = 0; Threads.sleepWhileIdle = Options["Use Sleeping Threads"]; // Set best timer interval to avoid lagging under time pressure. Timer is // used to check for remaining available thinking time. Threads.timer->msec = Limits.use_time_management() ? std::min(100, std::max(TimeMgr.available_time() / 16, TimerResolution)) : Limits.nodes ? 2 * TimerResolution : 100; Threads.timer->notify_one(); // Wake up the recurring timer id_loop(RootPos); // Let's start searching ! Threads.timer->msec = 0; // Stop the timer Threads.sleepWhileIdle = true; // Send idle threads to sleep if (Options["Use Search Log"]) { Time::point elapsed = Time::now() - SearchTime + 1; Log log(Options["Search Log Filename"]); log << "Nodes: " << RootPos.nodes_searched() << "\nNodes/second: " << RootPos.nodes_searched() * 1000 / elapsed << "\nBest move: " << move_to_san(RootPos, RootMoves[0].pv[0]); StateInfo st; RootPos.do_move(RootMoves[0].pv[0], st); log << "\nPonder move: " << move_to_san(RootPos, RootMoves[0].pv[1]) << std::endl; RootPos.undo_move(RootMoves[0].pv[0]); } finalize: // When search is stopped this info is not printed sync_cout << "info nodes " << RootPos.nodes_searched() << " time " << Time::now() - SearchTime + 1 << sync_endl; // When we reach max depth we arrive here even without Signals.stop is raised, // but if we are pondering or in infinite search, according to UCI protocol, // we shouldn't print the best move before the GUI sends a "stop" or "ponderhit" // command. We simply wait here until GUI sends one of those commands (that // raise Signals.stop). if (!Signals.stop && (Limits.ponder || Limits.infinite)) { Signals.stopOnPonderhit = true; RootPos.this_thread()->wait_for(Signals.stop); } // Best move could be MOVE_NONE when searching on a stalemate position sync_cout << "bestmove " << move_to_uci(RootMoves[0].pv[0], RootPos.is_chess960()) << " ponder " << move_to_uci(RootMoves[0].pv[1], RootPos.is_chess960()) << sync_endl; } namespace { // id_loop() is the main iterative deepening loop. It calls search() repeatedly // with increasing depth until the allocated thinking time has been consumed, // user stops the search, or the maximum search depth is reached. void id_loop(Position& pos) { Stack ss[MAX_PLY_PLUS_2]; int depth, prevBestMoveChanges; Value bestValue, alpha, beta, delta; memset(ss, 0, 4 * sizeof(Stack)); depth = BestMoveChanges = 0; bestValue = delta = -VALUE_INFINITE; ss->currentMove = MOVE_NULL; // Hack to skip update gains TT.new_search(); Hist.clear(); Gain.clear(); PVSize = Options["MultiPV"]; Skill skill(Options["Skill Level"]); // Do we have to play with skill handicap? In this case enable MultiPV search // that we will use behind the scenes to retrieve a set of possible moves. if (skill.enabled() && PVSize < 4) PVSize = 4; PVSize = std::min(PVSize, RootMoves.size()); // Iterative deepening loop until requested to stop or target depth reached while (++depth <= MAX_PLY && !Signals.stop && (!Limits.depth || depth <= Limits.depth)) { // Save last iteration's scores before first PV line is searched and all // the move scores but the (new) PV are set to -VALUE_INFINITE. for (size_t i = 0; i < RootMoves.size(); i++) RootMoves[i].prevScore = RootMoves[i].score; prevBestMoveChanges = BestMoveChanges; // Only sensible when PVSize == 1 BestMoveChanges = 0; // MultiPV loop. We perform a full root search for each PV line for (PVIdx = 0; PVIdx < PVSize; PVIdx++) { // Set aspiration window default width if (depth >= 5 && abs(RootMoves[PVIdx].prevScore) < VALUE_KNOWN_WIN) { delta = Value(16); alpha = RootMoves[PVIdx].prevScore - delta; beta = RootMoves[PVIdx].prevScore + delta; } else { alpha = -VALUE_INFINITE; beta = VALUE_INFINITE; } // Start with a small aspiration window and, in case of fail high/low, // research with bigger window until not failing high/low anymore. while (true) { // Search starts from ss+1 to allow referencing (ss-1). This is // needed by update gains and ss copy when splitting at Root. bestValue = search(pos, ss+1, alpha, beta, depth * ONE_PLY); // Bring to front the best move. It is critical that sorting is // done with a stable algorithm because all the values but the first // and eventually the new best one are set to -VALUE_INFINITE and // we want to keep the same order for all the moves but the new // PV that goes to the front. Note that in case of MultiPV search // the already searched PV lines are preserved. std::stable_sort(RootMoves.begin() + PVIdx, RootMoves.end()); // Write PV back to transposition table in case the relevant // entries have been overwritten during the search. for (size_t i = 0; i <= PVIdx; i++) RootMoves[i].insert_pv_in_tt(pos); // If search has been stopped return immediately. Sorting and // writing PV back to TT is safe becuase RootMoves is still // valid, although refers to previous iteration. if (Signals.stop) return; // In case of failing high/low increase aspiration window and // research, otherwise exit the loop. if (bestValue > alpha && bestValue < beta) break; // Give some update (without cluttering the UI) before to research if (Time::now() - SearchTime > 3000) sync_cout << uci_pv(pos, depth, alpha, beta) << sync_endl; if (abs(bestValue) >= VALUE_KNOWN_WIN) { alpha = -VALUE_INFINITE; beta = VALUE_INFINITE; } else if (bestValue >= beta) { beta += delta; delta += delta / 2; } else { Signals.failedLowAtRoot = true; Signals.stopOnPonderhit = false; alpha -= delta; delta += delta / 2; } assert(alpha >= -VALUE_INFINITE && beta <= VALUE_INFINITE); } // Sort the PV lines searched so far and update the GUI std::stable_sort(RootMoves.begin(), RootMoves.begin() + PVIdx + 1); if (PVIdx + 1 == PVSize || Time::now() - SearchTime > 3000) sync_cout << uci_pv(pos, depth, alpha, beta) << sync_endl; } // Do we need to pick now the sub-optimal best move ? if (skill.enabled() && skill.time_to_pick(depth)) skill.pick_move(); if (Options["Use Search Log"]) { Log log(Options["Search Log Filename"]); log << pretty_pv(pos, depth, bestValue, Time::now() - SearchTime, &RootMoves[0].pv[0]) << std::endl; } // Do we have found a "mate in x"? if ( Limits.mate && bestValue >= VALUE_MATE_IN_MAX_PLY && VALUE_MATE - bestValue <= 2 * Limits.mate) Signals.stop = true; // Do we have time for the next iteration? Can we stop searching now? if (Limits.use_time_management() && !Signals.stopOnPonderhit) { bool stop = false; // Local variable, not the volatile Signals.stop // Take in account some extra time if the best move has changed if (depth > 4 && depth < 50 && PVSize == 1) TimeMgr.pv_instability(BestMoveChanges, prevBestMoveChanges); // Stop search if most of available time is already consumed. We // probably don't have enough time to search the first move at the // next iteration anyway. if (Time::now() - SearchTime > (TimeMgr.available_time() * 62) / 100) stop = true; // Stop search early if one move seems to be much better than others if ( depth >= 12 && !stop && PVSize == 1 && bestValue > VALUE_MATED_IN_MAX_PLY && ( RootMoves.size() == 1 || Time::now() - SearchTime > (TimeMgr.available_time() * 20) / 100)) { Value rBeta = bestValue - 2 * PawnValueMg; (ss+1)->excludedMove = RootMoves[0].pv[0]; (ss+1)->skipNullMove = true; Value v = search(pos, ss+1, rBeta - 1, rBeta, (depth - 3) * ONE_PLY); (ss+1)->skipNullMove = false; (ss+1)->excludedMove = MOVE_NONE; if (v < rBeta) stop = true; } if (stop) { // If we are allowed to ponder do not stop the search now but // keep pondering until GUI sends "ponderhit" or "stop". if (Limits.ponder) Signals.stopOnPonderhit = true; else Signals.stop = true; } } } } // search<>() is the main search function for both PV and non-PV nodes and for // normal and SplitPoint nodes. When called just after a split point the search // is simpler because we have already probed the hash table, done a null move // search, and searched the first move before splitting, we don't have to repeat // all this work again. We also don't need to store anything to the hash table // here: This is taken care of after we return from the split point. template Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth) { const bool PvNode = (NT == PV || NT == Root || NT == SplitPointPV || NT == SplitPointRoot); const bool SpNode = (NT == SplitPointPV || NT == SplitPointNonPV || NT == SplitPointRoot); const bool RootNode = (NT == Root || NT == SplitPointRoot); assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE); assert(PvNode || (alpha == beta - 1)); assert(depth > DEPTH_ZERO); Move movesSearched[64]; StateInfo st; const TTEntry *tte; SplitPoint* splitPoint; Key posKey; Move ttMove, move, excludedMove, bestMove, threatMove; Depth ext, newDepth; Value bestValue, value, ttValue; Value eval, nullValue, futilityValue; bool inCheck, givesCheck, pvMove, singularExtensionNode; bool captureOrPromotion, dangerous, doFullDepthSearch; int moveCount, playedMoveCount; // Step 1. Initialize node Thread* thisThread = pos.this_thread(); moveCount = playedMoveCount = 0; inCheck = pos.checkers(); if (SpNode) { splitPoint = ss->splitPoint; bestMove = splitPoint->bestMove; threatMove = splitPoint->threatMove; bestValue = splitPoint->bestValue; tte = NULL; ttMove = excludedMove = MOVE_NONE; ttValue = VALUE_NONE; assert(splitPoint->bestValue > -VALUE_INFINITE && splitPoint->moveCount > 0); goto split_point_start; } bestValue = -VALUE_INFINITE; ss->currentMove = threatMove = (ss+1)->excludedMove = bestMove = MOVE_NONE; ss->ply = (ss-1)->ply + 1; ss->futilityMoveCount = 0; (ss+1)->skipNullMove = false; (ss+1)->reduction = DEPTH_ZERO; (ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE; // Used to send selDepth info to GUI if (PvNode && thisThread->maxPly < ss->ply) thisThread->maxPly = ss->ply; if (!RootNode) { // Step 2. Check for aborted search and immediate draw if (Signals.stop || pos.is_draw() || ss->ply > MAX_PLY) return DrawValue[pos.side_to_move()]; // Step 3. Mate distance pruning. Even if we mate at the next move our score // would be at best mate_in(ss->ply+1), but if alpha is already bigger because // a shorter mate was found upward in the tree then there is no need to search // further, we will never beat current alpha. Same logic but with reversed signs // applies also in the opposite condition of being mated instead of giving mate, // in this case return a fail-high score. alpha = std::max(mated_in(ss->ply), alpha); beta = std::min(mate_in(ss->ply+1), beta); if (alpha >= beta) return alpha; } // Step 4. Transposition table lookup // We don't want the score of a partial search to overwrite a previous full search // TT value, so we use a different position key in case of an excluded move. excludedMove = ss->excludedMove; posKey = excludedMove ? pos.exclusion_key() : pos.key(); tte = TT.probe(posKey); ttMove = RootNode ? RootMoves[PVIdx].pv[0] : tte ? tte->move() : MOVE_NONE; ttValue = tte ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE; // At PV nodes we check for exact scores, while at non-PV nodes we check for // a fail high/low. Biggest advantage at probing at PV nodes is to have a // smooth experience in analysis mode. We don't probe at Root nodes otherwise // we should also update RootMoveList to avoid bogus output. if ( !RootNode && tte && tte->depth() >= depth && ttValue != VALUE_NONE // Only in case of TT access race && ( PvNode ? tte->type() == BOUND_EXACT : ttValue >= beta ? (tte->type() & BOUND_LOWER) : (tte->type() & BOUND_UPPER))) { TT.refresh(tte); ss->currentMove = ttMove; // Can be MOVE_NONE if ( ttValue >= beta && ttMove && !pos.is_capture_or_promotion(ttMove) && ttMove != ss->killers[0]) { ss->killers[1] = ss->killers[0]; ss->killers[0] = ttMove; } return ttValue; } // Step 5. Evaluate the position statically and update parent's gain statistics if (inCheck) ss->staticEval = ss->evalMargin = eval = VALUE_NONE; else if (tte) { // Never assume anything on values stored in TT if ( (ss->staticEval = eval = tte->eval_value()) == VALUE_NONE ||(ss->evalMargin = tte->eval_margin()) == VALUE_NONE) eval = ss->staticEval = evaluate(pos, ss->evalMargin); // Can ttValue be used as a better position evaluation? if (ttValue != VALUE_NONE) if ( ((tte->type() & BOUND_LOWER) && ttValue > eval) || ((tte->type() & BOUND_UPPER) && ttValue < eval)) eval = ttValue; } else { eval = ss->staticEval = evaluate(pos, ss->evalMargin); TT.store(posKey, VALUE_NONE, BOUND_NONE, DEPTH_NONE, MOVE_NONE, ss->staticEval, ss->evalMargin); } // Update gain for the parent non-capture move given the static position // evaluation before and after the move. if ( (move = (ss-1)->currentMove) != MOVE_NULL && (ss-1)->staticEval != VALUE_NONE && ss->staticEval != VALUE_NONE && !pos.captured_piece_type() && type_of(move) == NORMAL) { Square to = to_sq(move); Gain.update(pos.piece_on(to), to, -(ss-1)->staticEval - ss->staticEval); } // Step 6. Razoring (is omitted in PV nodes) if ( !PvNode && depth < 4 * ONE_PLY && !inCheck && eval + razor_margin(depth) < beta && ttMove == MOVE_NONE && abs(beta) < VALUE_MATE_IN_MAX_PLY && !pos.pawn_on_7th(pos.side_to_move())) { Value rbeta = beta - razor_margin(depth); Value v = qsearch(pos, ss, rbeta-1, rbeta, DEPTH_ZERO); if (v < rbeta) // Logically we should return (v + razor_margin(depth)), but // surprisingly this did slightly weaker in tests. return v; } // Step 7. Static null move pruning (is omitted in PV nodes) // We're betting that the opponent doesn't have a move that will reduce // the score by more than futility_margin(depth) if we do a null move. if ( !PvNode && !ss->skipNullMove && depth < 4 * ONE_PLY && !inCheck && eval - futility_margin(depth, (ss-1)->futilityMoveCount) >= beta && abs(beta) < VALUE_MATE_IN_MAX_PLY && abs(eval) < VALUE_KNOWN_WIN && pos.non_pawn_material(pos.side_to_move())) return eval - futility_margin(depth, (ss-1)->futilityMoveCount); // Step 8. Null move search with verification search (is omitted in PV nodes) if ( !PvNode && !ss->skipNullMove && depth > ONE_PLY && !inCheck && eval >= beta && abs(beta) < VALUE_MATE_IN_MAX_PLY && pos.non_pawn_material(pos.side_to_move())) { ss->currentMove = MOVE_NULL; // Null move dynamic reduction based on depth Depth R = 3 * ONE_PLY + depth / 4; // Null move dynamic reduction based on value if (eval - PawnValueMg > beta) R += ONE_PLY; pos.do_null_move(st); (ss+1)->skipNullMove = true; nullValue = depth-R < ONE_PLY ? -qsearch(pos, ss+1, -beta, -alpha, DEPTH_ZERO) : - search(pos, ss+1, -beta, -alpha, depth-R); (ss+1)->skipNullMove = false; pos.undo_null_move(); if (nullValue >= beta) { // Do not return unproven mate scores if (nullValue >= VALUE_MATE_IN_MAX_PLY) nullValue = beta; if (depth < 12 * ONE_PLY) return nullValue; // Do verification search at high depths ss->skipNullMove = true; Value v = search(pos, ss, alpha, beta, depth-R); ss->skipNullMove = false; if (v >= beta) return nullValue; } else { // The null move failed low, which means that we may be faced with // some kind of threat. If the previous move was reduced, check if // the move that refuted the null move was somehow connected to the // move which was reduced. If a connection is found, return a fail // low score (which will cause the reduced move to fail high in the // parent node, which will trigger a re-search with full depth). threatMove = (ss+1)->currentMove; if ( depth < 5 * ONE_PLY && (ss-1)->reduction && threatMove != MOVE_NONE && allows(pos, (ss-1)->currentMove, threatMove)) return beta - 1; } } // Step 9. ProbCut (is omitted in PV nodes) // If we have a very good capture (i.e. SEE > seeValues[captured_piece_type]) // and a reduced search returns a value much above beta, we can (almost) safely // prune the previous move. if ( !PvNode && depth >= 5 * ONE_PLY && !inCheck && !ss->skipNullMove && excludedMove == MOVE_NONE && abs(beta) < VALUE_MATE_IN_MAX_PLY) { Value rbeta = beta + 200; Depth rdepth = depth - ONE_PLY - 3 * ONE_PLY; assert(rdepth >= ONE_PLY); assert((ss-1)->currentMove != MOVE_NONE); assert((ss-1)->currentMove != MOVE_NULL); MovePicker mp(pos, ttMove, Hist, pos.captured_piece_type()); CheckInfo ci(pos); while ((move = mp.next_move()) != MOVE_NONE) if (pos.pl_move_is_legal(move, ci.pinned)) { ss->currentMove = move; pos.do_move(move, st, ci, pos.move_gives_check(move, ci)); value = -search(pos, ss+1, -rbeta, -rbeta+1, rdepth); pos.undo_move(move); if (value >= rbeta) return value; } } // Step 10. Internal iterative deepening if ( depth >= (PvNode ? 5 * ONE_PLY : 8 * ONE_PLY) && ttMove == MOVE_NONE && (PvNode || (!inCheck && ss->staticEval + Value(256) >= beta))) { Depth d = depth - 2 * ONE_PLY - (PvNode ? DEPTH_ZERO : depth / 4); ss->skipNullMove = true; search(pos, ss, alpha, beta, d); ss->skipNullMove = false; tte = TT.probe(posKey); ttMove = tte ? tte->move() : MOVE_NONE; } split_point_start: // At split points actual search starts from here MovePicker mp(pos, ttMove, depth, Hist, ss, PvNode ? -VALUE_INFINITE : beta); CheckInfo ci(pos); value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc singularExtensionNode = !RootNode && !SpNode && depth >= (PvNode ? 6 * ONE_PLY : 8 * ONE_PLY) && ttMove != MOVE_NONE && !excludedMove // Recursive singular search is not allowed && (tte->type() & BOUND_LOWER) && tte->depth() >= depth - 3 * ONE_PLY; // Step 11. Loop through moves // Loop through all pseudo-legal moves until no moves remain or a beta cutoff occurs while ((move = mp.next_move()) != MOVE_NONE) { assert(is_ok(move)); if (move == excludedMove) continue; // At root obey the "searchmoves" option and skip moves not listed in Root // Move List, as a consequence any illegal move is also skipped. In MultiPV // mode we also skip PV moves which have been already searched. if (RootNode && !std::count(RootMoves.begin() + PVIdx, RootMoves.end(), move)) continue; if (SpNode) { // Shared counter cannot be decremented later if move turns out to be illegal if (!pos.pl_move_is_legal(move, ci.pinned)) continue; moveCount = ++splitPoint->moveCount; splitPoint->mutex.unlock(); } else moveCount++; if (RootNode) { Signals.firstRootMove = (moveCount == 1); if (thisThread == Threads.main_thread() && Time::now() - SearchTime > 3000) sync_cout << "info depth " << depth / ONE_PLY << " currmove " << move_to_uci(move, pos.is_chess960()) << " currmovenumber " << moveCount + PVIdx << sync_endl; } ext = DEPTH_ZERO; captureOrPromotion = pos.is_capture_or_promotion(move); givesCheck = pos.move_gives_check(move, ci); dangerous = givesCheck || pos.is_passed_pawn_push(move) || type_of(move) == CASTLE || ( captureOrPromotion // Entering a pawn endgame? && type_of(pos.piece_on(to_sq(move))) != PAWN && type_of(move) == NORMAL && ( pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK) - PieceValue[MG][pos.piece_on(to_sq(move))] == VALUE_ZERO)); // Step 12. Extend checks and, in PV nodes, also dangerous moves if (PvNode && dangerous) ext = ONE_PLY; else if (givesCheck && pos.see_sign(move) >= 0) ext = ONE_PLY / 2; // Singular extension search. If all moves but one fail low on a search of // (alpha-s, beta-s), and just one fails high on (alpha, beta), then that move // is singular and should be extended. To verify this we do a reduced search // on all the other moves but the ttMove, if result is lower than ttValue minus // a margin then we extend ttMove. if ( singularExtensionNode && move == ttMove && !ext && pos.pl_move_is_legal(move, ci.pinned) && abs(ttValue) < VALUE_KNOWN_WIN) { assert(ttValue != VALUE_NONE); Value rBeta = ttValue - int(depth); ss->excludedMove = move; ss->skipNullMove = true; value = search(pos, ss, rBeta - 1, rBeta, depth / 2); ss->skipNullMove = false; ss->excludedMove = MOVE_NONE; if (value < rBeta) ext = ONE_PLY; } // Update current move (this must be done after singular extension search) newDepth = depth - ONE_PLY + ext; // Step 13. Futility pruning (is omitted in PV nodes) if ( !PvNode && !captureOrPromotion && !inCheck && !dangerous /* && move != ttMove Already implicit in the next condition */ && bestValue > VALUE_MATED_IN_MAX_PLY) { // Move count based pruning if ( depth < 16 * ONE_PLY && moveCount >= FutilityMoveCounts[depth] && (!threatMove || !refutes(pos, move, threatMove))) { if (SpNode) splitPoint->mutex.lock(); continue; } // Value based pruning // We illogically ignore reduction condition depth >= 3*ONE_PLY for predicted depth, // but fixing this made program slightly weaker. Depth predictedDepth = newDepth - reduction(depth, moveCount); futilityValue = ss->staticEval + ss->evalMargin + futility_margin(predictedDepth, moveCount) + Gain[pos.piece_moved(move)][to_sq(move)]; if (futilityValue < beta) { bestValue = std::max(bestValue, futilityValue); if (SpNode) { splitPoint->mutex.lock(); if (bestValue > splitPoint->bestValue) splitPoint->bestValue = bestValue; } continue; } // Prune moves with negative SEE at low depths if ( predictedDepth < 4 * ONE_PLY && pos.see_sign(move) < 0) { if (SpNode) splitPoint->mutex.lock(); continue; } // We have not pruned the move that will be searched, but remember how // far in the move list we are to be more aggressive in the child node. ss->futilityMoveCount = moveCount; } else ss->futilityMoveCount = 0; // Check for legality only before to do the move if (!RootNode && !SpNode && !pos.pl_move_is_legal(move, ci.pinned)) { moveCount--; continue; } pvMove = PvNode && moveCount == 1; ss->currentMove = move; if (!SpNode && !captureOrPromotion && playedMoveCount < 64) movesSearched[playedMoveCount++] = move; // Step 14. Make the move pos.do_move(move, st, ci, givesCheck); // Step 15. Reduced depth search (LMR). If the move fails high will be // re-searched at full depth. if ( depth > 3 * ONE_PLY && !pvMove && !captureOrPromotion && !dangerous && move != ttMove && move != ss->killers[0] && move != ss->killers[1]) { ss->reduction = reduction(depth, moveCount); Depth d = std::max(newDepth - ss->reduction, ONE_PLY); if (SpNode) alpha = splitPoint->alpha; value = -search(pos, ss+1, -(alpha+1), -alpha, d); doFullDepthSearch = (value > alpha && ss->reduction != DEPTH_ZERO); ss->reduction = DEPTH_ZERO; } else doFullDepthSearch = !pvMove; // Step 16. Full depth search, when LMR is skipped or fails high if (doFullDepthSearch) { if (SpNode) alpha = splitPoint->alpha; value = newDepth < ONE_PLY ? givesCheck ? -qsearch(pos, ss+1, -(alpha+1), -alpha, DEPTH_ZERO) : -qsearch(pos, ss+1, -(alpha+1), -alpha, DEPTH_ZERO) : - search(pos, ss+1, -(alpha+1), -alpha, newDepth); } // Only for PV nodes do a full PV search on the first move or after a fail // high, in the latter case search only if value < beta, otherwise let the // parent node to fail low with value <= alpha and to try another move. if (PvNode && (pvMove || (value > alpha && (RootNode || value < beta)))) value = newDepth < ONE_PLY ? givesCheck ? -qsearch(pos, ss+1, -beta, -alpha, DEPTH_ZERO) : -qsearch(pos, ss+1, -beta, -alpha, DEPTH_ZERO) : - search(pos, ss+1, -beta, -alpha, newDepth); // Step 17. Undo move pos.undo_move(move); assert(value > -VALUE_INFINITE && value < VALUE_INFINITE); // Step 18. Check for new best move if (SpNode) { splitPoint->mutex.lock(); bestValue = splitPoint->bestValue; alpha = splitPoint->alpha; } // Finished searching the move. If Signals.stop is true, the search // was aborted because the user interrupted the search or because we // ran out of time. In this case, the return value of the search cannot // be trusted, and we don't update the best move and/or PV. if (Signals.stop || thisThread->cutoff_occurred()) return value; // To avoid returning VALUE_INFINITE if (RootNode) { RootMove& rm = *std::find(RootMoves.begin(), RootMoves.end(), move); // PV move or new best move ? if (pvMove || value > alpha) { rm.score = value; rm.extract_pv_from_tt(pos); // We record how often the best move has been changed in each // iteration. This information is used for time management: When // the best move changes frequently, we allocate some more time. if (!pvMove) BestMoveChanges++; } else // All other moves but the PV are set to the lowest value, this // is not a problem when sorting becuase sort is stable and move // position in the list is preserved, just the PV is pushed up. rm.score = -VALUE_INFINITE; } if (value > bestValue) { bestValue = SpNode ? splitPoint->bestValue = value : value; if (value > alpha) { bestMove = SpNode ? splitPoint->bestMove = move : move; if (PvNode && value < beta) // Update alpha! Always alpha < beta alpha = SpNode ? splitPoint->alpha = value : value; else { assert(value >= beta); // Fail high if (SpNode) splitPoint->cutoff = true; break; } } } // Step 19. Check for splitting the search if ( !SpNode && depth >= Threads.minimumSplitDepth && Threads.available_slave(thisThread) && thisThread->splitPointsSize < MAX_SPLITPOINTS_PER_THREAD) { assert(bestValue < beta); thisThread->split(pos, ss, alpha, beta, &bestValue, &bestMove, depth, threatMove, moveCount, &mp, NT); if (bestValue >= beta) break; } } if (SpNode) return bestValue; // Step 20. Check for mate and stalemate // All legal moves have been searched and if there are no legal moves, it // must be mate or stalemate. Note that we can have a false positive in // case of Signals.stop or thread.cutoff_occurred() are set, but this is // harmless because return value is discarded anyhow in the parent nodes. // If we are in a singular extension search then return a fail low score. // A split node has at least one move, the one tried before to be splitted. if (!moveCount) return excludedMove ? alpha : inCheck ? mated_in(ss->ply) : DrawValue[pos.side_to_move()]; // If we have pruned all the moves without searching return a fail-low score if (bestValue == -VALUE_INFINITE) { assert(!playedMoveCount); bestValue = alpha; } if (bestValue >= beta) // Failed high { TT.store(posKey, value_to_tt(bestValue, ss->ply), BOUND_LOWER, depth, bestMove, ss->staticEval, ss->evalMargin); if (!pos.is_capture_or_promotion(bestMove) && !inCheck) { if (bestMove != ss->killers[0]) { ss->killers[1] = ss->killers[0]; ss->killers[0] = bestMove; } // Increase history value of the cut-off move Value bonus = Value(int(depth) * int(depth)); Hist.update(pos.piece_moved(bestMove), to_sq(bestMove), bonus); // Decrease history of all the other played non-capture moves for (int i = 0; i < playedMoveCount - 1; i++) { Move m = movesSearched[i]; Hist.update(pos.piece_moved(m), to_sq(m), -bonus); } } } else // Failed low or PV search TT.store(posKey, value_to_tt(bestValue, ss->ply), PvNode && bestMove != MOVE_NONE ? BOUND_EXACT : BOUND_UPPER, depth, bestMove, ss->staticEval, ss->evalMargin); assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE); return bestValue; } // qsearch() is the quiescence search function, which is called by the main // search function when the remaining depth is zero (or, to be more precise, // less than ONE_PLY). template Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth) { const bool PvNode = (NT == PV); assert(NT == PV || NT == NonPV); assert(InCheck == !!pos.checkers()); assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE); assert(PvNode || (alpha == beta - 1)); assert(depth <= DEPTH_ZERO); StateInfo st; const TTEntry* tte; Key posKey; Move ttMove, move, bestMove; Value bestValue, value, ttValue, futilityValue, futilityBase, oldAlpha; bool givesCheck, enoughMaterial, evasionPrunable; Depth ttDepth; // To flag BOUND_EXACT a node with eval above alpha and no available moves if (PvNode) oldAlpha = alpha; ss->currentMove = bestMove = MOVE_NONE; ss->ply = (ss-1)->ply + 1; // Check for an instant draw or maximum ply reached if (pos.is_draw() || ss->ply > MAX_PLY) return DrawValue[pos.side_to_move()]; // Decide whether or not to include checks, this fixes also the type of // TT entry depth that we are going to use. Note that in qsearch we use // only two types of depth in TT: DEPTH_QS_CHECKS or DEPTH_QS_NO_CHECKS. ttDepth = InCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS : DEPTH_QS_NO_CHECKS; // Transposition table lookup. At PV nodes, we don't use the TT for // pruning, but only for move ordering. posKey = pos.key(); tte = TT.probe(posKey); ttMove = tte ? tte->move() : MOVE_NONE; ttValue = tte ? value_from_tt(tte->value(),ss->ply) : VALUE_NONE; if ( tte && tte->depth() >= ttDepth && ttValue != VALUE_NONE // Only in case of TT access race && ( PvNode ? tte->type() == BOUND_EXACT : ttValue >= beta ? (tte->type() & BOUND_LOWER) : (tte->type() & BOUND_UPPER))) { ss->currentMove = ttMove; // Can be MOVE_NONE return ttValue; } // Evaluate the position statically if (InCheck) { ss->staticEval = ss->evalMargin = VALUE_NONE; bestValue = futilityBase = -VALUE_INFINITE; enoughMaterial = false; } else { if (tte) { // Never assume anything on values stored in TT if ( (ss->staticEval = bestValue = tte->eval_value()) == VALUE_NONE ||(ss->evalMargin = tte->eval_margin()) == VALUE_NONE) ss->staticEval = bestValue = evaluate(pos, ss->evalMargin); } else ss->staticEval = bestValue = evaluate(pos, ss->evalMargin); // Stand pat. Return immediately if static value is at least beta if (bestValue >= beta) { if (!tte) TT.store(pos.key(), value_to_tt(bestValue, ss->ply), BOUND_LOWER, DEPTH_NONE, MOVE_NONE, ss->staticEval, ss->evalMargin); return bestValue; } if (PvNode && bestValue > alpha) alpha = bestValue; futilityBase = ss->staticEval + ss->evalMargin + Value(128); enoughMaterial = pos.non_pawn_material(pos.side_to_move()) > RookValueMg; } // Initialize a MovePicker object for the current position, and prepare // to search the moves. Because the depth is <= 0 here, only captures, // queen promotions and checks (only if depth >= DEPTH_QS_CHECKS) will // be generated. MovePicker mp(pos, ttMove, depth, Hist, to_sq((ss-1)->currentMove)); CheckInfo ci(pos); // Loop through the moves until no moves remain or a beta cutoff occurs while ((move = mp.next_move()) != MOVE_NONE) { assert(is_ok(move)); givesCheck = pos.move_gives_check(move, ci); // Futility pruning if ( !PvNode && !InCheck && !givesCheck && move != ttMove && enoughMaterial && type_of(move) != PROMOTION && !pos.is_passed_pawn_push(move)) { futilityValue = futilityBase + PieceValue[EG][pos.piece_on(to_sq(move))] + (type_of(move) == ENPASSANT ? PawnValueEg : VALUE_ZERO); if (futilityValue < beta) { bestValue = std::max(bestValue, futilityValue); continue; } // Prune moves with negative or equal SEE and also moves with positive // SEE where capturing piece loses a tempo and SEE < beta - futilityBase. if ( futilityBase < beta && depth < DEPTH_ZERO && pos.see(move, beta - futilityBase) <= 0) { bestValue = std::max(bestValue, futilityBase); continue; } } // Detect non-capture evasions that are candidate to be pruned evasionPrunable = !PvNode && InCheck && bestValue > VALUE_MATED_IN_MAX_PLY && !pos.is_capture(move) && !pos.can_castle(pos.side_to_move()); // Don't search moves with negative SEE values if ( !PvNode && (!InCheck || evasionPrunable) && move != ttMove && type_of(move) != PROMOTION && pos.see_sign(move) < 0) continue; // Don't search useless checks if ( !PvNode && !InCheck && givesCheck && move != ttMove && !pos.is_capture_or_promotion(move) && ss->staticEval + PawnValueMg / 4 < beta && !check_is_dangerous(pos, move, futilityBase, beta)) continue; // Check for legality only before to do the move if (!pos.pl_move_is_legal(move, ci.pinned)) continue; ss->currentMove = move; // Make and search the move pos.do_move(move, st, ci, givesCheck); value = givesCheck ? -qsearch(pos, ss+1, -beta, -alpha, depth - ONE_PLY) : -qsearch(pos, ss+1, -beta, -alpha, depth - ONE_PLY); pos.undo_move(move); assert(value > -VALUE_INFINITE && value < VALUE_INFINITE); // Check for new best move if (value > bestValue) { bestValue = value; if (value > alpha) { if (PvNode && value < beta) // Update alpha here! Always alpha < beta { alpha = value; bestMove = move; } else // Fail high { TT.store(posKey, value_to_tt(value, ss->ply), BOUND_LOWER, ttDepth, move, ss->staticEval, ss->evalMargin); return value; } } } } // All legal moves have been searched. A special case: If we're in check // and no legal moves were found, it is checkmate. if (InCheck && bestValue == -VALUE_INFINITE) return mated_in(ss->ply); // Plies to mate from the root TT.store(posKey, value_to_tt(bestValue, ss->ply), PvNode && bestValue > oldAlpha ? BOUND_EXACT : BOUND_UPPER, ttDepth, bestMove, ss->staticEval, ss->evalMargin); assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE); return bestValue; } // value_to_tt() adjusts a mate score from "plies to mate from the root" to // "plies to mate from the current position". Non-mate scores are unchanged. // The function is called before storing a value to the transposition table. Value value_to_tt(Value v, int ply) { assert(v != VALUE_NONE); return v >= VALUE_MATE_IN_MAX_PLY ? v + ply : v <= VALUE_MATED_IN_MAX_PLY ? v - ply : v; } // value_from_tt() is the inverse of value_to_tt(): It adjusts a mate score // from the transposition table (where refers to the plies to mate/be mated // from current position) to "plies to mate/be mated from the root". Value value_from_tt(Value v, int ply) { return v == VALUE_NONE ? VALUE_NONE : v >= VALUE_MATE_IN_MAX_PLY ? v - ply : v <= VALUE_MATED_IN_MAX_PLY ? v + ply : v; } // check_is_dangerous() tests if a checking move can be pruned in qsearch() bool check_is_dangerous(const Position& pos, Move move, Value futilityBase, Value beta) { Piece pc = pos.piece_moved(move); Square from = from_sq(move); Square to = to_sq(move); Color them = ~pos.side_to_move(); Square ksq = pos.king_square(them); Bitboard enemies = pos.pieces(them); Bitboard kingAtt = pos.attacks_from(ksq); Bitboard occ = pos.pieces() ^ from ^ ksq; Bitboard oldAtt = pos.attacks_from(pc, from, occ); Bitboard newAtt = pos.attacks_from(pc, to, occ); // Checks which give opponent's king at most one escape square are dangerous if (!more_than_one(kingAtt & ~(enemies | newAtt | to))) return true; // Queen contact check is very dangerous if (type_of(pc) == QUEEN && (kingAtt & to)) return true; // Creating new double threats with checks is dangerous Bitboard b = (enemies ^ ksq) & newAtt & ~oldAtt; while (b) { // Note that here we generate illegal "double move"! if (futilityBase + PieceValue[EG][pos.piece_on(pop_lsb(&b))] >= beta) return true; } return false; } // allows() tests whether the 'first' move at previous ply somehow makes the // 'second' move possible, for instance if the moving piece is the same in // both moves. Normally the second move is the threat (the best move returned // from a null search that fails low). bool allows(const Position& pos, Move first, Move second) { assert(is_ok(first)); assert(is_ok(second)); assert(color_of(pos.piece_on(from_sq(second))) == ~pos.side_to_move()); assert(color_of(pos.piece_on(to_sq(first))) == ~pos.side_to_move()); Square m1from = from_sq(first); Square m2from = from_sq(second); Square m1to = to_sq(first); Square m2to = to_sq(second); // The piece is the same or second's destination was vacated by the first move if (m1to == m2from || m2to == m1from) return true; // Second one moves through the square vacated by first one if (between_bb(m2from, m2to) & m1from) return true; // Second's destination is defended by the first move's piece Bitboard m1att = pos.attacks_from(pos.piece_on(m1to), m1to, pos.pieces() ^ m2from); if (m1att & m2to) return true; // Second move gives a discovered check through the first's checking piece if (m1att & pos.king_square(pos.side_to_move())) { assert(between_bb(m1to, pos.king_square(pos.side_to_move())) & m2from); return true; } return false; } // refutes() tests whether a 'first' move is able to defend against a 'second' // opponent's move. In this case will not be pruned. Normally the second move // is the threat (the best move returned from a null search that fails low). bool refutes(const Position& pos, Move first, Move second) { assert(is_ok(first)); assert(is_ok(second)); Square m1from = from_sq(first); Square m2from = from_sq(second); Square m1to = to_sq(first); Square m2to = to_sq(second); // Don't prune moves of the threatened piece if (m1from == m2to) return true; // If the threatened piece has value less than or equal to the value of the // threat piece, don't prune moves which defend it. if ( pos.is_capture(second) && ( PieceValue[MG][pos.piece_on(m2from)] >= PieceValue[MG][pos.piece_on(m2to)] || type_of(pos.piece_on(m2from)) == KING)) { // Update occupancy as if the piece and the threat are moving Bitboard occ = pos.pieces() ^ m1from ^ m1to ^ m2from; Piece piece = pos.piece_on(m1from); // The moved piece attacks the square 'tto' ? if (pos.attacks_from(piece, m1to, occ) & m2to) return true; // Scan for possible X-ray attackers behind the moved piece Bitboard xray = (attacks_bb< ROOK>(m2to, occ) & pos.pieces(color_of(piece), QUEEN, ROOK)) | (attacks_bb(m2to, occ) & pos.pieces(color_of(piece), QUEEN, BISHOP)); // Verify attackers are triggered by our move and not already existing if (xray && (xray ^ (xray & pos.attacks_from(m2to)))) return true; } // Don't prune safe moves which block the threat path if ((between_bb(m2from, m2to) & m1to) && pos.see_sign(first) >= 0) return true; return false; } // When playing with strength handicap choose best move among the MultiPV set // using a statistical rule dependent on 'level'. Idea by Heinz van Saanen. Move Skill::pick_move() { static RKISS rk; // PRNG sequence should be not deterministic for (int i = Time::now() % 50; i > 0; i--) rk.rand(); // RootMoves are already sorted by score in descending order int variance = std::min(RootMoves[0].score - RootMoves[PVSize - 1].score, PawnValueMg); int weakness = 120 - 2 * level; int max_s = -VALUE_INFINITE; best = MOVE_NONE; // Choose best move. For each move score we add two terms both dependent on // weakness, one deterministic and bigger for weaker moves, and one random, // then we choose the move with the resulting highest score. for (size_t i = 0; i < PVSize; i++) { int s = RootMoves[i].score; // Don't allow crazy blunders even at very low skills if (i > 0 && RootMoves[i-1].score > s + 2 * PawnValueMg) break; // This is our magic formula s += ( weakness * int(RootMoves[0].score - s) + variance * (rk.rand() % weakness)) / 128; if (s > max_s) { max_s = s; best = RootMoves[i].pv[0]; } } return best; } // uci_pv() formats PV information according to UCI protocol. UCI requires // to send all the PV lines also if are still to be searched and so refer to // the previous search score. string uci_pv(const Position& pos, int depth, Value alpha, Value beta) { std::stringstream s; Time::point elaspsed = Time::now() - SearchTime + 1; size_t uciPVSize = std::min((size_t)Options["MultiPV"], RootMoves.size()); int selDepth = 0; for (size_t i = 0; i < Threads.size(); i++) if (Threads[i]->maxPly > selDepth) selDepth = Threads[i]->maxPly; for (size_t i = 0; i < uciPVSize; i++) { bool updated = (i <= PVIdx); if (depth == 1 && !updated) continue; int d = updated ? depth : depth - 1; Value v = updated ? RootMoves[i].score : RootMoves[i].prevScore; if (s.rdbuf()->in_avail()) // Not at first line s << "\n"; s << "info depth " << d << " seldepth " << selDepth << " score " << (i == PVIdx ? score_to_uci(v, alpha, beta) : score_to_uci(v)) << " nodes " << pos.nodes_searched() << " nps " << pos.nodes_searched() * 1000 / elaspsed << " time " << elaspsed << " multipv " << i + 1 << " pv"; for (size_t j = 0; RootMoves[i].pv[j] != MOVE_NONE; j++) s << " " << move_to_uci(RootMoves[i].pv[j], pos.is_chess960()); } return s.str(); } } // namespace /// RootMove::extract_pv_from_tt() builds a PV by adding moves from the TT table. /// We consider also failing high nodes and not only BOUND_EXACT nodes so to /// allow to always have a ponder move even when we fail high at root, and a /// long PV to print that is important for position analysis. void RootMove::extract_pv_from_tt(Position& pos) { StateInfo state[MAX_PLY_PLUS_2], *st = state; TTEntry* tte; int ply = 0; Move m = pv[0]; pv.clear(); do { pv.push_back(m); assert(MoveList(pos).contains(pv[ply])); pos.do_move(pv[ply++], *st++); tte = TT.probe(pos.key()); } while ( tte && pos.is_pseudo_legal(m = tte->move()) // Local copy, TT could change && pos.pl_move_is_legal(m, pos.pinned_pieces()) && ply < MAX_PLY && (!pos.is_draw() || ply < 2)); pv.push_back(MOVE_NONE); // Must be zero-terminating while (ply) pos.undo_move(pv[--ply]); } /// RootMove::insert_pv_in_tt() is called at the end of a search iteration, and /// inserts the PV back into the TT. This makes sure the old PV moves are searched /// first, even if the old TT entries have been overwritten. void RootMove::insert_pv_in_tt(Position& pos) { StateInfo state[MAX_PLY_PLUS_2], *st = state; TTEntry* tte; int ply = 0; do { tte = TT.probe(pos.key()); if (!tte || tte->move() != pv[ply]) // Don't overwrite correct entries TT.store(pos.key(), VALUE_NONE, BOUND_NONE, DEPTH_NONE, pv[ply], VALUE_NONE, VALUE_NONE); assert(MoveList(pos).contains(pv[ply])); pos.do_move(pv[ply++], *st++); } while (pv[ply] != MOVE_NONE); while (ply) pos.undo_move(pv[--ply]); } /// Thread::idle_loop() is where the thread is parked when it has no work to do void Thread::idle_loop() { // Pointer 'this_sp' is not null only if we are called from split(), and not // at the thread creation. So it means we are the split point's master. SplitPoint* this_sp = splitPointsSize ? activeSplitPoint : NULL; assert(!this_sp || (this_sp->masterThread == this && searching)); while (true) { // If we are not searching, wait for a condition to be signaled instead of // wasting CPU time polling for work. while ((!searching && Threads.sleepWhileIdle) || exit) { if (exit) { assert(!this_sp); return; } // Grab the lock to avoid races with Thread::notify_one() mutex.lock(); // If we are master and all slaves have finished then exit idle_loop if (this_sp && !this_sp->slavesMask) { mutex.unlock(); break; } // Do sleep after retesting sleep conditions under lock protection, in // particular we need to avoid a deadlock in case a master thread has, // in the meanwhile, allocated us and sent the notify_one() call before // we had the chance to grab the lock. if (!searching && !exit) sleepCondition.wait(mutex); mutex.unlock(); } // If this thread has been assigned work, launch a search if (searching) { assert(!exit); Threads.mutex.lock(); assert(searching); SplitPoint* sp = activeSplitPoint; Threads.mutex.unlock(); Stack ss[MAX_PLY_PLUS_2]; Position pos(*sp->pos, this); memcpy(ss, sp->ss - 1, 4 * sizeof(Stack)); (ss+1)->splitPoint = sp; sp->mutex.lock(); assert(activePosition == NULL); activePosition = &pos; switch (sp->nodeType) { case Root: search(pos, ss+1, sp->alpha, sp->beta, sp->depth); break; case PV: search(pos, ss+1, sp->alpha, sp->beta, sp->depth); break; case NonPV: search(pos, ss+1, sp->alpha, sp->beta, sp->depth); break; default: assert(false); } assert(searching); searching = false; activePosition = NULL; sp->slavesMask &= ~(1ULL << idx); sp->nodes += pos.nodes_searched(); // Wake up master thread so to allow it to return from the idle loop // in case we are the last slave of the split point. if ( Threads.sleepWhileIdle && this != sp->masterThread && !sp->slavesMask) { assert(!sp->masterThread->searching); sp->masterThread->notify_one(); } // After releasing the lock we cannot access anymore any SplitPoint // related data in a safe way becuase it could have been released under // our feet by the sp master. Also accessing other Thread objects is // unsafe because if we are exiting there is a chance are already freed. sp->mutex.unlock(); } // If this thread is the master of a split point and all slaves have finished // their work at this split point, return from the idle loop. if (this_sp && !this_sp->slavesMask) { this_sp->mutex.lock(); bool finished = !this_sp->slavesMask; // Retest under lock protection this_sp->mutex.unlock(); if (finished) return; } } } /// check_time() is called by the timer thread when the timer triggers. It is /// used to print debug info and, more important, to detect when we are out of /// available time and so stop the search. void check_time() { static Time::point lastInfoTime = Time::now(); int64_t nodes = 0; // Workaround silly 'uninitialized' gcc warning if (Time::now() - lastInfoTime >= 1000) { lastInfoTime = Time::now(); dbg_print(); } if (Limits.ponder) return; if (Limits.nodes) { Threads.mutex.lock(); nodes = RootPos.nodes_searched(); // Loop across all split points and sum accumulated SplitPoint nodes plus // all the currently active positions nodes. for (size_t i = 0; i < Threads.size(); i++) for (int j = 0; j < Threads[i]->splitPointsSize; j++) { SplitPoint& sp = Threads[i]->splitPoints[j]; sp.mutex.lock(); nodes += sp.nodes; Bitboard sm = sp.slavesMask; while (sm) { Position* pos = Threads[pop_lsb(&sm)]->activePosition; if (pos) nodes += pos->nodes_searched(); } sp.mutex.unlock(); } Threads.mutex.unlock(); } Time::point elapsed = Time::now() - SearchTime; bool stillAtFirstMove = Signals.firstRootMove && !Signals.failedLowAtRoot && elapsed > TimeMgr.available_time(); bool noMoreTime = elapsed > TimeMgr.maximum_time() - 2 * TimerResolution || stillAtFirstMove; if ( (Limits.use_time_management() && noMoreTime) || (Limits.movetime && elapsed >= Limits.movetime) || (Limits.nodes && nodes >= Limits.nodes)) Signals.stop = true; } stockfish-3.0.0+git20130508/src/tt.h0000644000175000017500000000750212142540127016064 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #if !defined(TT_H_INCLUDED) #define TT_H_INCLUDED #include "misc.h" #include "types.h" /// The TTEntry is the class of transposition table entries /// /// A TTEntry needs 128 bits to be stored /// /// bit 0-31: key /// bit 32-63: data /// bit 64-79: value /// bit 80-95: depth /// bit 96-111: static value /// bit 112-127: margin of static value /// /// the 32 bits of the data field are so defined /// /// bit 0-15: move /// bit 16-20: not used /// bit 21-22: value type /// bit 23-31: generation class TTEntry { public: void save(uint32_t k, Value v, Bound b, Depth d, Move m, int g, Value ev, Value em) { key32 = (uint32_t)k; move16 = (uint16_t)m; bound = (uint8_t)b; generation8 = (uint8_t)g; value16 = (int16_t)v; depth16 = (int16_t)d; evalValue = (int16_t)ev; evalMargin = (int16_t)em; } void set_generation(int g) { generation8 = (uint8_t)g; } uint32_t key() const { return key32; } Depth depth() const { return (Depth)depth16; } Move move() const { return (Move)move16; } Value value() const { return (Value)value16; } Bound type() const { return (Bound)bound; } int generation() const { return (int)generation8; } Value eval_value() const { return (Value)evalValue; } Value eval_margin() const { return (Value)evalMargin; } private: uint32_t key32; uint16_t move16; uint8_t bound, generation8; int16_t value16, depth16, evalValue, evalMargin; }; /// A TranspositionTable consists of a power of 2 number of clusters and each /// cluster consists of ClusterSize number of TTEntry. Each non-empty entry /// contains information of exactly one position. Size of a cluster shall not be /// bigger than a cache line size. In case it is less, it should be padded to /// guarantee always aligned accesses. class TranspositionTable { static const unsigned ClusterSize = 4; // A cluster is 64 Bytes public: ~TranspositionTable() { free(mem); } void new_search() { generation++; } TTEntry* probe(const Key key) const; TTEntry* first_entry(const Key key) const; void refresh(const TTEntry* tte) const; void set_size(size_t mbSize); void clear(); void store(const Key key, Value v, Bound type, Depth d, Move m, Value statV, Value kingD); private: uint32_t hashMask; TTEntry* table; void* mem; uint8_t generation; // Size must be not bigger then TTEntry::generation8 }; extern TranspositionTable TT; /// TranspositionTable::first_entry() returns a pointer to the first entry of /// a cluster given a position. The lowest order bits of the key are used to /// get the index of the cluster. inline TTEntry* TranspositionTable::first_entry(const Key key) const { return table + ((uint32_t)key & hashMask); } /// TranspositionTable::refresh() updates the 'generation' value of the TTEntry /// to avoid aging. Normally called after a TT hit. inline void TranspositionTable::refresh(const TTEntry* tte) const { const_cast(tte)->set_generation(generation); } #endif // !defined(TT_H_INCLUDED) stockfish-3.0.0+git20130508/src/tt.cpp0000644000175000017500000001005212142540127016411 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include "bitboard.h" #include "tt.h" TranspositionTable TT; // Our global transposition table /// TranspositionTable::set_size() sets the size of the transposition table, /// measured in megabytes. Transposition table consists of a power of 2 number /// of clusters and each cluster consists of ClusterSize number of TTEntry. void TranspositionTable::set_size(size_t mbSize) { assert(msb((mbSize << 20) / sizeof(TTEntry)) < 32); uint32_t size = ClusterSize << msb((mbSize << 20) / sizeof(TTEntry[ClusterSize])); if (hashMask == size - ClusterSize) return; hashMask = size - ClusterSize; free(mem); mem = malloc(size * sizeof(TTEntry) + CACHE_LINE_SIZE - 1); if (!mem) { std::cerr << "Failed to allocate " << mbSize << "MB for transposition table." << std::endl; exit(EXIT_FAILURE); } table = (TTEntry*)((uintptr_t(mem) + CACHE_LINE_SIZE - 1) & ~(CACHE_LINE_SIZE - 1)); clear(); // Operator new is not guaranteed to initialize memory to zero } /// TranspositionTable::clear() overwrites the entire transposition table /// with zeroes. It is called whenever the table is resized, or when the /// user asks the program to clear the table (from the UCI interface). void TranspositionTable::clear() { memset(table, 0, (hashMask + ClusterSize) * sizeof(TTEntry)); } /// TranspositionTable::store() writes a new entry containing position key and /// valuable information of current position. The lowest order bits of position /// key are used to decide on which cluster the position will be placed. /// When a new entry is written and there are no empty entries available in cluster, /// it replaces the least valuable of entries. A TTEntry t1 is considered to be /// more valuable than a TTEntry t2 if t1 is from the current search and t2 is from /// a previous search, or if the depth of t1 is bigger than the depth of t2. void TranspositionTable::store(const Key key, Value v, Bound t, Depth d, Move m, Value statV, Value kingD) { int c1, c2, c3; TTEntry *tte, *replace; uint32_t key32 = key >> 32; // Use the high 32 bits as key inside the cluster tte = replace = first_entry(key); for (unsigned i = 0; i < ClusterSize; i++, tte++) { if (!tte->key() || tte->key() == key32) // Empty or overwrite old { // Preserve any existing ttMove if (m == MOVE_NONE) m = tte->move(); tte->save(key32, v, t, d, m, generation, statV, kingD); return; } // Implement replace strategy c1 = (replace->generation() == generation ? 2 : 0); c2 = (tte->generation() == generation || tte->type() == BOUND_EXACT ? -2 : 0); c3 = (tte->depth() < replace->depth() ? 1 : 0); if (c1 + c2 + c3 > 0) replace = tte; } replace->save(key32, v, t, d, m, generation, statV, kingD); } /// TranspositionTable::probe() looks up the current position in the /// transposition table. Returns a pointer to the TTEntry or NULL if /// position is not found. TTEntry* TranspositionTable::probe(const Key key) const { TTEntry* tte = first_entry(key); uint32_t key32 = key >> 32; for (unsigned i = 0; i < ClusterSize; i++, tte++) if (tte->key() == key32) return tte; return NULL; } stockfish-3.0.0+git20130508/src/book.cpp0000644000175000017500000006114212142540127016722 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* The code in this file is based on the opening book code in PolyGlot by Fabien Letouzey. PolyGlot is available under the GNU General Public License, and can be downloaded from http://wbec-ridderkerk.nl */ #include #include #include #include "book.h" #include "misc.h" #include "movegen.h" using namespace std; namespace { // A Polyglot book is a series of "entries" of 16 bytes. All integers are // stored in big-endian format, with highest byte first (regardless of size). // The entries are ordered according to the key in ascending order. struct Entry { uint64_t key; uint16_t move; uint16_t count; uint32_t learn; }; // Random numbers from PolyGlot, used to compute book hash keys const union { Key PolyGlotRandoms[781]; struct { Key psq[12][64]; // [piece][square] Key castle[4]; // [castle right] Key enpassant[8]; // [file] Key turn; } Zobrist; } PG = {{ 0x9D39247E33776D41ULL, 0x2AF7398005AAA5C7ULL, 0x44DB015024623547ULL, 0x9C15F73E62A76AE2ULL, 0x75834465489C0C89ULL, 0x3290AC3A203001BFULL, 0x0FBBAD1F61042279ULL, 0xE83A908FF2FB60CAULL, 0x0D7E765D58755C10ULL, 0x1A083822CEAFE02DULL, 0x9605D5F0E25EC3B0ULL, 0xD021FF5CD13A2ED5ULL, 0x40BDF15D4A672E32ULL, 0x011355146FD56395ULL, 0x5DB4832046F3D9E5ULL, 0x239F8B2D7FF719CCULL, 0x05D1A1AE85B49AA1ULL, 0x679F848F6E8FC971ULL, 0x7449BBFF801FED0BULL, 0x7D11CDB1C3B7ADF0ULL, 0x82C7709E781EB7CCULL, 0xF3218F1C9510786CULL, 0x331478F3AF51BBE6ULL, 0x4BB38DE5E7219443ULL, 0xAA649C6EBCFD50FCULL, 0x8DBD98A352AFD40BULL, 0x87D2074B81D79217ULL, 0x19F3C751D3E92AE1ULL, 0xB4AB30F062B19ABFULL, 0x7B0500AC42047AC4ULL, 0xC9452CA81A09D85DULL, 0x24AA6C514DA27500ULL, 0x4C9F34427501B447ULL, 0x14A68FD73C910841ULL, 0xA71B9B83461CBD93ULL, 0x03488B95B0F1850FULL, 0x637B2B34FF93C040ULL, 0x09D1BC9A3DD90A94ULL, 0x3575668334A1DD3BULL, 0x735E2B97A4C45A23ULL, 0x18727070F1BD400BULL, 0x1FCBACD259BF02E7ULL, 0xD310A7C2CE9B6555ULL, 0xBF983FE0FE5D8244ULL, 0x9F74D14F7454A824ULL, 0x51EBDC4AB9BA3035ULL, 0x5C82C505DB9AB0FAULL, 0xFCF7FE8A3430B241ULL, 0x3253A729B9BA3DDEULL, 0x8C74C368081B3075ULL, 0xB9BC6C87167C33E7ULL, 0x7EF48F2B83024E20ULL, 0x11D505D4C351BD7FULL, 0x6568FCA92C76A243ULL, 0x4DE0B0F40F32A7B8ULL, 0x96D693460CC37E5DULL, 0x42E240CB63689F2FULL, 0x6D2BDCDAE2919661ULL, 0x42880B0236E4D951ULL, 0x5F0F4A5898171BB6ULL, 0x39F890F579F92F88ULL, 0x93C5B5F47356388BULL, 0x63DC359D8D231B78ULL, 0xEC16CA8AEA98AD76ULL, 0x5355F900C2A82DC7ULL, 0x07FB9F855A997142ULL, 0x5093417AA8A7ED5EULL, 0x7BCBC38DA25A7F3CULL, 0x19FC8A768CF4B6D4ULL, 0x637A7780DECFC0D9ULL, 0x8249A47AEE0E41F7ULL, 0x79AD695501E7D1E8ULL, 0x14ACBAF4777D5776ULL, 0xF145B6BECCDEA195ULL, 0xDABF2AC8201752FCULL, 0x24C3C94DF9C8D3F6ULL, 0xBB6E2924F03912EAULL, 0x0CE26C0B95C980D9ULL, 0xA49CD132BFBF7CC4ULL, 0xE99D662AF4243939ULL, 0x27E6AD7891165C3FULL, 0x8535F040B9744FF1ULL, 0x54B3F4FA5F40D873ULL, 0x72B12C32127FED2BULL, 0xEE954D3C7B411F47ULL, 0x9A85AC909A24EAA1ULL, 0x70AC4CD9F04F21F5ULL, 0xF9B89D3E99A075C2ULL, 0x87B3E2B2B5C907B1ULL, 0xA366E5B8C54F48B8ULL, 0xAE4A9346CC3F7CF2ULL, 0x1920C04D47267BBDULL, 0x87BF02C6B49E2AE9ULL, 0x092237AC237F3859ULL, 0xFF07F64EF8ED14D0ULL, 0x8DE8DCA9F03CC54EULL, 0x9C1633264DB49C89ULL, 0xB3F22C3D0B0B38EDULL, 0x390E5FB44D01144BULL, 0x5BFEA5B4712768E9ULL, 0x1E1032911FA78984ULL, 0x9A74ACB964E78CB3ULL, 0x4F80F7A035DAFB04ULL, 0x6304D09A0B3738C4ULL, 0x2171E64683023A08ULL, 0x5B9B63EB9CEFF80CULL, 0x506AACF489889342ULL, 0x1881AFC9A3A701D6ULL, 0x6503080440750644ULL, 0xDFD395339CDBF4A7ULL, 0xEF927DBCF00C20F2ULL, 0x7B32F7D1E03680ECULL, 0xB9FD7620E7316243ULL, 0x05A7E8A57DB91B77ULL, 0xB5889C6E15630A75ULL, 0x4A750A09CE9573F7ULL, 0xCF464CEC899A2F8AULL, 0xF538639CE705B824ULL, 0x3C79A0FF5580EF7FULL, 0xEDE6C87F8477609DULL, 0x799E81F05BC93F31ULL, 0x86536B8CF3428A8CULL, 0x97D7374C60087B73ULL, 0xA246637CFF328532ULL, 0x043FCAE60CC0EBA0ULL, 0x920E449535DD359EULL, 0x70EB093B15B290CCULL, 0x73A1921916591CBDULL, 0x56436C9FE1A1AA8DULL, 0xEFAC4B70633B8F81ULL, 0xBB215798D45DF7AFULL, 0x45F20042F24F1768ULL, 0x930F80F4E8EB7462ULL, 0xFF6712FFCFD75EA1ULL, 0xAE623FD67468AA70ULL, 0xDD2C5BC84BC8D8FCULL, 0x7EED120D54CF2DD9ULL, 0x22FE545401165F1CULL, 0xC91800E98FB99929ULL, 0x808BD68E6AC10365ULL, 0xDEC468145B7605F6ULL, 0x1BEDE3A3AEF53302ULL, 0x43539603D6C55602ULL, 0xAA969B5C691CCB7AULL, 0xA87832D392EFEE56ULL, 0x65942C7B3C7E11AEULL, 0xDED2D633CAD004F6ULL, 0x21F08570F420E565ULL, 0xB415938D7DA94E3CULL, 0x91B859E59ECB6350ULL, 0x10CFF333E0ED804AULL, 0x28AED140BE0BB7DDULL, 0xC5CC1D89724FA456ULL, 0x5648F680F11A2741ULL, 0x2D255069F0B7DAB3ULL, 0x9BC5A38EF729ABD4ULL, 0xEF2F054308F6A2BCULL, 0xAF2042F5CC5C2858ULL, 0x480412BAB7F5BE2AULL, 0xAEF3AF4A563DFE43ULL, 0x19AFE59AE451497FULL, 0x52593803DFF1E840ULL, 0xF4F076E65F2CE6F0ULL, 0x11379625747D5AF3ULL, 0xBCE5D2248682C115ULL, 0x9DA4243DE836994FULL, 0x066F70B33FE09017ULL, 0x4DC4DE189B671A1CULL, 0x51039AB7712457C3ULL, 0xC07A3F80C31FB4B4ULL, 0xB46EE9C5E64A6E7CULL, 0xB3819A42ABE61C87ULL, 0x21A007933A522A20ULL, 0x2DF16F761598AA4FULL, 0x763C4A1371B368FDULL, 0xF793C46702E086A0ULL, 0xD7288E012AEB8D31ULL, 0xDE336A2A4BC1C44BULL, 0x0BF692B38D079F23ULL, 0x2C604A7A177326B3ULL, 0x4850E73E03EB6064ULL, 0xCFC447F1E53C8E1BULL, 0xB05CA3F564268D99ULL, 0x9AE182C8BC9474E8ULL, 0xA4FC4BD4FC5558CAULL, 0xE755178D58FC4E76ULL, 0x69B97DB1A4C03DFEULL, 0xF9B5B7C4ACC67C96ULL, 0xFC6A82D64B8655FBULL, 0x9C684CB6C4D24417ULL, 0x8EC97D2917456ED0ULL, 0x6703DF9D2924E97EULL, 0xC547F57E42A7444EULL, 0x78E37644E7CAD29EULL, 0xFE9A44E9362F05FAULL, 0x08BD35CC38336615ULL, 0x9315E5EB3A129ACEULL, 0x94061B871E04DF75ULL, 0xDF1D9F9D784BA010ULL, 0x3BBA57B68871B59DULL, 0xD2B7ADEEDED1F73FULL, 0xF7A255D83BC373F8ULL, 0xD7F4F2448C0CEB81ULL, 0xD95BE88CD210FFA7ULL, 0x336F52F8FF4728E7ULL, 0xA74049DAC312AC71ULL, 0xA2F61BB6E437FDB5ULL, 0x4F2A5CB07F6A35B3ULL, 0x87D380BDA5BF7859ULL, 0x16B9F7E06C453A21ULL, 0x7BA2484C8A0FD54EULL, 0xF3A678CAD9A2E38CULL, 0x39B0BF7DDE437BA2ULL, 0xFCAF55C1BF8A4424ULL, 0x18FCF680573FA594ULL, 0x4C0563B89F495AC3ULL, 0x40E087931A00930DULL, 0x8CFFA9412EB642C1ULL, 0x68CA39053261169FULL, 0x7A1EE967D27579E2ULL, 0x9D1D60E5076F5B6FULL, 0x3810E399B6F65BA2ULL, 0x32095B6D4AB5F9B1ULL, 0x35CAB62109DD038AULL, 0xA90B24499FCFAFB1ULL, 0x77A225A07CC2C6BDULL, 0x513E5E634C70E331ULL, 0x4361C0CA3F692F12ULL, 0xD941ACA44B20A45BULL, 0x528F7C8602C5807BULL, 0x52AB92BEB9613989ULL, 0x9D1DFA2EFC557F73ULL, 0x722FF175F572C348ULL, 0x1D1260A51107FE97ULL, 0x7A249A57EC0C9BA2ULL, 0x04208FE9E8F7F2D6ULL, 0x5A110C6058B920A0ULL, 0x0CD9A497658A5698ULL, 0x56FD23C8F9715A4CULL, 0x284C847B9D887AAEULL, 0x04FEABFBBDB619CBULL, 0x742E1E651C60BA83ULL, 0x9A9632E65904AD3CULL, 0x881B82A13B51B9E2ULL, 0x506E6744CD974924ULL, 0xB0183DB56FFC6A79ULL, 0x0ED9B915C66ED37EULL, 0x5E11E86D5873D484ULL, 0xF678647E3519AC6EULL, 0x1B85D488D0F20CC5ULL, 0xDAB9FE6525D89021ULL, 0x0D151D86ADB73615ULL, 0xA865A54EDCC0F019ULL, 0x93C42566AEF98FFBULL, 0x99E7AFEABE000731ULL, 0x48CBFF086DDF285AULL, 0x7F9B6AF1EBF78BAFULL, 0x58627E1A149BBA21ULL, 0x2CD16E2ABD791E33ULL, 0xD363EFF5F0977996ULL, 0x0CE2A38C344A6EEDULL, 0x1A804AADB9CFA741ULL, 0x907F30421D78C5DEULL, 0x501F65EDB3034D07ULL, 0x37624AE5A48FA6E9ULL, 0x957BAF61700CFF4EULL, 0x3A6C27934E31188AULL, 0xD49503536ABCA345ULL, 0x088E049589C432E0ULL, 0xF943AEE7FEBF21B8ULL, 0x6C3B8E3E336139D3ULL, 0x364F6FFA464EE52EULL, 0xD60F6DCEDC314222ULL, 0x56963B0DCA418FC0ULL, 0x16F50EDF91E513AFULL, 0xEF1955914B609F93ULL, 0x565601C0364E3228ULL, 0xECB53939887E8175ULL, 0xBAC7A9A18531294BULL, 0xB344C470397BBA52ULL, 0x65D34954DAF3CEBDULL, 0xB4B81B3FA97511E2ULL, 0xB422061193D6F6A7ULL, 0x071582401C38434DULL, 0x7A13F18BBEDC4FF5ULL, 0xBC4097B116C524D2ULL, 0x59B97885E2F2EA28ULL, 0x99170A5DC3115544ULL, 0x6F423357E7C6A9F9ULL, 0x325928EE6E6F8794ULL, 0xD0E4366228B03343ULL, 0x565C31F7DE89EA27ULL, 0x30F5611484119414ULL, 0xD873DB391292ED4FULL, 0x7BD94E1D8E17DEBCULL, 0xC7D9F16864A76E94ULL, 0x947AE053EE56E63CULL, 0xC8C93882F9475F5FULL, 0x3A9BF55BA91F81CAULL, 0xD9A11FBB3D9808E4ULL, 0x0FD22063EDC29FCAULL, 0xB3F256D8ACA0B0B9ULL, 0xB03031A8B4516E84ULL, 0x35DD37D5871448AFULL, 0xE9F6082B05542E4EULL, 0xEBFAFA33D7254B59ULL, 0x9255ABB50D532280ULL, 0xB9AB4CE57F2D34F3ULL, 0x693501D628297551ULL, 0xC62C58F97DD949BFULL, 0xCD454F8F19C5126AULL, 0xBBE83F4ECC2BDECBULL, 0xDC842B7E2819E230ULL, 0xBA89142E007503B8ULL, 0xA3BC941D0A5061CBULL, 0xE9F6760E32CD8021ULL, 0x09C7E552BC76492FULL, 0x852F54934DA55CC9ULL, 0x8107FCCF064FCF56ULL, 0x098954D51FFF6580ULL, 0x23B70EDB1955C4BFULL, 0xC330DE426430F69DULL, 0x4715ED43E8A45C0AULL, 0xA8D7E4DAB780A08DULL, 0x0572B974F03CE0BBULL, 0xB57D2E985E1419C7ULL, 0xE8D9ECBE2CF3D73FULL, 0x2FE4B17170E59750ULL, 0x11317BA87905E790ULL, 0x7FBF21EC8A1F45ECULL, 0x1725CABFCB045B00ULL, 0x964E915CD5E2B207ULL, 0x3E2B8BCBF016D66DULL, 0xBE7444E39328A0ACULL, 0xF85B2B4FBCDE44B7ULL, 0x49353FEA39BA63B1ULL, 0x1DD01AAFCD53486AULL, 0x1FCA8A92FD719F85ULL, 0xFC7C95D827357AFAULL, 0x18A6A990C8B35EBDULL, 0xCCCB7005C6B9C28DULL, 0x3BDBB92C43B17F26ULL, 0xAA70B5B4F89695A2ULL, 0xE94C39A54A98307FULL, 0xB7A0B174CFF6F36EULL, 0xD4DBA84729AF48ADULL, 0x2E18BC1AD9704A68ULL, 0x2DE0966DAF2F8B1CULL, 0xB9C11D5B1E43A07EULL, 0x64972D68DEE33360ULL, 0x94628D38D0C20584ULL, 0xDBC0D2B6AB90A559ULL, 0xD2733C4335C6A72FULL, 0x7E75D99D94A70F4DULL, 0x6CED1983376FA72BULL, 0x97FCAACBF030BC24ULL, 0x7B77497B32503B12ULL, 0x8547EDDFB81CCB94ULL, 0x79999CDFF70902CBULL, 0xCFFE1939438E9B24ULL, 0x829626E3892D95D7ULL, 0x92FAE24291F2B3F1ULL, 0x63E22C147B9C3403ULL, 0xC678B6D860284A1CULL, 0x5873888850659AE7ULL, 0x0981DCD296A8736DULL, 0x9F65789A6509A440ULL, 0x9FF38FED72E9052FULL, 0xE479EE5B9930578CULL, 0xE7F28ECD2D49EECDULL, 0x56C074A581EA17FEULL, 0x5544F7D774B14AEFULL, 0x7B3F0195FC6F290FULL, 0x12153635B2C0CF57ULL, 0x7F5126DBBA5E0CA7ULL, 0x7A76956C3EAFB413ULL, 0x3D5774A11D31AB39ULL, 0x8A1B083821F40CB4ULL, 0x7B4A38E32537DF62ULL, 0x950113646D1D6E03ULL, 0x4DA8979A0041E8A9ULL, 0x3BC36E078F7515D7ULL, 0x5D0A12F27AD310D1ULL, 0x7F9D1A2E1EBE1327ULL, 0xDA3A361B1C5157B1ULL, 0xDCDD7D20903D0C25ULL, 0x36833336D068F707ULL, 0xCE68341F79893389ULL, 0xAB9090168DD05F34ULL, 0x43954B3252DC25E5ULL, 0xB438C2B67F98E5E9ULL, 0x10DCD78E3851A492ULL, 0xDBC27AB5447822BFULL, 0x9B3CDB65F82CA382ULL, 0xB67B7896167B4C84ULL, 0xBFCED1B0048EAC50ULL, 0xA9119B60369FFEBDULL, 0x1FFF7AC80904BF45ULL, 0xAC12FB171817EEE7ULL, 0xAF08DA9177DDA93DULL, 0x1B0CAB936E65C744ULL, 0xB559EB1D04E5E932ULL, 0xC37B45B3F8D6F2BAULL, 0xC3A9DC228CAAC9E9ULL, 0xF3B8B6675A6507FFULL, 0x9FC477DE4ED681DAULL, 0x67378D8ECCEF96CBULL, 0x6DD856D94D259236ULL, 0xA319CE15B0B4DB31ULL, 0x073973751F12DD5EULL, 0x8A8E849EB32781A5ULL, 0xE1925C71285279F5ULL, 0x74C04BF1790C0EFEULL, 0x4DDA48153C94938AULL, 0x9D266D6A1CC0542CULL, 0x7440FB816508C4FEULL, 0x13328503DF48229FULL, 0xD6BF7BAEE43CAC40ULL, 0x4838D65F6EF6748FULL, 0x1E152328F3318DEAULL, 0x8F8419A348F296BFULL, 0x72C8834A5957B511ULL, 0xD7A023A73260B45CULL, 0x94EBC8ABCFB56DAEULL, 0x9FC10D0F989993E0ULL, 0xDE68A2355B93CAE6ULL, 0xA44CFE79AE538BBEULL, 0x9D1D84FCCE371425ULL, 0x51D2B1AB2DDFB636ULL, 0x2FD7E4B9E72CD38CULL, 0x65CA5B96B7552210ULL, 0xDD69A0D8AB3B546DULL, 0x604D51B25FBF70E2ULL, 0x73AA8A564FB7AC9EULL, 0x1A8C1E992B941148ULL, 0xAAC40A2703D9BEA0ULL, 0x764DBEAE7FA4F3A6ULL, 0x1E99B96E70A9BE8BULL, 0x2C5E9DEB57EF4743ULL, 0x3A938FEE32D29981ULL, 0x26E6DB8FFDF5ADFEULL, 0x469356C504EC9F9DULL, 0xC8763C5B08D1908CULL, 0x3F6C6AF859D80055ULL, 0x7F7CC39420A3A545ULL, 0x9BFB227EBDF4C5CEULL, 0x89039D79D6FC5C5CULL, 0x8FE88B57305E2AB6ULL, 0xA09E8C8C35AB96DEULL, 0xFA7E393983325753ULL, 0xD6B6D0ECC617C699ULL, 0xDFEA21EA9E7557E3ULL, 0xB67C1FA481680AF8ULL, 0xCA1E3785A9E724E5ULL, 0x1CFC8BED0D681639ULL, 0xD18D8549D140CAEAULL, 0x4ED0FE7E9DC91335ULL, 0xE4DBF0634473F5D2ULL, 0x1761F93A44D5AEFEULL, 0x53898E4C3910DA55ULL, 0x734DE8181F6EC39AULL, 0x2680B122BAA28D97ULL, 0x298AF231C85BAFABULL, 0x7983EED3740847D5ULL, 0x66C1A2A1A60CD889ULL, 0x9E17E49642A3E4C1ULL, 0xEDB454E7BADC0805ULL, 0x50B704CAB602C329ULL, 0x4CC317FB9CDDD023ULL, 0x66B4835D9EAFEA22ULL, 0x219B97E26FFC81BDULL, 0x261E4E4C0A333A9DULL, 0x1FE2CCA76517DB90ULL, 0xD7504DFA8816EDBBULL, 0xB9571FA04DC089C8ULL, 0x1DDC0325259B27DEULL, 0xCF3F4688801EB9AAULL, 0xF4F5D05C10CAB243ULL, 0x38B6525C21A42B0EULL, 0x36F60E2BA4FA6800ULL, 0xEB3593803173E0CEULL, 0x9C4CD6257C5A3603ULL, 0xAF0C317D32ADAA8AULL, 0x258E5A80C7204C4BULL, 0x8B889D624D44885DULL, 0xF4D14597E660F855ULL, 0xD4347F66EC8941C3ULL, 0xE699ED85B0DFB40DULL, 0x2472F6207C2D0484ULL, 0xC2A1E7B5B459AEB5ULL, 0xAB4F6451CC1D45ECULL, 0x63767572AE3D6174ULL, 0xA59E0BD101731A28ULL, 0x116D0016CB948F09ULL, 0x2CF9C8CA052F6E9FULL, 0x0B090A7560A968E3ULL, 0xABEEDDB2DDE06FF1ULL, 0x58EFC10B06A2068DULL, 0xC6E57A78FBD986E0ULL, 0x2EAB8CA63CE802D7ULL, 0x14A195640116F336ULL, 0x7C0828DD624EC390ULL, 0xD74BBE77E6116AC7ULL, 0x804456AF10F5FB53ULL, 0xEBE9EA2ADF4321C7ULL, 0x03219A39EE587A30ULL, 0x49787FEF17AF9924ULL, 0xA1E9300CD8520548ULL, 0x5B45E522E4B1B4EFULL, 0xB49C3B3995091A36ULL, 0xD4490AD526F14431ULL, 0x12A8F216AF9418C2ULL, 0x001F837CC7350524ULL, 0x1877B51E57A764D5ULL, 0xA2853B80F17F58EEULL, 0x993E1DE72D36D310ULL, 0xB3598080CE64A656ULL, 0x252F59CF0D9F04BBULL, 0xD23C8E176D113600ULL, 0x1BDA0492E7E4586EULL, 0x21E0BD5026C619BFULL, 0x3B097ADAF088F94EULL, 0x8D14DEDB30BE846EULL, 0xF95CFFA23AF5F6F4ULL, 0x3871700761B3F743ULL, 0xCA672B91E9E4FA16ULL, 0x64C8E531BFF53B55ULL, 0x241260ED4AD1E87DULL, 0x106C09B972D2E822ULL, 0x7FBA195410E5CA30ULL, 0x7884D9BC6CB569D8ULL, 0x0647DFEDCD894A29ULL, 0x63573FF03E224774ULL, 0x4FC8E9560F91B123ULL, 0x1DB956E450275779ULL, 0xB8D91274B9E9D4FBULL, 0xA2EBEE47E2FBFCE1ULL, 0xD9F1F30CCD97FB09ULL, 0xEFED53D75FD64E6BULL, 0x2E6D02C36017F67FULL, 0xA9AA4D20DB084E9BULL, 0xB64BE8D8B25396C1ULL, 0x70CB6AF7C2D5BCF0ULL, 0x98F076A4F7A2322EULL, 0xBF84470805E69B5FULL, 0x94C3251F06F90CF3ULL, 0x3E003E616A6591E9ULL, 0xB925A6CD0421AFF3ULL, 0x61BDD1307C66E300ULL, 0xBF8D5108E27E0D48ULL, 0x240AB57A8B888B20ULL, 0xFC87614BAF287E07ULL, 0xEF02CDD06FFDB432ULL, 0xA1082C0466DF6C0AULL, 0x8215E577001332C8ULL, 0xD39BB9C3A48DB6CFULL, 0x2738259634305C14ULL, 0x61CF4F94C97DF93DULL, 0x1B6BACA2AE4E125BULL, 0x758F450C88572E0BULL, 0x959F587D507A8359ULL, 0xB063E962E045F54DULL, 0x60E8ED72C0DFF5D1ULL, 0x7B64978555326F9FULL, 0xFD080D236DA814BAULL, 0x8C90FD9B083F4558ULL, 0x106F72FE81E2C590ULL, 0x7976033A39F7D952ULL, 0xA4EC0132764CA04BULL, 0x733EA705FAE4FA77ULL, 0xB4D8F77BC3E56167ULL, 0x9E21F4F903B33FD9ULL, 0x9D765E419FB69F6DULL, 0xD30C088BA61EA5EFULL, 0x5D94337FBFAF7F5BULL, 0x1A4E4822EB4D7A59ULL, 0x6FFE73E81B637FB3ULL, 0xDDF957BC36D8B9CAULL, 0x64D0E29EEA8838B3ULL, 0x08DD9BDFD96B9F63ULL, 0x087E79E5A57D1D13ULL, 0xE328E230E3E2B3FBULL, 0x1C2559E30F0946BEULL, 0x720BF5F26F4D2EAAULL, 0xB0774D261CC609DBULL, 0x443F64EC5A371195ULL, 0x4112CF68649A260EULL, 0xD813F2FAB7F5C5CAULL, 0x660D3257380841EEULL, 0x59AC2C7873F910A3ULL, 0xE846963877671A17ULL, 0x93B633ABFA3469F8ULL, 0xC0C0F5A60EF4CDCFULL, 0xCAF21ECD4377B28CULL, 0x57277707199B8175ULL, 0x506C11B9D90E8B1DULL, 0xD83CC2687A19255FULL, 0x4A29C6465A314CD1ULL, 0xED2DF21216235097ULL, 0xB5635C95FF7296E2ULL, 0x22AF003AB672E811ULL, 0x52E762596BF68235ULL, 0x9AEBA33AC6ECC6B0ULL, 0x944F6DE09134DFB6ULL, 0x6C47BEC883A7DE39ULL, 0x6AD047C430A12104ULL, 0xA5B1CFDBA0AB4067ULL, 0x7C45D833AFF07862ULL, 0x5092EF950A16DA0BULL, 0x9338E69C052B8E7BULL, 0x455A4B4CFE30E3F5ULL, 0x6B02E63195AD0CF8ULL, 0x6B17B224BAD6BF27ULL, 0xD1E0CCD25BB9C169ULL, 0xDE0C89A556B9AE70ULL, 0x50065E535A213CF6ULL, 0x9C1169FA2777B874ULL, 0x78EDEFD694AF1EEDULL, 0x6DC93D9526A50E68ULL, 0xEE97F453F06791EDULL, 0x32AB0EDB696703D3ULL, 0x3A6853C7E70757A7ULL, 0x31865CED6120F37DULL, 0x67FEF95D92607890ULL, 0x1F2B1D1F15F6DC9CULL, 0xB69E38A8965C6B65ULL, 0xAA9119FF184CCCF4ULL, 0xF43C732873F24C13ULL, 0xFB4A3D794A9A80D2ULL, 0x3550C2321FD6109CULL, 0x371F77E76BB8417EULL, 0x6BFA9AAE5EC05779ULL, 0xCD04F3FF001A4778ULL, 0xE3273522064480CAULL, 0x9F91508BFFCFC14AULL, 0x049A7F41061A9E60ULL, 0xFCB6BE43A9F2FE9BULL, 0x08DE8A1C7797DA9BULL, 0x8F9887E6078735A1ULL, 0xB5B4071DBFC73A66ULL, 0x230E343DFBA08D33ULL, 0x43ED7F5A0FAE657DULL, 0x3A88A0FBBCB05C63ULL, 0x21874B8B4D2DBC4FULL, 0x1BDEA12E35F6A8C9ULL, 0x53C065C6C8E63528ULL, 0xE34A1D250E7A8D6BULL, 0xD6B04D3B7651DD7EULL, 0x5E90277E7CB39E2DULL, 0x2C046F22062DC67DULL, 0xB10BB459132D0A26ULL, 0x3FA9DDFB67E2F199ULL, 0x0E09B88E1914F7AFULL, 0x10E8B35AF3EEAB37ULL, 0x9EEDECA8E272B933ULL, 0xD4C718BC4AE8AE5FULL, 0x81536D601170FC20ULL, 0x91B534F885818A06ULL, 0xEC8177F83F900978ULL, 0x190E714FADA5156EULL, 0xB592BF39B0364963ULL, 0x89C350C893AE7DC1ULL, 0xAC042E70F8B383F2ULL, 0xB49B52E587A1EE60ULL, 0xFB152FE3FF26DA89ULL, 0x3E666E6F69AE2C15ULL, 0x3B544EBE544C19F9ULL, 0xE805A1E290CF2456ULL, 0x24B33C9D7ED25117ULL, 0xE74733427B72F0C1ULL, 0x0A804D18B7097475ULL, 0x57E3306D881EDB4FULL, 0x4AE7D6A36EB5DBCBULL, 0x2D8D5432157064C8ULL, 0xD1E649DE1E7F268BULL, 0x8A328A1CEDFE552CULL, 0x07A3AEC79624C7DAULL, 0x84547DDC3E203C94ULL, 0x990A98FD5071D263ULL, 0x1A4FF12616EEFC89ULL, 0xF6F7FD1431714200ULL, 0x30C05B1BA332F41CULL, 0x8D2636B81555A786ULL, 0x46C9FEB55D120902ULL, 0xCCEC0A73B49C9921ULL, 0x4E9D2827355FC492ULL, 0x19EBB029435DCB0FULL, 0x4659D2B743848A2CULL, 0x963EF2C96B33BE31ULL, 0x74F85198B05A2E7DULL, 0x5A0F544DD2B1FB18ULL, 0x03727073C2E134B1ULL, 0xC7F6AA2DE59AEA61ULL, 0x352787BAA0D7C22FULL, 0x9853EAB63B5E0B35ULL, 0xABBDCDD7ED5C0860ULL, 0xCF05DAF5AC8D77B0ULL, 0x49CAD48CEBF4A71EULL, 0x7A4C10EC2158C4A6ULL, 0xD9E92AA246BF719EULL, 0x13AE978D09FE5557ULL, 0x730499AF921549FFULL, 0x4E4B705B92903BA4ULL, 0xFF577222C14F0A3AULL, 0x55B6344CF97AAFAEULL, 0xB862225B055B6960ULL, 0xCAC09AFBDDD2CDB4ULL, 0xDAF8E9829FE96B5FULL, 0xB5FDFC5D3132C498ULL, 0x310CB380DB6F7503ULL, 0xE87FBB46217A360EULL, 0x2102AE466EBB1148ULL, 0xF8549E1A3AA5E00DULL, 0x07A69AFDCC42261AULL, 0xC4C118BFE78FEAAEULL, 0xF9F4892ED96BD438ULL, 0x1AF3DBE25D8F45DAULL, 0xF5B4B0B0D2DEEEB4ULL, 0x962ACEEFA82E1C84ULL, 0x046E3ECAAF453CE9ULL, 0xF05D129681949A4CULL, 0x964781CE734B3C84ULL, 0x9C2ED44081CE5FBDULL, 0x522E23F3925E319EULL, 0x177E00F9FC32F791ULL, 0x2BC60A63A6F3B3F2ULL, 0x222BBFAE61725606ULL, 0x486289DDCC3D6780ULL, 0x7DC7785B8EFDFC80ULL, 0x8AF38731C02BA980ULL, 0x1FAB64EA29A2DDF7ULL, 0xE4D9429322CD065AULL, 0x9DA058C67844F20CULL, 0x24C0E332B70019B0ULL, 0x233003B5A6CFE6ADULL, 0xD586BD01C5C217F6ULL, 0x5E5637885F29BC2BULL, 0x7EBA726D8C94094BULL, 0x0A56A5F0BFE39272ULL, 0xD79476A84EE20D06ULL, 0x9E4C1269BAA4BF37ULL, 0x17EFEE45B0DEE640ULL, 0x1D95B0A5FCF90BC6ULL, 0x93CBE0B699C2585DULL, 0x65FA4F227A2B6D79ULL, 0xD5F9E858292504D5ULL, 0xC2B5A03F71471A6FULL, 0x59300222B4561E00ULL, 0xCE2F8642CA0712DCULL, 0x7CA9723FBB2E8988ULL, 0x2785338347F2BA08ULL, 0xC61BB3A141E50E8CULL, 0x150F361DAB9DEC26ULL, 0x9F6A419D382595F4ULL, 0x64A53DC924FE7AC9ULL, 0x142DE49FFF7A7C3DULL, 0x0C335248857FA9E7ULL, 0x0A9C32D5EAE45305ULL, 0xE6C42178C4BBB92EULL, 0x71F1CE2490D20B07ULL, 0xF1BCC3D275AFE51AULL, 0xE728E8C83C334074ULL, 0x96FBF83A12884624ULL, 0x81A1549FD6573DA5ULL, 0x5FA7867CAF35E149ULL, 0x56986E2EF3ED091BULL, 0x917F1DD5F8886C61ULL, 0xD20D8C88C8FFE65FULL, 0x31D71DCE64B2C310ULL, 0xF165B587DF898190ULL, 0xA57E6339DD2CF3A0ULL, 0x1EF6E6DBB1961EC9ULL, 0x70CC73D90BC26E24ULL, 0xE21A6B35DF0C3AD7ULL, 0x003A93D8B2806962ULL, 0x1C99DED33CB890A1ULL, 0xCF3145DE0ADD4289ULL, 0xD0E4427A5514FB72ULL, 0x77C621CC9FB3A483ULL, 0x67A34DAC4356550BULL, 0xF8D626AAAF278509ULL }}; // polyglot_key() returns the PolyGlot hash key of the given position Key polyglot_key(const Position& pos) { Key key = 0; Bitboard b = pos.pieces(); while (b) { Square s = pop_lsb(&b); Piece p = pos.piece_on(s); // PolyGlot pieces are: BP = 0, WP = 1, BN = 2, ... BK = 10, WK = 11 key ^= PG.Zobrist.psq[2 * (type_of(p) - 1) + (color_of(p) == WHITE)][s]; } b = pos.can_castle(ALL_CASTLES); while (b) key ^= PG.Zobrist.castle[pop_lsb(&b)]; if (pos.ep_square() != SQ_NONE) key ^= PG.Zobrist.enpassant[file_of(pos.ep_square())]; if (pos.side_to_move() == WHITE) key ^= PG.Zobrist.turn; return key; } } // namespace PolyglotBook::PolyglotBook() : rkiss(Time::now() % 10000) {} PolyglotBook::~PolyglotBook() { if (is_open()) close(); } /// operator>>() reads sizeof(T) chars from the file's binary byte stream and /// converts them in a number of type T. A Polyglot book stores numbers in /// big-endian format. template PolyglotBook& PolyglotBook::operator>>(T& n) { n = 0; for (size_t i = 0; i < sizeof(T); i++) n = T((n << 8) + ifstream::get()); return *this; } template<> PolyglotBook& PolyglotBook::operator>>(Entry& e) { return *this >> e.key >> e.move >> e.count >> e.learn; } /// open() tries to open a book file with the given name after closing any /// exsisting one. bool PolyglotBook::open(const char* fName) { if (is_open()) // Cannot close an already closed file close(); ifstream::open(fName, ifstream::in | ifstream::binary); fileName = is_open() ? fName : ""; ifstream::clear(); // Reset any error flag to allow retry ifstream::open() return !fileName.empty(); } /// probe() tries to find a book move for the given position. If no move is /// found returns MOVE_NONE. If pickBest is true returns always the highest /// rated move, otherwise randomly chooses one, based on the move score. Move PolyglotBook::probe(const Position& pos, const string& fName, bool pickBest) { if (fileName != fName && !open(fName.c_str())) return MOVE_NONE; Entry e; uint16_t best = 0; unsigned sum = 0; Move move = MOVE_NONE; Key key = polyglot_key(pos); seekg(find_first(key) * sizeof(Entry), ios_base::beg); while (*this >> e, e.key == key && good()) { best = max(best, e.count); sum += e.count; // Choose book move according to its score. If a move has a very // high score it has higher probability to be choosen than a move // with lower score. Note that first entry is always chosen. if ( (sum && rkiss.rand() % sum < e.count) || (pickBest && e.count == best)) move = Move(e.move); } if (!move) return MOVE_NONE; // A PolyGlot book move is encoded as follows: // // bit 0- 5: destination square (from 0 to 63) // bit 6-11: origin square (from 0 to 63) // bit 12-14: promotion piece (from KNIGHT == 1 to QUEEN == 4) // // Castling moves follow "king captures rook" representation. So in case book // move is a promotion we have to convert to our representation, in all the // other cases we can directly compare with a Move after having masked out // the special Move's flags (bit 14-15) that are not supported by PolyGlot. int pt = (move >> 12) & 7; if (pt) move = make(from_sq(move), to_sq(move), PieceType(pt + 1)); // Add 'special move' flags and verify it is legal for (MoveList ml(pos); !ml.end(); ++ml) if (move == (ml.move() ^ type_of(ml.move()))) return ml.move(); return MOVE_NONE; } /// find_first() takes a book key as input, and does a binary search through /// the book file for the given key. Returns the index of the leftmost book /// entry with the same key as the input. size_t PolyglotBook::find_first(Key key) { seekg(0, ios::end); // Move pointer to end, so tellg() gets file's size size_t low = 0, mid, high = (size_t)tellg() / sizeof(Entry) - 1; Entry e; assert(low <= high); while (low < high && good()) { mid = (low + high) / 2; assert(mid >= low && mid < high); seekg(mid * sizeof(Entry), ios_base::beg); *this >> e; if (key <= e.key) high = mid; else low = mid + 1; } assert(low == high); return low; } stockfish-3.0.0+git20130508/src/position.cpp0000644000175000017500000014117512142540127017641 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include "bitcount.h" #include "movegen.h" #include "notation.h" #include "position.h" #include "psqtab.h" #include "rkiss.h" #include "thread.h" #include "tt.h" using std::string; using std::cout; using std::endl; static const string PieceToChar(" PNBRQK pnbrqk"); CACHE_LINE_ALIGNMENT Score pieceSquareTable[PIECE_NB][SQUARE_NB]; Value PieceValue[PHASE_NB][PIECE_NB] = { { VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg }, { VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg } }; namespace Zobrist { Key psq[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB]; Key enpassant[FILE_NB]; Key castle[CASTLE_RIGHT_NB]; Key side; Key exclusion; /// init() initializes at startup the various arrays used to compute hash keys /// and the piece square tables. The latter is a two-step operation: First, the /// white halves of the tables are copied from PSQT[] tables. Second, the black /// halves of the tables are initialized by flipping and changing the sign of /// the white scores. void init() { RKISS rk; for (Color c = WHITE; c <= BLACK; c++) for (PieceType pt = PAWN; pt <= KING; pt++) for (Square s = SQ_A1; s <= SQ_H8; s++) psq[c][pt][s] = rk.rand(); for (File f = FILE_A; f <= FILE_H; f++) enpassant[f] = rk.rand(); for (int cr = CASTLES_NONE; cr <= ALL_CASTLES; cr++) { Bitboard b = cr; while (b) { Key k = castle[1ULL << pop_lsb(&b)]; castle[cr] ^= k ? k : rk.rand(); } } side = rk.rand(); exclusion = rk.rand(); for (PieceType pt = PAWN; pt <= KING; pt++) { PieceValue[MG][make_piece(BLACK, pt)] = PieceValue[MG][pt]; PieceValue[EG][make_piece(BLACK, pt)] = PieceValue[EG][pt]; Score v = make_score(PieceValue[MG][pt], PieceValue[EG][pt]); for (Square s = SQ_A1; s <= SQ_H8; s++) { pieceSquareTable[make_piece(WHITE, pt)][ s] = (v + PSQT[pt][s]); pieceSquareTable[make_piece(BLACK, pt)][~s] = -(v + PSQT[pt][s]); } } } } // namespace Zobrist namespace { /// next_attacker() is an helper function used by see() to locate the least /// valuable attacker for the side to move, remove the attacker we just found /// from the 'occupied' bitboard and scan for new X-ray attacks behind it. template FORCE_INLINE PieceType next_attacker(const Bitboard* bb, const Square& to, const Bitboard& stmAttackers, Bitboard& occupied, Bitboard& attackers) { if (stmAttackers & bb[Pt]) { Bitboard b = stmAttackers & bb[Pt]; occupied ^= b & ~(b - 1); if (Pt == PAWN || Pt == BISHOP || Pt == QUEEN) attackers |= attacks_bb(to, occupied) & (bb[BISHOP] | bb[QUEEN]); if (Pt == ROOK || Pt == QUEEN) attackers |= attacks_bb(to, occupied) & (bb[ROOK] | bb[QUEEN]); return (PieceType)Pt; } return next_attacker(bb, to, stmAttackers, occupied, attackers); } template<> FORCE_INLINE PieceType next_attacker(const Bitboard*, const Square&, const Bitboard&, Bitboard&, Bitboard&) { return KING; // No need to update bitboards, it is the last cycle } } // namespace /// CheckInfo c'tor CheckInfo::CheckInfo(const Position& pos) { Color them = ~pos.side_to_move(); ksq = pos.king_square(them); pinned = pos.pinned_pieces(); dcCandidates = pos.discovered_check_candidates(); checkSq[PAWN] = pos.attacks_from(ksq, them); checkSq[KNIGHT] = pos.attacks_from(ksq); checkSq[BISHOP] = pos.attacks_from(ksq); checkSq[ROOK] = pos.attacks_from(ksq); checkSq[QUEEN] = checkSq[BISHOP] | checkSq[ROOK]; checkSq[KING] = 0; } /// Position::operator=() creates a copy of 'pos'. We want the new born Position /// object do not depend on any external data so we detach state pointer from /// the source one. Position& Position::operator=(const Position& pos) { memcpy(this, &pos, sizeof(Position)); startState = *st; st = &startState; nodes = 0; assert(pos_is_ok()); return *this; } /// Position::set() initializes the position object with the given FEN string. /// This function is not very robust - make sure that input FENs are correct, /// this is assumed to be the responsibility of the GUI. void Position::set(const string& fenStr, bool isChess960, Thread* th) { /* A FEN string defines a particular position using only the ASCII character set. A FEN string contains six fields separated by a space. The fields are: 1) Piece placement (from white's perspective). Each rank is described, starting with rank 8 and ending with rank 1; within each rank, the contents of each square are described from file A through file H. Following the Standard Algebraic Notation (SAN), each piece is identified by a single letter taken from the standard English names. White pieces are designated using upper-case letters ("PNBRQK") while Black take lowercase ("pnbrqk"). Blank squares are noted using digits 1 through 8 (the number of blank squares), and "/" separates ranks. 2) Active color. "w" means white moves next, "b" means black. 3) Castling availability. If neither side can castle, this is "-". Otherwise, this has one or more letters: "K" (White can castle kingside), "Q" (White can castle queenside), "k" (Black can castle kingside), and/or "q" (Black can castle queenside). 4) En passant target square (in algebraic notation). If there's no en passant target square, this is "-". If a pawn has just made a 2-square move, this is the position "behind" the pawn. This is recorded regardless of whether there is a pawn in position to make an en passant capture. 5) Halfmove clock. This is the number of halfmoves since the last pawn advance or capture. This is used to determine if a draw can be claimed under the fifty-move rule. 6) Fullmove number. The number of the full move. It starts at 1, and is incremented after Black's move. */ char col, row, token; size_t p; Square sq = SQ_A8; std::istringstream ss(fenStr); clear(); ss >> std::noskipws; // 1. Piece placement while ((ss >> token) && !isspace(token)) { if (isdigit(token)) sq += Square(token - '0'); // Advance the given number of files else if (token == '/') sq -= Square(16); else if ((p = PieceToChar.find(token)) != string::npos) { put_piece(Piece(p), sq); sq++; } } // 2. Active color ss >> token; sideToMove = (token == 'w' ? WHITE : BLACK); ss >> token; // 3. Castling availability. Compatible with 3 standards: Normal FEN standard, // Shredder-FEN that uses the letters of the columns on which the rooks began // the game instead of KQkq and also X-FEN standard that, in case of Chess960, // if an inner rook is associated with the castling right, the castling tag is // replaced by the file letter of the involved rook, as for the Shredder-FEN. while ((ss >> token) && !isspace(token)) { Square rsq; Color c = islower(token) ? BLACK : WHITE; token = char(toupper(token)); if (token == 'K') for (rsq = relative_square(c, SQ_H1); type_of(piece_on(rsq)) != ROOK; rsq--) {} else if (token == 'Q') for (rsq = relative_square(c, SQ_A1); type_of(piece_on(rsq)) != ROOK; rsq++) {} else if (token >= 'A' && token <= 'H') rsq = File(token - 'A') | relative_rank(c, RANK_1); else continue; set_castle_right(c, rsq); } // 4. En passant square. Ignore if no pawn capture is possible if ( ((ss >> col) && (col >= 'a' && col <= 'h')) && ((ss >> row) && (row == '3' || row == '6'))) { st->epSquare = File(col - 'a') | Rank(row - '1'); if (!(attackers_to(st->epSquare) & pieces(sideToMove, PAWN))) st->epSquare = SQ_NONE; } // 5-6. Halfmove clock and fullmove number ss >> std::skipws >> st->rule50 >> gamePly; // Convert from fullmove starting from 1 to ply starting from 0, // handle also common incorrect FEN with fullmove = 0. gamePly = std::max(2 * (gamePly - 1), 0) + int(sideToMove == BLACK); st->key = compute_key(); st->pawnKey = compute_pawn_key(); st->materialKey = compute_material_key(); st->psqScore = compute_psq_score(); st->npMaterial[WHITE] = compute_non_pawn_material(WHITE); st->npMaterial[BLACK] = compute_non_pawn_material(BLACK); st->checkersBB = attackers_to(king_square(sideToMove)) & pieces(~sideToMove); chess960 = isChess960; thisThread = th; assert(pos_is_ok()); } /// Position::set_castle_right() is an helper function used to set castling /// rights given the corresponding color and the rook starting square. void Position::set_castle_right(Color c, Square rfrom) { Square kfrom = king_square(c); CastlingSide cs = kfrom < rfrom ? KING_SIDE : QUEEN_SIDE; CastleRight cr = make_castle_right(c, cs); st->castleRights |= cr; castleRightsMask[kfrom] |= cr; castleRightsMask[rfrom] |= cr; castleRookSquare[c][cs] = rfrom; Square kto = relative_square(c, cs == KING_SIDE ? SQ_G1 : SQ_C1); Square rto = relative_square(c, cs == KING_SIDE ? SQ_F1 : SQ_D1); for (Square s = std::min(rfrom, rto); s <= std::max(rfrom, rto); s++) if (s != kfrom && s != rfrom) castlePath[c][cs] |= s; for (Square s = std::min(kfrom, kto); s <= std::max(kfrom, kto); s++) if (s != kfrom && s != rfrom) castlePath[c][cs] |= s; } /// Position::fen() returns a FEN representation of the position. In case /// of Chess960 the Shredder-FEN notation is used. Mainly a debugging function. const string Position::fen() const { std::ostringstream ss; for (Rank rank = RANK_8; rank >= RANK_1; rank--) { for (File file = FILE_A; file <= FILE_H; file++) { Square sq = file | rank; if (is_empty(sq)) { int emptyCnt = 1; for ( ; file < FILE_H && is_empty(sq++); file++) emptyCnt++; ss << emptyCnt; } else ss << PieceToChar[piece_on(sq)]; } if (rank > RANK_1) ss << '/'; } ss << (sideToMove == WHITE ? " w " : " b "); if (can_castle(WHITE_OO)) ss << (chess960 ? file_to_char(file_of(castle_rook_square(WHITE, KING_SIDE)), false) : 'K'); if (can_castle(WHITE_OOO)) ss << (chess960 ? file_to_char(file_of(castle_rook_square(WHITE, QUEEN_SIDE)), false) : 'Q'); if (can_castle(BLACK_OO)) ss << (chess960 ? file_to_char(file_of(castle_rook_square(BLACK, KING_SIDE)), true) : 'k'); if (can_castle(BLACK_OOO)) ss << (chess960 ? file_to_char(file_of(castle_rook_square(BLACK, QUEEN_SIDE)), true) : 'q'); if (st->castleRights == CASTLES_NONE) ss << '-'; ss << (ep_square() == SQ_NONE ? " - " : " " + square_to_string(ep_square()) + " ") << st->rule50 << " " << 1 + (gamePly - int(sideToMove == BLACK)) / 2; return ss.str(); } /// Position::pretty() returns an ASCII representation of the position to be /// printed to the standard output together with the move's san notation. const string Position::pretty(Move move) const { const string dottedLine = "\n+---+---+---+---+---+---+---+---+"; const string twoRows = dottedLine + "\n| | . | | . | | . | | . |" + dottedLine + "\n| . | | . | | . | | . | |"; string brd = twoRows + twoRows + twoRows + twoRows + dottedLine; std::ostringstream ss; if (move) ss << "\nMove: " << (sideToMove == BLACK ? ".." : "") << move_to_san(*const_cast(this), move); for (Square sq = SQ_A1; sq <= SQ_H8; sq++) if (piece_on(sq) != NO_PIECE) brd[513 - 68*rank_of(sq) + 4*file_of(sq)] = PieceToChar[piece_on(sq)]; ss << brd << "\nFen: " << fen() << "\nKey: " << std::hex << std::uppercase << std::setfill('0') << std::setw(16) << st->key << "\nCheckers: "; for (Bitboard b = checkers(); b; ) ss << square_to_string(pop_lsb(&b)) << " "; ss << "\nLegal moves: "; for (MoveList ml(*this); !ml.end(); ++ml) ss << move_to_san(*const_cast(this), ml.move()) << " "; return ss.str(); } /// Position:hidden_checkers<>() returns a bitboard of all pinned (against the /// king) pieces for the given color. Or, when template parameter FindPinned is /// false, the function return the pieces of the given color candidate for a /// discovery check against the enemy king. template Bitboard Position::hidden_checkers() const { // Pinned pieces protect our king, dicovery checks attack the enemy king Bitboard b, result = 0; Bitboard pinners = pieces(FindPinned ? ~sideToMove : sideToMove); Square ksq = king_square(FindPinned ? sideToMove : ~sideToMove); // Pinners are sliders, that give check when candidate pinned is removed pinners &= (pieces(ROOK, QUEEN) & PseudoAttacks[ROOK][ksq]) | (pieces(BISHOP, QUEEN) & PseudoAttacks[BISHOP][ksq]); while (pinners) { b = between_bb(ksq, pop_lsb(&pinners)) & pieces(); if (b && !more_than_one(b) && (b & pieces(sideToMove))) result |= b; } return result; } // Explicit template instantiations template Bitboard Position::hidden_checkers() const; template Bitboard Position::hidden_checkers() const; /// Position::attackers_to() computes a bitboard of all pieces which attack a /// given square. Slider attacks use occ bitboard as occupancy. Bitboard Position::attackers_to(Square s, Bitboard occ) const { return (attacks_from(s, BLACK) & pieces(WHITE, PAWN)) | (attacks_from(s, WHITE) & pieces(BLACK, PAWN)) | (attacks_from(s) & pieces(KNIGHT)) | (attacks_bb(s, occ) & pieces(ROOK, QUEEN)) | (attacks_bb(s, occ) & pieces(BISHOP, QUEEN)) | (attacks_from(s) & pieces(KING)); } /// Position::attacks_from() computes a bitboard of all attacks of a given piece /// put in a given square. Slider attacks use occ bitboard as occupancy. Bitboard Position::attacks_from(Piece p, Square s, Bitboard occ) { assert(is_ok(s)); switch (type_of(p)) { case BISHOP: return attacks_bb(s, occ); case ROOK : return attacks_bb(s, occ); case QUEEN : return attacks_bb(s, occ) | attacks_bb(s, occ); default : return StepAttacksBB[p][s]; } } /// Position::pl_move_is_legal() tests whether a pseudo-legal move is legal bool Position::pl_move_is_legal(Move m, Bitboard pinned) const { assert(is_ok(m)); assert(pinned == pinned_pieces()); Color us = sideToMove; Square from = from_sq(m); assert(color_of(piece_moved(m)) == us); assert(piece_on(king_square(us)) == make_piece(us, KING)); // En passant captures are a tricky special case. Because they are rather // uncommon, we do it simply by testing whether the king is attacked after // the move is made. if (type_of(m) == ENPASSANT) { Color them = ~us; Square to = to_sq(m); Square capsq = to + pawn_push(them); Square ksq = king_square(us); Bitboard b = (pieces() ^ from ^ capsq) | to; assert(to == ep_square()); assert(piece_moved(m) == make_piece(us, PAWN)); assert(piece_on(capsq) == make_piece(them, PAWN)); assert(piece_on(to) == NO_PIECE); return !(attacks_bb< ROOK>(ksq, b) & pieces(them, QUEEN, ROOK)) && !(attacks_bb(ksq, b) & pieces(them, QUEEN, BISHOP)); } // If the moving piece is a king, check whether the destination // square is attacked by the opponent. Castling moves are checked // for legality during move generation. if (type_of(piece_on(from)) == KING) return type_of(m) == CASTLE || !(attackers_to(to_sq(m)) & pieces(~us)); // A non-king move is legal if and only if it is not pinned or it // is moving along the ray towards or away from the king. return !pinned || !(pinned & from) || squares_aligned(from, to_sq(m), king_square(us)); } /// Position::is_pseudo_legal() takes a random move and tests whether the move /// is pseudo legal. It is used to validate moves from TT that can be corrupted /// due to SMP concurrent access or hash position key aliasing. bool Position::is_pseudo_legal(const Move m) const { Color us = sideToMove; Square from = from_sq(m); Square to = to_sq(m); Piece pc = piece_moved(m); // Use a slower but simpler function for uncommon cases if (type_of(m) != NORMAL) return MoveList(*this).contains(m); // Is not a promotion, so promotion piece must be empty if (promotion_type(m) - 2 != NO_PIECE_TYPE) return false; // If the from square is not occupied by a piece belonging to the side to // move, the move is obviously not legal. if (pc == NO_PIECE || color_of(pc) != us) return false; // The destination square cannot be occupied by a friendly piece if (piece_on(to) != NO_PIECE && color_of(piece_on(to)) == us) return false; // Handle the special case of a pawn move if (type_of(pc) == PAWN) { // Move direction must be compatible with pawn color int direction = to - from; if ((us == WHITE) != (direction > 0)) return false; // We have already handled promotion moves, so destination // cannot be on the 8/1th rank. if (rank_of(to) == RANK_8 || rank_of(to) == RANK_1) return false; // Proceed according to the square delta between the origin and // destination squares. switch (direction) { case DELTA_NW: case DELTA_NE: case DELTA_SW: case DELTA_SE: // Capture. The destination square must be occupied by an enemy // piece (en passant captures was handled earlier). if (piece_on(to) == NO_PIECE || color_of(piece_on(to)) != ~us) return false; // From and to files must be one file apart, avoids a7h5 if (abs(file_of(from) - file_of(to)) != 1) return false; break; case DELTA_N: case DELTA_S: // Pawn push. The destination square must be empty. if (!is_empty(to)) return false; break; case DELTA_NN: // Double white pawn push. The destination square must be on the fourth // rank, and both the destination square and the square between the // source and destination squares must be empty. if ( rank_of(to) != RANK_4 || !is_empty(to) || !is_empty(from + DELTA_N)) return false; break; case DELTA_SS: // Double black pawn push. The destination square must be on the fifth // rank, and both the destination square and the square between the // source and destination squares must be empty. if ( rank_of(to) != RANK_5 || !is_empty(to) || !is_empty(from + DELTA_S)) return false; break; default: return false; } } else if (!(attacks_from(pc, from) & to)) return false; // Evasions generator already takes care to avoid some kind of illegal moves // and pl_move_is_legal() relies on this. So we have to take care that the // same kind of moves are filtered out here. if (checkers()) { if (type_of(pc) != KING) { // Double check? In this case a king move is required if (more_than_one(checkers())) return false; // Our move must be a blocking evasion or a capture of the checking piece if (!((between_bb(lsb(checkers()), king_square(us)) | checkers()) & to)) return false; } // In case of king moves under check we have to remove king so to catch // as invalid moves like b1a1 when opposite queen is on c1. else if (attackers_to(to, pieces() ^ from) & pieces(~us)) return false; } return true; } /// Position::move_gives_check() tests whether a pseudo-legal move gives a check bool Position::move_gives_check(Move m, const CheckInfo& ci) const { assert(is_ok(m)); assert(ci.dcCandidates == discovered_check_candidates()); assert(color_of(piece_moved(m)) == sideToMove); Square from = from_sq(m); Square to = to_sq(m); PieceType pt = type_of(piece_on(from)); // Direct check ? if (ci.checkSq[pt] & to) return true; // Discovery check ? if (ci.dcCandidates && (ci.dcCandidates & from)) { // For pawn and king moves we need to verify also direction if ( (pt != PAWN && pt != KING) || !squares_aligned(from, to, king_square(~sideToMove))) return true; } // Can we skip the ugly special cases ? if (type_of(m) == NORMAL) return false; Color us = sideToMove; Square ksq = king_square(~us); switch (type_of(m)) { case PROMOTION: return attacks_from(Piece(promotion_type(m)), to, pieces() ^ from) & ksq; // En passant capture with check ? We have already handled the case // of direct checks and ordinary discovered check, the only case we // need to handle is the unusual case of a discovered check through // the captured pawn. case ENPASSANT: { Square capsq = file_of(to) | rank_of(from); Bitboard b = (pieces() ^ from ^ capsq) | to; return (attacks_bb< ROOK>(ksq, b) & pieces(us, QUEEN, ROOK)) | (attacks_bb(ksq, b) & pieces(us, QUEEN, BISHOP)); } case CASTLE: { Square kfrom = from; Square rfrom = to; // 'King captures the rook' notation Square kto = relative_square(us, rfrom > kfrom ? SQ_G1 : SQ_C1); Square rto = relative_square(us, rfrom > kfrom ? SQ_F1 : SQ_D1); Bitboard b = (pieces() ^ kfrom ^ rfrom) | rto | kto; return attacks_bb(rto, b) & ksq; } default: assert(false); return false; } } /// Position::do_move() makes a move, and saves all information necessary /// to a StateInfo object. The move is assumed to be legal. Pseudo-legal /// moves should be filtered out before this function is called. void Position::do_move(Move m, StateInfo& newSt) { CheckInfo ci(*this); do_move(m, newSt, ci, move_gives_check(m, ci)); } void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveIsCheck) { assert(is_ok(m)); assert(&newSt != st); nodes++; Key k = st->key; // Copy some fields of old state to our new StateInfo object except the ones // which are going to be recalculated from scratch anyway, then switch our state // pointer to point to the new, ready to be updated, state. memcpy(&newSt, st, StateCopySize64 * sizeof(uint64_t)); newSt.previous = st; st = &newSt; // Update side to move k ^= Zobrist::side; // Increment ply counters.In particular rule50 will be later reset it to zero // in case of a capture or a pawn move. gamePly++; st->rule50++; st->pliesFromNull++; Color us = sideToMove; Color them = ~us; Square from = from_sq(m); Square to = to_sq(m); Piece piece = piece_on(from); PieceType pt = type_of(piece); PieceType capture = type_of(m) == ENPASSANT ? PAWN : type_of(piece_on(to)); assert(color_of(piece) == us); assert(piece_on(to) == NO_PIECE || color_of(piece_on(to)) == them || type_of(m) == CASTLE); assert(capture != KING); if (type_of(m) == CASTLE) { assert(piece == make_piece(us, KING)); bool kingSide = to > from; Square rfrom = to; // Castle is encoded as "king captures friendly rook" Square rto = relative_square(us, kingSide ? SQ_F1 : SQ_D1); to = relative_square(us, kingSide ? SQ_G1 : SQ_C1); capture = NO_PIECE_TYPE; do_castle(from, to, rfrom, rto); st->psqScore += psq_delta(make_piece(us, ROOK), rfrom, rto); k ^= Zobrist::psq[us][ROOK][rfrom] ^ Zobrist::psq[us][ROOK][rto]; } if (capture) { Square capsq = to; // If the captured piece is a pawn, update pawn hash key, otherwise // update non-pawn material. if (capture == PAWN) { if (type_of(m) == ENPASSANT) { capsq += pawn_push(them); assert(pt == PAWN); assert(to == st->epSquare); assert(relative_rank(us, to) == RANK_6); assert(piece_on(to) == NO_PIECE); assert(piece_on(capsq) == make_piece(them, PAWN)); board[capsq] = NO_PIECE; } st->pawnKey ^= Zobrist::psq[them][PAWN][capsq]; } else st->npMaterial[them] -= PieceValue[MG][capture]; // Remove the captured piece byTypeBB[ALL_PIECES] ^= capsq; byTypeBB[capture] ^= capsq; byColorBB[them] ^= capsq; // Update piece list, move the last piece at index[capsq] position and // shrink the list. // // WARNING: This is a not reversible operation. When we will reinsert the // captured piece in undo_move() we will put it at the end of the list and // not in its original place, it means index[] and pieceList[] are not // guaranteed to be invariant to a do_move() + undo_move() sequence. Square lastSquare = pieceList[them][capture][--pieceCount[them][capture]]; index[lastSquare] = index[capsq]; pieceList[them][capture][index[lastSquare]] = lastSquare; pieceList[them][capture][pieceCount[them][capture]] = SQ_NONE; // Update material hash key and prefetch access to materialTable k ^= Zobrist::psq[them][capture][capsq]; st->materialKey ^= Zobrist::psq[them][capture][pieceCount[them][capture]]; prefetch((char*)thisThread->materialTable[st->materialKey]); // Update incremental scores st->psqScore -= pieceSquareTable[make_piece(them, capture)][capsq]; // Reset rule 50 counter st->rule50 = 0; } // Update hash key k ^= Zobrist::psq[us][pt][from] ^ Zobrist::psq[us][pt][to]; // Reset en passant square if (st->epSquare != SQ_NONE) { k ^= Zobrist::enpassant[file_of(st->epSquare)]; st->epSquare = SQ_NONE; } // Update castle rights if needed if (st->castleRights && (castleRightsMask[from] | castleRightsMask[to])) { int cr = castleRightsMask[from] | castleRightsMask[to]; k ^= Zobrist::castle[st->castleRights & cr]; st->castleRights &= ~cr; } // Prefetch TT access as soon as we know the new hash key prefetch((char*)TT.first_entry(k)); // Move the piece. The tricky Chess960 castle is handled earlier if (type_of(m) != CASTLE) { Bitboard from_to_bb = SquareBB[from] ^ SquareBB[to]; byTypeBB[ALL_PIECES] ^= from_to_bb; byTypeBB[pt] ^= from_to_bb; byColorBB[us] ^= from_to_bb; board[from] = NO_PIECE; board[to] = piece; // Update piece lists, index[from] is not updated and becomes stale. This // works as long as index[] is accessed just by known occupied squares. index[to] = index[from]; pieceList[us][pt][index[to]] = to; } // If the moving piece is a pawn do some special extra work if (pt == PAWN) { // Set en-passant square, only if moved pawn can be captured if ( (int(to) ^ int(from)) == 16 && (attacks_from(from + pawn_push(us), us) & pieces(them, PAWN))) { st->epSquare = Square((from + to) / 2); k ^= Zobrist::enpassant[file_of(st->epSquare)]; } if (type_of(m) == PROMOTION) { PieceType promotion = promotion_type(m); assert(relative_rank(us, to) == RANK_8); assert(promotion >= KNIGHT && promotion <= QUEEN); // Replace the pawn with the promoted piece byTypeBB[PAWN] ^= to; byTypeBB[promotion] |= to; board[to] = make_piece(us, promotion); // Update piece lists, move the last pawn at index[to] position // and shrink the list. Add a new promotion piece to the list. Square lastSquare = pieceList[us][PAWN][--pieceCount[us][PAWN]]; index[lastSquare] = index[to]; pieceList[us][PAWN][index[lastSquare]] = lastSquare; pieceList[us][PAWN][pieceCount[us][PAWN]] = SQ_NONE; index[to] = pieceCount[us][promotion]; pieceList[us][promotion][index[to]] = to; // Update hash keys k ^= Zobrist::psq[us][PAWN][to] ^ Zobrist::psq[us][promotion][to]; st->pawnKey ^= Zobrist::psq[us][PAWN][to]; st->materialKey ^= Zobrist::psq[us][promotion][pieceCount[us][promotion]++] ^ Zobrist::psq[us][PAWN][pieceCount[us][PAWN]]; // Update incremental score st->psqScore += pieceSquareTable[make_piece(us, promotion)][to] - pieceSquareTable[make_piece(us, PAWN)][to]; // Update material st->npMaterial[us] += PieceValue[MG][promotion]; } // Update pawn hash key and prefetch access to pawnsTable st->pawnKey ^= Zobrist::psq[us][PAWN][from] ^ Zobrist::psq[us][PAWN][to]; prefetch((char*)thisThread->pawnsTable[st->pawnKey]); // Reset rule 50 draw counter st->rule50 = 0; } // Update incremental scores st->psqScore += psq_delta(piece, from, to); // Set capture piece st->capturedType = capture; // Update the key with the final value st->key = k; // Update checkers bitboard, piece must be already moved st->checkersBB = 0; if (moveIsCheck) { if (type_of(m) != NORMAL) st->checkersBB = attackers_to(king_square(them)) & pieces(us); else { // Direct checks if (ci.checkSq[pt] & to) st->checkersBB |= to; // Discovery checks if (ci.dcCandidates && (ci.dcCandidates & from)) { if (pt != ROOK) st->checkersBB |= attacks_from(king_square(them)) & pieces(us, QUEEN, ROOK); if (pt != BISHOP) st->checkersBB |= attacks_from(king_square(them)) & pieces(us, QUEEN, BISHOP); } } } sideToMove = ~sideToMove; assert(pos_is_ok()); } /// Position::undo_move() unmakes a move. When it returns, the position should /// be restored to exactly the same state as before the move was made. void Position::undo_move(Move m) { assert(is_ok(m)); sideToMove = ~sideToMove; Color us = sideToMove; Color them = ~us; Square from = from_sq(m); Square to = to_sq(m); PieceType pt = type_of(piece_on(to)); PieceType capture = st->capturedType; assert(is_empty(from) || type_of(m) == CASTLE); assert(capture != KING); if (type_of(m) == PROMOTION) { PieceType promotion = promotion_type(m); assert(promotion == pt); assert(relative_rank(us, to) == RANK_8); assert(promotion >= KNIGHT && promotion <= QUEEN); // Replace the promoted piece with the pawn byTypeBB[promotion] ^= to; byTypeBB[PAWN] |= to; board[to] = make_piece(us, PAWN); // Update piece lists, move the last promoted piece at index[to] position // and shrink the list. Add a new pawn to the list. Square lastSquare = pieceList[us][promotion][--pieceCount[us][promotion]]; index[lastSquare] = index[to]; pieceList[us][promotion][index[lastSquare]] = lastSquare; pieceList[us][promotion][pieceCount[us][promotion]] = SQ_NONE; index[to] = pieceCount[us][PAWN]++; pieceList[us][PAWN][index[to]] = to; pt = PAWN; } if (type_of(m) == CASTLE) { bool kingSide = to > from; Square rfrom = to; // Castle is encoded as "king captures friendly rook" Square rto = relative_square(us, kingSide ? SQ_F1 : SQ_D1); to = relative_square(us, kingSide ? SQ_G1 : SQ_C1); capture = NO_PIECE_TYPE; pt = KING; do_castle(to, from, rto, rfrom); } else { // Put the piece back at the source square Bitboard from_to_bb = SquareBB[from] ^ SquareBB[to]; byTypeBB[ALL_PIECES] ^= from_to_bb; byTypeBB[pt] ^= from_to_bb; byColorBB[us] ^= from_to_bb; board[to] = NO_PIECE; board[from] = make_piece(us, pt); // Update piece lists, index[to] is not updated and becomes stale. This // works as long as index[] is accessed just by known occupied squares. index[from] = index[to]; pieceList[us][pt][index[from]] = from; } if (capture) { Square capsq = to; if (type_of(m) == ENPASSANT) { capsq -= pawn_push(us); assert(pt == PAWN); assert(to == st->previous->epSquare); assert(relative_rank(us, to) == RANK_6); assert(piece_on(capsq) == NO_PIECE); } // Restore the captured piece byTypeBB[ALL_PIECES] |= capsq; byTypeBB[capture] |= capsq; byColorBB[them] |= capsq; board[capsq] = make_piece(them, capture); // Update piece list, add a new captured piece in capsq square index[capsq] = pieceCount[them][capture]++; pieceList[them][capture][index[capsq]] = capsq; } // Finally point our state pointer back to the previous state st = st->previous; gamePly--; assert(pos_is_ok()); } /// Position::do_castle() is a helper used to do/undo a castling move. This /// is a bit tricky, especially in Chess960. void Position::do_castle(Square kfrom, Square kto, Square rfrom, Square rto) { Color us = sideToMove; Bitboard k_from_to_bb = SquareBB[kfrom] ^ SquareBB[kto]; Bitboard r_from_to_bb = SquareBB[rfrom] ^ SquareBB[rto]; byTypeBB[KING] ^= k_from_to_bb; byTypeBB[ROOK] ^= r_from_to_bb; byTypeBB[ALL_PIECES] ^= k_from_to_bb ^ r_from_to_bb; byColorBB[us] ^= k_from_to_bb ^ r_from_to_bb; // Could be from == to, so first set NO_PIECE then KING and ROOK board[kfrom] = board[rfrom] = NO_PIECE; board[kto] = make_piece(us, KING); board[rto] = make_piece(us, ROOK); // Could be kfrom == rto, so use a 'tmp' variable int tmp = index[kfrom]; index[rto] = index[rfrom]; index[kto] = tmp; pieceList[us][KING][index[kto]] = kto; pieceList[us][ROOK][index[rto]] = rto; } /// Position::do(undo)_null_move() is used to do(undo) a "null move": It flips /// the side to move without executing any move on the board. void Position::do_null_move(StateInfo& newSt) { assert(!checkers()); memcpy(&newSt, st, sizeof(StateInfo)); // Fully copy here newSt.previous = st; st = &newSt; if (st->epSquare != SQ_NONE) { st->key ^= Zobrist::enpassant[file_of(st->epSquare)]; st->epSquare = SQ_NONE; } st->key ^= Zobrist::side; prefetch((char*)TT.first_entry(st->key)); st->rule50++; st->pliesFromNull = 0; sideToMove = ~sideToMove; assert(pos_is_ok()); } void Position::undo_null_move() { assert(!checkers()); st = st->previous; sideToMove = ~sideToMove; } /// Position::see() is a static exchange evaluator: It tries to estimate the /// material gain or loss resulting from a move. Parameter 'asymmThreshold' takes /// tempi into account. If the side who initiated the capturing sequence does the /// last capture, he loses a tempo and if the result is below 'asymmThreshold' /// the capturing sequence is considered bad. int Position::see_sign(Move m) const { assert(is_ok(m)); // Early return if SEE cannot be negative because captured piece value // is not less then capturing one. Note that king moves always return // here because king midgame value is set to 0. if (PieceValue[MG][piece_on(to_sq(m))] >= PieceValue[MG][piece_moved(m)]) return 1; return see(m); } int Position::see(Move m, int asymmThreshold) const { Square from, to; Bitboard occupied, attackers, stmAttackers; int swapList[32], slIndex = 1; PieceType captured; Color stm; assert(is_ok(m)); from = from_sq(m); to = to_sq(m); captured = type_of(piece_on(to)); occupied = pieces() ^ from; // Handle en passant moves if (type_of(m) == ENPASSANT) { Square capQq = to - pawn_push(sideToMove); assert(!captured); assert(type_of(piece_on(capQq)) == PAWN); // Remove the captured pawn occupied ^= capQq; captured = PAWN; } else if (type_of(m) == CASTLE) // Castle moves are implemented as king capturing the rook so cannot be // handled correctly. Simply return 0 that is always the correct value // unless the rook is ends up under attack. return 0; // Find all attackers to the destination square, with the moving piece // removed, but possibly an X-ray attacker added behind it. attackers = attackers_to(to, occupied); // If the opponent has no attackers we are finished stm = ~color_of(piece_on(from)); stmAttackers = attackers & pieces(stm); if (!stmAttackers) return PieceValue[MG][captured]; // The destination square is defended, which makes things rather more // difficult to compute. We proceed by building up a "swap list" containing // the material gain or loss at each stop in a sequence of captures to the // destination square, where the sides alternately capture, and always // capture with the least valuable piece. After each capture, we look for // new X-ray attacks from behind the capturing piece. swapList[0] = PieceValue[MG][captured]; captured = type_of(piece_on(from)); do { assert(slIndex < 32); // Add the new entry to the swap list swapList[slIndex] = -swapList[slIndex - 1] + PieceValue[MG][captured]; slIndex++; // Locate and remove from 'occupied' the next least valuable attacker captured = next_attacker(byTypeBB, to, stmAttackers, occupied, attackers); attackers &= occupied; // Remove the just found attacker stm = ~stm; stmAttackers = attackers & pieces(stm); if (captured == KING) { // Stop before processing a king capture if (stmAttackers) swapList[slIndex++] = QueenValueMg * 16; break; } } while (stmAttackers); // If we are doing asymmetric SEE evaluation and the same side does the first // and the last capture, he loses a tempo and gain must be at least worth // 'asymmThreshold', otherwise we replace the score with a very low value, // before negamaxing. if (asymmThreshold) for (int i = 0; i < slIndex; i += 2) if (swapList[i] < asymmThreshold) swapList[i] = - QueenValueMg * 16; // Having built the swap list, we negamax through it to find the best // achievable score from the point of view of the side to move. while (--slIndex) swapList[slIndex-1] = std::min(-swapList[slIndex], swapList[slIndex-1]); return swapList[0]; } /// Position::clear() erases the position object to a pristine state, with an /// empty board, white to move, and no castling rights. void Position::clear() { memset(this, 0, sizeof(Position)); startState.epSquare = SQ_NONE; st = &startState; for (int i = 0; i < 8; i++) for (int j = 0; j < 16; j++) pieceList[0][i][j] = pieceList[1][i][j] = SQ_NONE; } /// Position::put_piece() puts a piece on the given square of the board, /// updating the board array, pieces list, bitboards, and piece counts. void Position::put_piece(Piece p, Square s) { Color c = color_of(p); PieceType pt = type_of(p); board[s] = p; index[s] = pieceCount[c][pt]++; pieceList[c][pt][index[s]] = s; byTypeBB[ALL_PIECES] |= s; byTypeBB[pt] |= s; byColorBB[c] |= s; } /// Position::compute_key() computes the hash key of the position. The hash /// key is usually updated incrementally as moves are made and unmade, the /// compute_key() function is only used when a new position is set up, and /// to verify the correctness of the hash key when running in debug mode. Key Position::compute_key() const { Key k = Zobrist::castle[st->castleRights]; for (Bitboard b = pieces(); b; ) { Square s = pop_lsb(&b); k ^= Zobrist::psq[color_of(piece_on(s))][type_of(piece_on(s))][s]; } if (ep_square() != SQ_NONE) k ^= Zobrist::enpassant[file_of(ep_square())]; if (sideToMove == BLACK) k ^= Zobrist::side; return k; } /// Position::compute_pawn_key() computes the hash key of the position. The /// hash key is usually updated incrementally as moves are made and unmade, /// the compute_pawn_key() function is only used when a new position is set /// up, and to verify the correctness of the pawn hash key when running in /// debug mode. Key Position::compute_pawn_key() const { Key k = 0; for (Bitboard b = pieces(PAWN); b; ) { Square s = pop_lsb(&b); k ^= Zobrist::psq[color_of(piece_on(s))][PAWN][s]; } return k; } /// Position::compute_material_key() computes the hash key of the position. /// The hash key is usually updated incrementally as moves are made and unmade, /// the compute_material_key() function is only used when a new position is set /// up, and to verify the correctness of the material hash key when running in /// debug mode. Key Position::compute_material_key() const { Key k = 0; for (Color c = WHITE; c <= BLACK; c++) for (PieceType pt = PAWN; pt <= QUEEN; pt++) for (int cnt = 0; cnt < piece_count(c, pt); cnt++) k ^= Zobrist::psq[c][pt][cnt]; return k; } /// Position::compute_psq_score() computes the incremental scores for the middle /// game and the endgame. These functions are used to initialize the incremental /// scores when a new position is set up, and to verify that the scores are correctly /// updated by do_move and undo_move when the program is running in debug mode. Score Position::compute_psq_score() const { Score score = SCORE_ZERO; for (Bitboard b = pieces(); b; ) { Square s = pop_lsb(&b); score += pieceSquareTable[piece_on(s)][s]; } return score; } /// Position::compute_non_pawn_material() computes the total non-pawn middle /// game material value for the given side. Material values are updated /// incrementally during the search, this function is only used while /// initializing a new Position object. Value Position::compute_non_pawn_material(Color c) const { Value value = VALUE_ZERO; for (PieceType pt = KNIGHT; pt <= QUEEN; pt++) value += piece_count(c, pt) * PieceValue[MG][pt]; return value; } /// Position::is_draw() tests whether the position is drawn by material, /// repetition, or the 50 moves rule. It does not detect stalemates, this /// must be done by the search. bool Position::is_draw() const { // Draw by material? if ( !pieces(PAWN) && (non_pawn_material(WHITE) + non_pawn_material(BLACK) <= BishopValueMg)) return true; // Draw by the 50 moves rule? if (st->rule50 > 99 && (!checkers() || MoveList(*this).size())) return true; // Draw by repetition? int i = 4, e = std::min(st->rule50, st->pliesFromNull); if (i <= e) { StateInfo* stp = st->previous->previous; do { stp = stp->previous->previous; if (stp->key == st->key) return true; i += 2; } while (i <= e); } return false; } /// Position::flip() flips position with the white and black sides reversed. This /// is only useful for debugging especially for finding evaluation symmetry bugs. void Position::flip() { const Position pos(*this); clear(); sideToMove = ~pos.side_to_move(); thisThread = pos.this_thread(); nodes = pos.nodes_searched(); chess960 = pos.is_chess960(); gamePly = pos.game_ply(); for (Square s = SQ_A1; s <= SQ_H8; s++) if (!pos.is_empty(s)) put_piece(Piece(pos.piece_on(s) ^ 8), ~s); if (pos.can_castle(WHITE_OO)) set_castle_right(BLACK, ~pos.castle_rook_square(WHITE, KING_SIDE)); if (pos.can_castle(WHITE_OOO)) set_castle_right(BLACK, ~pos.castle_rook_square(WHITE, QUEEN_SIDE)); if (pos.can_castle(BLACK_OO)) set_castle_right(WHITE, ~pos.castle_rook_square(BLACK, KING_SIDE)); if (pos.can_castle(BLACK_OOO)) set_castle_right(WHITE, ~pos.castle_rook_square(BLACK, QUEEN_SIDE)); if (pos.st->epSquare != SQ_NONE) st->epSquare = ~pos.st->epSquare; st->checkersBB = attackers_to(king_square(sideToMove)) & pieces(~sideToMove); st->key = compute_key(); st->pawnKey = compute_pawn_key(); st->materialKey = compute_material_key(); st->psqScore = compute_psq_score(); st->npMaterial[WHITE] = compute_non_pawn_material(WHITE); st->npMaterial[BLACK] = compute_non_pawn_material(BLACK); assert(pos_is_ok()); } /// Position::pos_is_ok() performs some consitency checks for the position object. /// This is meant to be helpful when debugging. bool Position::pos_is_ok(int* failedStep) const { int dummy, *step = failedStep ? failedStep : &dummy; // What features of the position should be verified? const bool all = false; const bool debugBitboards = all || false; const bool debugKingCount = all || false; const bool debugKingCapture = all || false; const bool debugCheckerCount = all || false; const bool debugKey = all || false; const bool debugMaterialKey = all || false; const bool debugPawnKey = all || false; const bool debugIncrementalEval = all || false; const bool debugNonPawnMaterial = all || false; const bool debugPieceCounts = all || false; const bool debugPieceList = all || false; const bool debugCastleSquares = all || false; *step = 1; if (sideToMove != WHITE && sideToMove != BLACK) return false; if ((*step)++, piece_on(king_square(WHITE)) != W_KING) return false; if ((*step)++, piece_on(king_square(BLACK)) != B_KING) return false; if ((*step)++, debugKingCount) { int kingCount[COLOR_NB] = {}; for (Square s = SQ_A1; s <= SQ_H8; s++) if (type_of(piece_on(s)) == KING) kingCount[color_of(piece_on(s))]++; if (kingCount[0] != 1 || kingCount[1] != 1) return false; } if ((*step)++, debugKingCapture) if (attackers_to(king_square(~sideToMove)) & pieces(sideToMove)) return false; if ((*step)++, debugCheckerCount && popcount(st->checkersBB) > 2) return false; if ((*step)++, debugBitboards) { // The intersection of the white and black pieces must be empty if (pieces(WHITE) & pieces(BLACK)) return false; // The union of the white and black pieces must be equal to all // occupied squares if ((pieces(WHITE) | pieces(BLACK)) != pieces()) return false; // Separate piece type bitboards must have empty intersections for (PieceType p1 = PAWN; p1 <= KING; p1++) for (PieceType p2 = PAWN; p2 <= KING; p2++) if (p1 != p2 && (pieces(p1) & pieces(p2))) return false; } if ((*step)++, ep_square() != SQ_NONE && relative_rank(sideToMove, ep_square()) != RANK_6) return false; if ((*step)++, debugKey && st->key != compute_key()) return false; if ((*step)++, debugPawnKey && st->pawnKey != compute_pawn_key()) return false; if ((*step)++, debugMaterialKey && st->materialKey != compute_material_key()) return false; if ((*step)++, debugIncrementalEval && st->psqScore != compute_psq_score()) return false; if ((*step)++, debugNonPawnMaterial) { if ( st->npMaterial[WHITE] != compute_non_pawn_material(WHITE) || st->npMaterial[BLACK] != compute_non_pawn_material(BLACK)) return false; } if ((*step)++, debugPieceCounts) for (Color c = WHITE; c <= BLACK; c++) for (PieceType pt = PAWN; pt <= KING; pt++) if (pieceCount[c][pt] != popcount(pieces(c, pt))) return false; if ((*step)++, debugPieceList) for (Color c = WHITE; c <= BLACK; c++) for (PieceType pt = PAWN; pt <= KING; pt++) for (int i = 0; i < pieceCount[c][pt]; i++) { if (piece_on(piece_list(c, pt)[i]) != make_piece(c, pt)) return false; if (index[piece_list(c, pt)[i]] != i) return false; } if ((*step)++, debugCastleSquares) for (Color c = WHITE; c <= BLACK; c++) for (CastlingSide s = KING_SIDE; s <= QUEEN_SIDE; s = CastlingSide(s + 1)) { CastleRight cr = make_castle_right(c, s); if (!can_castle(cr)) continue; if ((castleRightsMask[king_square(c)] & cr) != cr) return false; if ( piece_on(castleRookSquare[c][s]) != make_piece(c, ROOK) || castleRightsMask[castleRookSquare[c][s]] != cr) return false; } *step = 0; return true; } stockfish-3.0.0+git20130508/src/endgame.h0000644000175000017500000000627312142540127017041 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #if !defined(ENDGAME_H_INCLUDED) #define ENDGAME_H_INCLUDED #include #include #include "position.h" #include "types.h" /// EndgameType lists all supported endgames enum EndgameType { // Evaluation functions KXK, // Generic "mate lone king" eval KBNK, // KBN vs K KPK, // KP vs K KRKP, // KR vs KP KRKB, // KR vs KB KRKN, // KR vs KN KQKP, // KQ vs KP KQKR, // KQ vs KR KBBKN, // KBB vs KN KNNK, // KNN vs K KmmKm, // K and two minors vs K and one or two minors // Scaling functions SCALE_FUNS, KBPsK, // KB+pawns vs K KQKRPs, // KQ vs KR+pawns KRPKR, // KRP vs KR KRPPKRP, // KRPP vs KRP KPsK, // King and pawns vs king KBPKB, // KBP vs KB KBPPKB, // KBPP vs KB KBPKN, // KBP vs KN KNPK, // KNP vs K KNPKB, // KNP vs KB KPKP // KP vs KP }; /// Endgame functions can be of two types according if return a Value or a /// ScaleFactor. Type eg_fun::type equals to either ScaleFactor or Value /// depending if the template parameter is 0 or 1. template struct eg_fun { typedef Value type; }; template<> struct eg_fun<1> { typedef ScaleFactor type; }; /// Base and derived templates for endgame evaluation and scaling functions template struct EndgameBase { virtual ~EndgameBase() {} virtual Color color() const = 0; virtual T operator()(const Position&) const = 0; }; template SCALE_FUNS)>::type> struct Endgame : public EndgameBase { explicit Endgame(Color c) : strongerSide(c), weakerSide(~c) {} Color color() const { return strongerSide; } T operator()(const Position&) const; private: Color strongerSide, weakerSide; }; /// Endgames class stores in two std::map the pointers to endgame evaluation /// and scaling base objects. Then we use polymorphism to invoke the actual /// endgame function calling its operator() that is virtual. class Endgames { typedef std::map::type>*> M1; typedef std::map::type>*> M2; M1 m1; M2 m2; M1& map(M1::mapped_type) { return m1; } M2& map(M2::mapped_type) { return m2; } template void add(const std::string& code); public: Endgames(); ~Endgames(); template T probe(Key key, T& eg) { return eg = map(eg).count(key) ? map(eg)[key] : NULL; } }; #endif // !defined(ENDGAME_H_INCLUDED) stockfish-3.0.0+git20130508/src/thread.h0000644000175000017500000001117312142540127016703 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #if !defined(THREAD_H_INCLUDED) #define THREAD_H_INCLUDED #include #include "material.h" #include "movepick.h" #include "pawns.h" #include "position.h" #include "search.h" const int MAX_THREADS = 64; // Because SplitPoint::slavesMask is a uint64_t const int MAX_SPLITPOINTS_PER_THREAD = 8; struct Mutex { Mutex() { lock_init(l); } ~Mutex() { lock_destroy(l); } void lock() { lock_grab(l); } void unlock() { lock_release(l); } private: friend struct ConditionVariable; Lock l; }; struct ConditionVariable { ConditionVariable() { cond_init(c); } ~ConditionVariable() { cond_destroy(c); } void wait(Mutex& m) { cond_wait(c, m.l); } void wait_for(Mutex& m, int ms) { timed_wait(c, m.l, ms); } void notify_one() { cond_signal(c); } private: WaitCondition c; }; struct Thread; struct SplitPoint { // Const data after split point has been setup const Position* pos; const Search::Stack* ss; Thread* masterThread; Depth depth; Value beta; int nodeType; Move threatMove; // Const pointers to shared data MovePicker* movePicker; SplitPoint* parentSplitPoint; // Shared data Mutex mutex; volatile uint64_t slavesMask; volatile int64_t nodes; volatile Value alpha; volatile Value bestValue; volatile Move bestMove; volatile int moveCount; volatile bool cutoff; }; /// Thread struct keeps together all the thread related stuff like locks, state /// and especially split points. We also use per-thread pawn and material hash /// tables so that once we get a pointer to an entry its life time is unlimited /// and we don't have to care about someone changing the entry under our feet. struct Thread { Thread(); virtual ~Thread(); virtual void idle_loop(); void notify_one(); bool cutoff_occurred() const; bool is_available_to(Thread* master) const; void wait_for(volatile const bool& b); template void split(Position& pos, Search::Stack* ss, Value alpha, Value beta, Value* bestValue, Move* bestMove, Depth depth, Move threatMove, int moveCount, MovePicker* movePicker, int nodeType); SplitPoint splitPoints[MAX_SPLITPOINTS_PER_THREAD]; Material::Table materialTable; Endgames endgames; Pawns::Table pawnsTable; Position* activePosition; size_t idx; int maxPly; Mutex mutex; ConditionVariable sleepCondition; NativeHandle handle; SplitPoint* volatile activeSplitPoint; volatile int splitPointsSize; volatile bool searching; volatile bool exit; }; /// MainThread and TimerThread are sublassed from Thread to characterize the two /// special threads: the main one and the recurring timer. struct MainThread : public Thread { MainThread() : thinking(true) {} // Avoid a race with start_thinking() virtual void idle_loop(); volatile bool thinking; }; struct TimerThread : public Thread { TimerThread() : msec(0) {} virtual void idle_loop(); int msec; }; /// ThreadPool struct handles all the threads related stuff like init, starting, /// parking and, the most important, launching a slave thread at a split point. /// All the access to shared thread data is done through this class. struct ThreadPool : public std::vector { void init(); // No c'tor and d'tor, threads rely on globals that should void exit(); // be initialized and valid during the whole thread lifetime. MainThread* main_thread() { return static_cast((*this)[0]); } void read_uci_options(); Thread* available_slave(Thread* master) const; void wait_for_think_finished(); void start_thinking(const Position&, const Search::LimitsType&, const std::vector&, Search::StateStackPtr&); bool sleepWhileIdle; Depth minimumSplitDepth; size_t maxThreadsPerSplitPoint; Mutex mutex; ConditionVariable sleepCondition; TimerThread* timer; }; extern ThreadPool Threads; #endif // !defined(THREAD_H_INCLUDED) stockfish-3.0.0+git20130508/src/pawns.h0000644000175000017500000000516612142540127016571 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #if !defined(PAWNS_H_INCLUDED) #define PAWNS_H_INCLUDED #include "misc.h" #include "position.h" #include "types.h" namespace Pawns { /// Pawns::Entry contains various information about a pawn structure. Currently, /// it only includes a middle game and end game pawn structure evaluation, and a /// bitboard of passed pawns. We may want to add further information in the future. /// A lookup to the pawn hash table (performed by calling the probe function) /// returns a pointer to an Entry object. struct Entry { Score pawns_value() const { return value; } Bitboard pawn_attacks(Color c) const { return pawnAttacks[c]; } Bitboard passed_pawns(Color c) const { return passedPawns[c]; } int file_is_half_open(Color c, File f) const { return halfOpenFiles[c] & (1 << int(f)); } int pawns_on_same_color_squares(Color c, Square s) const { return pawnsOnSquares[c][!!(BlackSquares & s)]; } int has_open_file_on_side(Color c, File f, bool left) const { return halfOpenFiles[c] & (left ? ((1 << int(f)) - 1) : ~((1 << int(f+1)) - 1)); } template Score king_safety(const Position& pos, Square ksq) { return kingSquares[Us] == ksq && castleRights[Us] == pos.can_castle(Us) ? kingSafety[Us] : update_safety(pos, ksq); } template Score update_safety(const Position& pos, Square ksq); template Value shelter_storm(const Position& pos, Square ksq); Key key; Bitboard passedPawns[COLOR_NB]; Bitboard pawnAttacks[COLOR_NB]; Square kingSquares[COLOR_NB]; int minKPdistance[COLOR_NB]; int castleRights[COLOR_NB]; Score value; int halfOpenFiles[COLOR_NB]; Score kingSafety[COLOR_NB]; int pawnsOnSquares[COLOR_NB][COLOR_NB]; }; typedef HashTable Table; Entry* probe(const Position& pos, Table& entries); } #endif // !defined(PAWNS_H_INCLUDED) stockfish-3.0.0+git20130508/src/bitcount.h0000644000175000017500000000612512142540127017264 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #if !defined(BITCOUNT_H_INCLUDED) #define BITCOUNT_H_INCLUDED #include #include "types.h" enum BitCountType { CNT_64, CNT_64_MAX15, CNT_32, CNT_32_MAX15, CNT_HW_POPCNT }; /// Determine at compile time the best popcount<> specialization according if /// platform is 32 or 64 bits, to the maximum number of nonzero bits to count /// and if hardware popcnt instruction is available. const BitCountType Full = HasPopCnt ? CNT_HW_POPCNT : Is64Bit ? CNT_64 : CNT_32; const BitCountType Max15 = HasPopCnt ? CNT_HW_POPCNT : Is64Bit ? CNT_64_MAX15 : CNT_32_MAX15; /// popcount() counts the number of nonzero bits in a bitboard template inline int popcount(Bitboard); template<> inline int popcount(Bitboard b) { b -= (b >> 1) & 0x5555555555555555ULL; b = ((b >> 2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL); b = ((b >> 4) + b) & 0x0F0F0F0F0F0F0F0FULL; return (b * 0x0101010101010101ULL) >> 56; } template<> inline int popcount(Bitboard b) { b -= (b >> 1) & 0x5555555555555555ULL; b = ((b >> 2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL); return (b * 0x1111111111111111ULL) >> 60; } template<> inline int popcount(Bitboard b) { unsigned w = unsigned(b >> 32), v = unsigned(b); v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits w -= (w >> 1) & 0x55555555; v = ((v >> 2) & 0x33333333) + (v & 0x33333333); // 0-4 in 4 bits w = ((w >> 2) & 0x33333333) + (w & 0x33333333); v = ((v >> 4) + v + (w >> 4) + w) & 0x0F0F0F0F; return (v * 0x01010101) >> 24; } template<> inline int popcount(Bitboard b) { unsigned w = unsigned(b >> 32), v = unsigned(b); v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits w -= (w >> 1) & 0x55555555; v = ((v >> 2) & 0x33333333) + (v & 0x33333333); // 0-4 in 4 bits w = ((w >> 2) & 0x33333333) + (w & 0x33333333); return ((v + w) * 0x11111111) >> 28; } template<> inline int popcount(Bitboard b) { #if !defined(USE_POPCNT) assert(false); return b != 0; // Avoid 'b not used' warning #elif defined(_MSC_VER) && defined(__INTEL_COMPILER) return _mm_popcnt_u64(b); #elif defined(_MSC_VER) return (int)__popcnt64(b); #else __asm__("popcnt %1, %0" : "=r" (b) : "r" (b)); return b; #endif } #endif // !defined(BITCOUNT_H_INCLUDED) stockfish-3.0.0+git20130508/src/pawns.cpp0000644000175000017500000002515012142540127017117 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "bitboard.h" #include "bitcount.h" #include "pawns.h" #include "position.h" namespace { #define V Value #define S(mg, eg) make_score(mg, eg) // Doubled pawn penalty by opposed flag and file const Score DoubledPawnPenalty[2][FILE_NB] = { { S(13, 43), S(20, 48), S(23, 48), S(23, 48), S(23, 48), S(23, 48), S(20, 48), S(13, 43) }, { S(13, 43), S(20, 48), S(23, 48), S(23, 48), S(23, 48), S(23, 48), S(20, 48), S(13, 43) }}; // Isolated pawn penalty by opposed flag and file const Score IsolatedPawnPenalty[2][FILE_NB] = { { S(37, 45), S(54, 52), S(60, 52), S(60, 52), S(60, 52), S(60, 52), S(54, 52), S(37, 45) }, { S(25, 30), S(36, 35), S(40, 35), S(40, 35), S(40, 35), S(40, 35), S(36, 35), S(25, 30) }}; // Backward pawn penalty by opposed flag and file const Score BackwardPawnPenalty[2][FILE_NB] = { { S(30, 42), S(43, 46), S(49, 46), S(49, 46), S(49, 46), S(49, 46), S(43, 46), S(30, 42) }, { S(20, 28), S(29, 31), S(33, 31), S(33, 31), S(33, 31), S(33, 31), S(29, 31), S(20, 28) }}; // Pawn chain membership bonus by file const Score ChainBonus[FILE_NB] = { S(11,-1), S(13,-1), S(13,-1), S(14,-1), S(14,-1), S(13,-1), S(13,-1), S(11,-1) }; // Candidate passed pawn bonus by rank const Score CandidateBonus[RANK_NB] = { S( 0, 0), S( 6, 13), S(6,13), S(14,29), S(34,68), S(83,166), S(0, 0), S( 0, 0) }; const Score PawnStructureWeight = S(233, 201); // Weakness of our pawn shelter in front of the king indexed by [king pawn][rank] const Value ShelterWeakness[2][RANK_NB] = { { V(141), V(0), V(38), V(102), V(128), V(141), V(141) }, { V( 61), V(0), V(16), V( 44), V( 56), V( 61), V( 61) } }; // Danger of enemy pawns moving toward our king indexed by [pawn blocked][rank] const Value StormDanger[2][RANK_NB] = { { V(26), V(0), V(128), V(51), V(26) }, { V(13), V(0), V( 64), V(25), V(13) } }; // Max bonus for king safety. Corresponds to start position with all the pawns // in front of the king and no enemy pawn on the horizont. const Value MaxSafetyBonus = V(263); #undef S #undef V template Score evaluate_pawns(const Position& pos, Bitboard ourPawns, Bitboard theirPawns, Pawns::Entry* e) { const Color Them = (Us == WHITE ? BLACK : WHITE); Bitboard b; Square s; File f; Rank r; bool passed, isolated, doubled, opposed, chain, backward, candidate; Score value = SCORE_ZERO; const Square* pl = pos.piece_list(Us, PAWN); // Loop through all pawns of the current color and score each pawn while ((s = *pl++) != SQ_NONE) { assert(pos.piece_on(s) == make_piece(Us, PAWN)); f = file_of(s); r = rank_of(s); // This file cannot be half open e->halfOpenFiles[Us] &= ~(1 << f); // Our rank plus previous one. Used for chain detection b = rank_bb(r) | rank_bb(Us == WHITE ? r - Rank(1) : r + Rank(1)); // Flag the pawn as passed, isolated, doubled or member of a pawn // chain (but not the backward one). chain = ourPawns & adjacent_files_bb(f) & b; isolated = !(ourPawns & adjacent_files_bb(f)); doubled = ourPawns & forward_bb(Us, s); opposed = theirPawns & forward_bb(Us, s); passed = !(theirPawns & passed_pawn_mask(Us, s)); // Test for backward pawn backward = false; // If the pawn is passed, isolated, or member of a pawn chain it cannot // be backward. If there are friendly pawns behind on adjacent files // or if can capture an enemy pawn it cannot be backward either. if ( !(passed | isolated | chain) && !(ourPawns & attack_span_mask(Them, s)) && !(pos.attacks_from(s, Us) & theirPawns)) { // We now know that there are no friendly pawns beside or behind this // pawn on adjacent files. We now check whether the pawn is // backward by looking in the forward direction on the adjacent // files, and seeing whether we meet a friendly or an enemy pawn first. b = pos.attacks_from(s, Us); // Note that we are sure to find something because pawn is not passed // nor isolated, so loop is potentially infinite, but it isn't. while (!(b & (ourPawns | theirPawns))) Us == WHITE ? b <<= 8 : b >>= 8; // The friendly pawn needs to be at least two ranks closer than the // enemy pawn in order to help the potentially backward pawn advance. backward = (b | (Us == WHITE ? b << 8 : b >> 8)) & theirPawns; } assert(opposed | passed | (attack_span_mask(Us, s) & theirPawns)); // A not passed pawn is a candidate to become passed if it is free to // advance and if the number of friendly pawns beside or behind this // pawn on adjacent files is higher or equal than the number of // enemy pawns in the forward direction on the adjacent files. candidate = !(opposed | passed | backward | isolated) && (b = attack_span_mask(Them, s + pawn_push(Us)) & ourPawns) != 0 && popcount(b) >= popcount(attack_span_mask(Us, s) & theirPawns); // Passed pawns will be properly scored in evaluation because we need // full attack info to evaluate passed pawns. Only the frontmost passed // pawn on each file is considered a true passed pawn. if (passed && !doubled) e->passedPawns[Us] |= s; // Score this pawn if (isolated) value -= IsolatedPawnPenalty[opposed][f]; if (doubled) value -= DoubledPawnPenalty[opposed][f]; if (backward) value -= BackwardPawnPenalty[opposed][f]; if (chain) value += ChainBonus[f]; if (candidate) value += CandidateBonus[relative_rank(Us, s)]; } e->pawnsOnSquares[Us][BLACK] = popcount(ourPawns & BlackSquares); e->pawnsOnSquares[Us][WHITE] = pos.piece_count(Us, PAWN) - e->pawnsOnSquares[Us][BLACK]; e->pawnsOnSquares[Them][BLACK] = popcount(theirPawns & BlackSquares); e->pawnsOnSquares[Them][WHITE] = pos.piece_count(Them, PAWN) - e->pawnsOnSquares[Them][BLACK]; return value; } } namespace Pawns { /// probe() takes a position object as input, computes a Entry object, and returns /// a pointer to it. The result is also stored in a hash table, so we don't have /// to recompute everything when the same pawn structure occurs again. Entry* probe(const Position& pos, Table& entries) { Key key = pos.pawn_key(); Entry* e = entries[key]; // If e->key matches the position's pawn hash key, it means that we // have analysed this pawn structure before, and we can simply return // the information we found the last time instead of recomputing it. if (e->key == key) return e; e->key = key; e->passedPawns[WHITE] = e->passedPawns[BLACK] = 0; e->kingSquares[WHITE] = e->kingSquares[BLACK] = SQ_NONE; e->halfOpenFiles[WHITE] = e->halfOpenFiles[BLACK] = 0xFF; Bitboard wPawns = pos.pieces(WHITE, PAWN); Bitboard bPawns = pos.pieces(BLACK, PAWN); e->pawnAttacks[WHITE] = ((wPawns & ~FileHBB) << 9) | ((wPawns & ~FileABB) << 7); e->pawnAttacks[BLACK] = ((bPawns & ~FileHBB) >> 7) | ((bPawns & ~FileABB) >> 9); e->value = evaluate_pawns(pos, wPawns, bPawns, e) - evaluate_pawns(pos, bPawns, wPawns, e); e->value = apply_weight(e->value, PawnStructureWeight); return e; } /// Entry::shelter_storm() calculates shelter and storm penalties for the file /// the king is on, as well as the two adjacent files. template Value Entry::shelter_storm(const Position& pos, Square ksq) { const Color Them = (Us == WHITE ? BLACK : WHITE); Value safety = MaxSafetyBonus; Bitboard b = pos.pieces(PAWN) & (in_front_bb(Us, ksq) | rank_bb(ksq)); Bitboard ourPawns = b & pos.pieces(Us) & ~rank_bb(ksq); Bitboard theirPawns = b & pos.pieces(Them); Rank rkUs, rkThem; File kf = file_of(ksq); kf = (kf == FILE_A) ? FILE_B : (kf == FILE_H) ? FILE_G : kf; for (int f = kf - 1; f <= kf + 1; f++) { // Shelter penalty is higher for the pawn in front of the king b = ourPawns & FileBB[f]; rkUs = b ? rank_of(Us == WHITE ? lsb(b) : ~msb(b)) : RANK_1; safety -= ShelterWeakness[f != kf][rkUs]; // Storm danger is smaller if enemy pawn is blocked b = theirPawns & FileBB[f]; rkThem = b ? rank_of(Us == WHITE ? lsb(b) : ~msb(b)) : RANK_1; safety -= StormDanger[rkThem == rkUs + 1][rkThem]; } return safety; } /// Entry::update_safety() calculates and caches a bonus for king safety. It is /// called only when king square changes, about 20% of total king_safety() calls. template Score Entry::update_safety(const Position& pos, Square ksq) { kingSquares[Us] = ksq; castleRights[Us] = pos.can_castle(Us); minKPdistance[Us] = 0; Bitboard pawns = pos.pieces(Us, PAWN); if (pawns) while (!(DistanceRingsBB[ksq][minKPdistance[Us]++] & pawns)) {} if (relative_rank(Us, ksq) > RANK_4) return kingSafety[Us] = make_score(0, -16 * minKPdistance[Us]); Value bonus = shelter_storm(pos, ksq); // If we can castle use the bonus after the castle if is bigger if (pos.can_castle(make_castle_right(Us, KING_SIDE))) bonus = std::max(bonus, shelter_storm(pos, relative_square(Us, SQ_G1))); if (pos.can_castle(make_castle_right(Us, QUEEN_SIDE))) bonus = std::max(bonus, shelter_storm(pos, relative_square(Us, SQ_C1))); return kingSafety[Us] = make_score(bonus, -16 * minKPdistance[Us]); } // Explicit template instantiation template Score Entry::update_safety(const Position& pos, Square ksq); template Score Entry::update_safety(const Position& pos, Square ksq); } // namespace Pawns stockfish-3.0.0+git20130508/src/book.h0000644000175000017500000000246612142540127016373 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #if !defined(BOOK_H_INCLUDED) #define BOOK_H_INCLUDED #include #include #include "position.h" #include "rkiss.h" class PolyglotBook : private std::ifstream { public: PolyglotBook(); ~PolyglotBook(); Move probe(const Position& pos, const std::string& fName, bool pickBest); private: template PolyglotBook& operator>>(T& n); bool open(const char* fName); size_t find_first(Key key); RKISS rkiss; std::string fileName; }; #endif // !defined(BOOK_H_INCLUDED) stockfish-3.0.0+git20130508/src/material.cpp0000644000175000017500000002536612142540127017576 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include // For std::min #include #include #include "material.h" using namespace std; namespace { // Values modified by Joona Kiiski const Value MidgameLimit = Value(15581); const Value EndgameLimit = Value(3998); // Scale factors used when one side has no more pawns const int NoPawnsSF[4] = { 6, 12, 32 }; // Polynomial material balance parameters const Value RedundantQueenPenalty = Value(320); const Value RedundantRookPenalty = Value(554); // pair pawn knight bishop rook queen const int LinearCoefficients[6] = { 1617, -162, -1172, -190, 105, 26 }; const int QuadraticCoefficientsSameColor[][PIECE_TYPE_NB] = { // pair pawn knight bishop rook queen { 7 }, // Bishop pair { 39, 2 }, // Pawn { 35, 271, -4 }, // Knight { 7, 105, 4, 7 }, // Bishop { -27, -2, 46, 100, 56 }, // Rook { 58, 29, 83, 148, -3, -25 } // Queen }; const int QuadraticCoefficientsOppositeColor[][PIECE_TYPE_NB] = { // THEIR PIECES // pair pawn knight bishop rook queen { 41 }, // Bishop pair { 37, 41 }, // Pawn { 10, 62, 41 }, // Knight OUR PIECES { 57, 64, 39, 41 }, // Bishop { 50, 40, 23, -22, 41 }, // Rook { 106, 101, 3, 151, 171, 41 } // Queen }; // Endgame evaluation and scaling functions accessed direcly and not through // the function maps because correspond to more then one material hash key. Endgame EvaluateKmmKm[] = { Endgame(WHITE), Endgame(BLACK) }; Endgame EvaluateKXK[] = { Endgame(WHITE), Endgame(BLACK) }; Endgame ScaleKBPsK[] = { Endgame(WHITE), Endgame(BLACK) }; Endgame ScaleKQKRPs[] = { Endgame(WHITE), Endgame(BLACK) }; Endgame ScaleKPsK[] = { Endgame(WHITE), Endgame(BLACK) }; Endgame ScaleKPKP[] = { Endgame(WHITE), Endgame(BLACK) }; // Helper templates used to detect a given material distribution template bool is_KXK(const Position& pos) { const Color Them = (Us == WHITE ? BLACK : WHITE); return pos.non_pawn_material(Them) == VALUE_ZERO && pos.piece_count(Them, PAWN) == 0 && pos.non_pawn_material(Us) >= RookValueMg; } template bool is_KBPsKs(const Position& pos) { return pos.non_pawn_material(Us) == BishopValueMg && pos.piece_count(Us, BISHOP) == 1 && pos.piece_count(Us, PAWN) >= 1; } template bool is_KQKRPs(const Position& pos) { const Color Them = (Us == WHITE ? BLACK : WHITE); return pos.piece_count(Us, PAWN) == 0 && pos.non_pawn_material(Us) == QueenValueMg && pos.piece_count(Us, QUEEN) == 1 && pos.piece_count(Them, ROOK) == 1 && pos.piece_count(Them, PAWN) >= 1; } /// imbalance() calculates imbalance comparing piece count of each /// piece type for both colors. template int imbalance(const int pieceCount[][PIECE_TYPE_NB]) { const Color Them = (Us == WHITE ? BLACK : WHITE); int pt1, pt2, pc, v; int value = 0; // Redundancy of major pieces, formula based on Kaufman's paper // "The Evaluation of Material Imbalances in Chess" if (pieceCount[Us][ROOK] > 0) value -= RedundantRookPenalty * (pieceCount[Us][ROOK] - 1) + RedundantQueenPenalty * pieceCount[Us][QUEEN]; // Second-degree polynomial material imbalance by Tord Romstad for (pt1 = NO_PIECE_TYPE; pt1 <= QUEEN; pt1++) { pc = pieceCount[Us][pt1]; if (!pc) continue; v = LinearCoefficients[pt1]; for (pt2 = NO_PIECE_TYPE; pt2 <= pt1; pt2++) v += QuadraticCoefficientsSameColor[pt1][pt2] * pieceCount[Us][pt2] + QuadraticCoefficientsOppositeColor[pt1][pt2] * pieceCount[Them][pt2]; value += pc * v; } return value; } } // namespace namespace Material { /// Material::probe() takes a position object as input, looks up a MaterialEntry /// object, and returns a pointer to it. If the material configuration is not /// already present in the table, it is computed and stored there, so we don't /// have to recompute everything when the same material configuration occurs again. Entry* probe(const Position& pos, Table& entries, Endgames& endgames) { Key key = pos.material_key(); Entry* e = entries[key]; // If e->key matches the position's material hash key, it means that we // have analysed this material configuration before, and we can simply // return the information we found the last time instead of recomputing it. if (e->key == key) return e; memset(e, 0, sizeof(Entry)); e->key = key; e->factor[WHITE] = e->factor[BLACK] = (uint8_t)SCALE_FACTOR_NORMAL; e->gamePhase = game_phase(pos); // Let's look if we have a specialized evaluation function for this // particular material configuration. First we look for a fixed // configuration one, then a generic one if previous search failed. if (endgames.probe(key, e->evaluationFunction)) return e; if (is_KXK(pos)) { e->evaluationFunction = &EvaluateKXK[WHITE]; return e; } if (is_KXK(pos)) { e->evaluationFunction = &EvaluateKXK[BLACK]; return e; } if (!pos.pieces(PAWN) && !pos.pieces(ROOK) && !pos.pieces(QUEEN)) { // Minor piece endgame with at least one minor piece per side and // no pawns. Note that the case KmmK is already handled by KXK. assert((pos.pieces(WHITE, KNIGHT) | pos.pieces(WHITE, BISHOP))); assert((pos.pieces(BLACK, KNIGHT) | pos.pieces(BLACK, BISHOP))); if ( pos.piece_count(WHITE, BISHOP) + pos.piece_count(WHITE, KNIGHT) <= 2 && pos.piece_count(BLACK, BISHOP) + pos.piece_count(BLACK, KNIGHT) <= 2) { e->evaluationFunction = &EvaluateKmmKm[pos.side_to_move()]; return e; } } // OK, we didn't find any special evaluation function for the current // material configuration. Is there a suitable scaling function? // // We face problems when there are several conflicting applicable // scaling functions and we need to decide which one to use. EndgameBase* sf; if (endgames.probe(key, sf)) { e->scalingFunction[sf->color()] = sf; return e; } // Generic scaling functions that refer to more then one material // distribution. Should be probed after the specialized ones. // Note that these ones don't return after setting the function. if (is_KBPsKs(pos)) e->scalingFunction[WHITE] = &ScaleKBPsK[WHITE]; if (is_KBPsKs(pos)) e->scalingFunction[BLACK] = &ScaleKBPsK[BLACK]; if (is_KQKRPs(pos)) e->scalingFunction[WHITE] = &ScaleKQKRPs[WHITE]; else if (is_KQKRPs(pos)) e->scalingFunction[BLACK] = &ScaleKQKRPs[BLACK]; Value npm_w = pos.non_pawn_material(WHITE); Value npm_b = pos.non_pawn_material(BLACK); if (npm_w + npm_b == VALUE_ZERO) { if (pos.piece_count(BLACK, PAWN) == 0) { assert(pos.piece_count(WHITE, PAWN) >= 2); e->scalingFunction[WHITE] = &ScaleKPsK[WHITE]; } else if (pos.piece_count(WHITE, PAWN) == 0) { assert(pos.piece_count(BLACK, PAWN) >= 2); e->scalingFunction[BLACK] = &ScaleKPsK[BLACK]; } else if (pos.piece_count(WHITE, PAWN) == 1 && pos.piece_count(BLACK, PAWN) == 1) { // This is a special case because we set scaling functions // for both colors instead of only one. e->scalingFunction[WHITE] = &ScaleKPKP[WHITE]; e->scalingFunction[BLACK] = &ScaleKPKP[BLACK]; } } // No pawns makes it difficult to win, even with a material advantage if (pos.piece_count(WHITE, PAWN) == 0 && npm_w - npm_b <= BishopValueMg) { e->factor[WHITE] = (uint8_t) (npm_w == npm_b || npm_w < RookValueMg ? 0 : NoPawnsSF[std::min(pos.piece_count(WHITE, BISHOP), 2)]); } if (pos.piece_count(BLACK, PAWN) == 0 && npm_b - npm_w <= BishopValueMg) { e->factor[BLACK] = (uint8_t) (npm_w == npm_b || npm_b < RookValueMg ? 0 : NoPawnsSF[std::min(pos.piece_count(BLACK, BISHOP), 2)]); } // Compute the space weight if (npm_w + npm_b >= 2 * QueenValueMg + 4 * RookValueMg + 2 * KnightValueMg) { int minorPieceCount = pos.piece_count(WHITE, KNIGHT) + pos.piece_count(WHITE, BISHOP) + pos.piece_count(BLACK, KNIGHT) + pos.piece_count(BLACK, BISHOP); e->spaceWeight = minorPieceCount * minorPieceCount; } // Evaluate the material imbalance. We use PIECE_TYPE_NONE as a place holder // for the bishop pair "extended piece", this allow us to be more flexible // in defining bishop pair bonuses. const int pieceCount[COLOR_NB][PIECE_TYPE_NB] = { { pos.piece_count(WHITE, BISHOP) > 1, pos.piece_count(WHITE, PAWN), pos.piece_count(WHITE, KNIGHT), pos.piece_count(WHITE, BISHOP) , pos.piece_count(WHITE, ROOK), pos.piece_count(WHITE, QUEEN) }, { pos.piece_count(BLACK, BISHOP) > 1, pos.piece_count(BLACK, PAWN), pos.piece_count(BLACK, KNIGHT), pos.piece_count(BLACK, BISHOP) , pos.piece_count(BLACK, ROOK), pos.piece_count(BLACK, QUEEN) } }; e->value = (int16_t)((imbalance(pieceCount) - imbalance(pieceCount)) / 16); return e; } /// Material::game_phase() calculates the phase given the current /// position. Because the phase is strictly a function of the material, it /// is stored in MaterialEntry. Phase game_phase(const Position& pos) { Value npm = pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK); return npm >= MidgameLimit ? PHASE_MIDGAME : npm <= EndgameLimit ? PHASE_ENDGAME : Phase(((npm - EndgameLimit) * 128) / (MidgameLimit - EndgameLimit)); } } // namespace Material stockfish-3.0.0+git20130508/src/bitboard.h0000644000175000017500000002051312142540127017220 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #if !defined(BITBOARD_H_INCLUDED) #define BITBOARD_H_INCLUDED #include "types.h" namespace Bitboards { void init(); void print(Bitboard b); } namespace Bitbases { void init_kpk(); bool probe_kpk(Square wksq, Square wpsq, Square bksq, Color us); } CACHE_LINE_ALIGNMENT extern Bitboard RMasks[SQUARE_NB]; extern Bitboard RMagics[SQUARE_NB]; extern Bitboard* RAttacks[SQUARE_NB]; extern unsigned RShifts[SQUARE_NB]; extern Bitboard BMasks[SQUARE_NB]; extern Bitboard BMagics[SQUARE_NB]; extern Bitboard* BAttacks[SQUARE_NB]; extern unsigned BShifts[SQUARE_NB]; extern Bitboard SquareBB[SQUARE_NB]; extern Bitboard FileBB[FILE_NB]; extern Bitboard RankBB[RANK_NB]; extern Bitboard AdjacentFilesBB[FILE_NB]; extern Bitboard ThisAndAdjacentFilesBB[FILE_NB]; extern Bitboard InFrontBB[COLOR_NB][RANK_NB]; extern Bitboard StepAttacksBB[PIECE_NB][SQUARE_NB]; extern Bitboard BetweenBB[SQUARE_NB][SQUARE_NB]; extern Bitboard DistanceRingsBB[SQUARE_NB][8]; extern Bitboard ForwardBB[COLOR_NB][SQUARE_NB]; extern Bitboard PassedPawnMask[COLOR_NB][SQUARE_NB]; extern Bitboard AttackSpanMask[COLOR_NB][SQUARE_NB]; extern Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB]; const Bitboard BlackSquares = 0xAA55AA55AA55AA55ULL; /// Overloads of bitwise operators between a Bitboard and a Square for testing /// whether a given bit is set in a bitboard, and for setting and clearing bits. inline Bitboard operator&(Bitboard b, Square s) { return b & SquareBB[s]; } inline Bitboard& operator|=(Bitboard& b, Square s) { return b |= SquareBB[s]; } inline Bitboard& operator^=(Bitboard& b, Square s) { return b ^= SquareBB[s]; } inline Bitboard operator|(Bitboard b, Square s) { return b | SquareBB[s]; } inline Bitboard operator^(Bitboard b, Square s) { return b ^ SquareBB[s]; } /// more_than_one() returns true if in 'b' there is more than one bit set inline bool more_than_one(Bitboard b) { return b & (b - 1); } /// rank_bb() and file_bb() take a file or a square as input and return /// a bitboard representing all squares on the given file or rank. inline Bitboard rank_bb(Rank r) { return RankBB[r]; } inline Bitboard rank_bb(Square s) { return RankBB[rank_of(s)]; } inline Bitboard file_bb(File f) { return FileBB[f]; } inline Bitboard file_bb(Square s) { return FileBB[file_of(s)]; } /// adjacent_files_bb takes a file as input and returns a bitboard representing /// all squares on the adjacent files. inline Bitboard adjacent_files_bb(File f) { return AdjacentFilesBB[f]; } /// this_and_adjacent_files_bb takes a file as input and returns a bitboard /// representing all squares on the given and adjacent files. inline Bitboard this_and_adjacent_files_bb(File f) { return ThisAndAdjacentFilesBB[f]; } /// in_front_bb() takes a color and a rank or square as input, and returns a /// bitboard representing all the squares on all ranks in front of the rank /// (or square), from the given color's point of view. For instance, /// in_front_bb(WHITE, RANK_5) will give all squares on ranks 6, 7 and 8, while /// in_front_bb(BLACK, SQ_D3) will give all squares on ranks 1 and 2. inline Bitboard in_front_bb(Color c, Rank r) { return InFrontBB[c][r]; } inline Bitboard in_front_bb(Color c, Square s) { return InFrontBB[c][rank_of(s)]; } /// between_bb returns a bitboard representing all squares between two squares. /// For instance, between_bb(SQ_C4, SQ_F7) returns a bitboard with the bits for /// square d5 and e6 set. If s1 and s2 are not on the same line, file or diagonal, /// 0 is returned. inline Bitboard between_bb(Square s1, Square s2) { return BetweenBB[s1][s2]; } /// forward_bb takes a color and a square as input, and returns a bitboard /// representing all squares along the line in front of the square, from the /// point of view of the given color. Definition of the table is: /// ForwardBB[c][s] = in_front_bb(c, s) & file_bb(s) inline Bitboard forward_bb(Color c, Square s) { return ForwardBB[c][s]; } /// passed_pawn_mask takes a color and a square as input, and returns a /// bitboard mask which can be used to test if a pawn of the given color on /// the given square is a passed pawn. Definition of the table is: /// PassedPawnMask[c][s] = in_front_bb(c, s) & this_and_adjacent_files_bb(s) inline Bitboard passed_pawn_mask(Color c, Square s) { return PassedPawnMask[c][s]; } /// attack_span_mask takes a color and a square as input, and returns a bitboard /// representing all squares that can be attacked by a pawn of the given color /// when it moves along its file starting from the given square. Definition is: /// AttackSpanMask[c][s] = in_front_bb(c, s) & adjacent_files_bb(s); inline Bitboard attack_span_mask(Color c, Square s) { return AttackSpanMask[c][s]; } /// squares_aligned returns true if the squares s1, s2 and s3 are aligned /// either on a straight or on a diagonal line. inline bool squares_aligned(Square s1, Square s2, Square s3) { return (BetweenBB[s1][s2] | BetweenBB[s1][s3] | BetweenBB[s2][s3]) & ( SquareBB[s1] | SquareBB[s2] | SquareBB[s3]); } /// same_color_squares() returns a bitboard representing all squares with /// the same color of the given square. inline Bitboard same_color_squares(Square s) { return BlackSquares & s ? BlackSquares : ~BlackSquares; } /// Functions for computing sliding attack bitboards. Function attacks_bb() takes /// a square and a bitboard of occupied squares as input, and returns a bitboard /// representing all squares attacked by Pt (bishop or rook) on the given square. template FORCE_INLINE unsigned magic_index(Square s, Bitboard occ) { Bitboard* const Masks = Pt == ROOK ? RMasks : BMasks; Bitboard* const Magics = Pt == ROOK ? RMagics : BMagics; unsigned* const Shifts = Pt == ROOK ? RShifts : BShifts; if (Is64Bit) return unsigned(((occ & Masks[s]) * Magics[s]) >> Shifts[s]); unsigned lo = unsigned(occ) & unsigned(Masks[s]); unsigned hi = unsigned(occ >> 32) & unsigned(Masks[s] >> 32); return (lo * unsigned(Magics[s]) ^ hi * unsigned(Magics[s] >> 32)) >> Shifts[s]; } template inline Bitboard attacks_bb(Square s, Bitboard occ) { return (Pt == ROOK ? RAttacks : BAttacks)[s][magic_index(s, occ)]; } /// lsb()/msb() finds the least/most significant bit in a nonzero bitboard. /// pop_lsb() finds and clears the least significant bit in a nonzero bitboard. #if defined(USE_BSFQ) # if defined(_MSC_VER) && !defined(__INTEL_COMPILER) FORCE_INLINE Square lsb(Bitboard b) { unsigned long index; _BitScanForward64(&index, b); return (Square) index; } FORCE_INLINE Square msb(Bitboard b) { unsigned long index; _BitScanReverse64(&index, b); return (Square) index; } # elif defined(__arm__) FORCE_INLINE int lsb32(uint32_t v) { __asm__("rbit %0, %1" : "=r"(v) : "r"(v)); return __builtin_clz(v); } FORCE_INLINE Square msb(Bitboard b) { return (Square) (63 - __builtin_clzll(b)); } FORCE_INLINE Square lsb(Bitboard b) { return (Square) (uint32_t(b) ? lsb32(uint32_t(b)) : 32 + lsb32(uint32_t(b >> 32))); } # else FORCE_INLINE Square lsb(Bitboard b) { // Assembly code by Heinz van Saanen Bitboard index; __asm__("bsfq %1, %0": "=r"(index): "rm"(b) ); return (Square) index; } FORCE_INLINE Square msb(Bitboard b) { Bitboard index; __asm__("bsrq %1, %0": "=r"(index): "rm"(b) ); return (Square) index; } # endif FORCE_INLINE Square pop_lsb(Bitboard* b) { const Square s = lsb(*b); *b &= *b - 1; return s; } #else // if !defined(USE_BSFQ) extern Square msb(Bitboard b); extern Square lsb(Bitboard b); extern Square pop_lsb(Bitboard* b); #endif #endif // !defined(BITBOARD_H_INCLUDED) stockfish-3.0.0+git20130508/src/misc.cpp0000644000175000017500000001416212142540127016723 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include "misc.h" #include "thread.h" #if defined(__hpux) # include #endif using namespace std; /// Version number. If Version is left empty, then Tag plus current /// date, in the format DD-MM-YY, are used as a version number. static const string Version = ""; static const string Tag = ""; /// engine_info() returns the full name of the current Stockfish version. This /// will be either "Stockfish DD-MM-YY" (where DD-MM-YY is the date when /// the program was compiled) or "Stockfish ", depending on whether /// Version is empty. const string engine_info(bool to_uci) { const string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"); const string cpu64(Is64Bit ? " 64bit" : ""); const string popcnt(HasPopCnt ? " SSE4.2" : ""); string month, day, year; stringstream s, date(__DATE__); // From compiler, format is "Sep 21 2008" s << "Stockfish " << Version; if (Version.empty()) { date >> month >> day >> year; s << Tag << string(Tag.empty() ? "" : " ") << setfill('0') << setw(2) << day << "-" << setw(2) << (1 + months.find(month) / 4) << "-" << year.substr(2); } s << cpu64 << popcnt << (to_uci ? "\nid author ": " by ") << "Tord Romstad, Marco Costalba and Joona Kiiski"; return s.str(); } /// Convert system time to milliseconds. That's all we need. Time::point Time::now() { sys_time_t t; system_time(&t); return time_to_msec(t); } /// Debug functions used mainly to collect run-time statistics static uint64_t hits[2], means[2]; void dbg_hit_on(bool b) { hits[0]++; if (b) hits[1]++; } void dbg_hit_on_c(bool c, bool b) { if (c) dbg_hit_on(b); } void dbg_mean_of(int v) { means[0]++; means[1] += v; } void dbg_print() { if (hits[0]) cerr << "Total " << hits[0] << " Hits " << hits[1] << " hit rate (%) " << 100 * hits[1] / hits[0] << endl; if (means[0]) cerr << "Total " << means[0] << " Mean " << (float)means[1] / means[0] << endl; } /// Our fancy logging facility. The trick here is to replace cin.rdbuf() and /// cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We /// can toggle the logging of std::cout and std:cin at runtime while preserving /// usual i/o functionality and without changing a single line of code! /// Idea from http://groups.google.com/group/comp.lang.c++/msg/1d941c0f26ea0d81 struct Tie: public streambuf { // MSVC requires splitted streambuf for cin and cout Tie(streambuf* b, ofstream* f) : buf(b), file(f) {} int sync() { return file->rdbuf()->pubsync(), buf->pubsync(); } int overflow(int c) { return log(buf->sputc((char)c), "<< "); } int underflow() { return buf->sgetc(); } int uflow() { return log(buf->sbumpc(), ">> "); } streambuf* buf; ofstream* file; int log(int c, const char* prefix) { static int last = '\n'; if (last == '\n') file->rdbuf()->sputn(prefix, 3); return last = file->rdbuf()->sputc((char)c); } }; class Logger { Logger() : in(cin.rdbuf(), &file), out(cout.rdbuf(), &file) {} ~Logger() { start(false); } ofstream file; Tie in, out; public: static void start(bool b) { static Logger l; if (b && !l.file.is_open()) { l.file.open("io_log.txt", ifstream::out | ifstream::app); cin.rdbuf(&l.in); cout.rdbuf(&l.out); } else if (!b && l.file.is_open()) { cout.rdbuf(l.out.buf); cin.rdbuf(l.in.buf); l.file.close(); } } }; /// Used to serialize access to std::cout to avoid multiple threads to write at /// the same time. std::ostream& operator<<(std::ostream& os, SyncCout sc) { static Mutex m; if (sc == io_lock) m.lock(); if (sc == io_unlock) m.unlock(); return os; } /// Trampoline helper to avoid moving Logger to misc.h void start_logger(bool b) { Logger::start(b); } /// cpu_count() tries to detect the number of CPU cores int cpu_count() { #if defined(_WIN32) SYSTEM_INFO s; GetSystemInfo(&s); return s.dwNumberOfProcessors; #else # if defined(_SC_NPROCESSORS_ONLN) return sysconf(_SC_NPROCESSORS_ONLN); # elif defined(__hpux) struct pst_dynamic psd; if (pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0) == -1) return 1; return psd.psd_proc_cnt; # else return 1; # endif #endif } /// timed_wait() waits for msec milliseconds. It is mainly an helper to wrap /// conversion from milliseconds to struct timespec, as used by pthreads. void timed_wait(WaitCondition& sleepCond, Lock& sleepLock, int msec) { #if defined(_WIN32) int tm = msec; #else timespec ts, *tm = &ts; uint64_t ms = Time::now() + msec; ts.tv_sec = ms / 1000; ts.tv_nsec = (ms % 1000) * 1000000LL; #endif cond_timedwait(sleepCond, sleepLock, tm); } /// prefetch() preloads the given address in L1/L2 cache. This is a non /// blocking function and do not stalls the CPU waiting for data to be /// loaded from memory, that can be quite slow. #if defined(NO_PREFETCH) void prefetch(char*) {} #else void prefetch(char* addr) { # if defined(__INTEL_COMPILER) // This hack prevents prefetches to be optimized away by // Intel compiler. Both MSVC and gcc seems not affected. __asm__ (""); # endif # if defined(__INTEL_COMPILER) || defined(_MSC_VER) _mm_prefetch(addr, _MM_HINT_T0); # else __builtin_prefetch(addr); # endif } #endif stockfish-3.0.0+git20130508/src/thread.cpp0000644000175000017500000002622212142540127017237 0ustar oliveroliver/* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2013 Marco Costalba, Joona Kiiski, Tord Romstad 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. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include // For std::count #include #include #include "movegen.h" #include "search.h" #include "thread.h" #include "ucioption.h" using namespace Search; ThreadPool Threads; // Global object namespace { extern "C" { // start_routine() is the C function which is called when a new thread // is launched. It is a wrapper to the virtual function idle_loop(). long start_routine(Thread* th) { th->idle_loop(); return 0; } } } // Thread c'tor starts a newly-created thread of execution that will call // the the virtual function idle_loop(), going immediately to sleep. Thread::Thread() /* : splitPoints() */ { // Value-initialization bug in MSVC searching = exit = false; maxPly = splitPointsSize = 0; activeSplitPoint = NULL; activePosition = NULL; idx = Threads.size(); if (!thread_create(handle, start_routine, this)) { std::cerr << "Failed to create thread number " << idx << std::endl; ::exit(EXIT_FAILURE); } } // Thread d'tor waits for thread termination before to return Thread::~Thread() { exit = true; // Search must be already finished notify_one(); thread_join(handle); // Wait for thread termination } // TimerThread::idle_loop() is where the timer thread waits msec milliseconds // and then calls check_time(). If msec is 0 thread sleeps until is woken up. extern void check_time(); void TimerThread::idle_loop() { while (!exit) { mutex.lock(); if (!exit) sleepCondition.wait_for(mutex, msec ? msec : INT_MAX); mutex.unlock(); if (msec) check_time(); } } // MainThread::idle_loop() is where the main thread is parked waiting to be started // when there is a new search. Main thread will launch all the slave threads. void MainThread::idle_loop() { while (true) { mutex.lock(); thinking = false; while (!thinking && !exit) { Threads.sleepCondition.notify_one(); // Wake up UI thread if needed sleepCondition.wait(mutex); } mutex.unlock(); if (exit) return; searching = true; Search::think(); assert(searching); searching = false; } } // Thread::notify_one() wakes up the thread when there is some search to do void Thread::notify_one() { mutex.lock(); sleepCondition.notify_one(); mutex.unlock(); } // Thread::wait_for() set the thread to sleep until condition 'b' turns true void Thread::wait_for(volatile const bool& b) { mutex.lock(); while (!b) sleepCondition.wait(mutex); mutex.unlock(); } // Thread::cutoff_occurred() checks whether a beta cutoff has occurred in the // current active split point, or in some ancestor of the split point. bool Thread::cutoff_occurred() const { for (SplitPoint* sp = activeSplitPoint; sp; sp = sp->parentSplitPoint) if (sp->cutoff) return true; return false; } // Thread::is_available_to() checks whether the thread is available to help the // thread 'master' at a split point. An obvious requirement is that thread must // be idle. With more than two threads, this is not sufficient: If the thread is // the master of some split point, it is only available as a slave to the slaves // which are busy searching the split point at the top of slaves split point // stack (the "helpful master concept" in YBWC terminology). bool Thread::is_available_to(Thread* master) const { if (searching) return false; // Make a local copy to be sure doesn't become zero under our feet while // testing next condition and so leading to an out of bound access. int size = splitPointsSize; // No split points means that the thread is available as a slave for any // other thread otherwise apply the "helpful master" concept if possible. return !size || (splitPoints[size - 1].slavesMask & (1ULL << master->idx)); } // init() is called at startup to create and launch requested threads, that will // go immediately to sleep due to 'sleepWhileIdle' set to true. We cannot use // a c'tor becuase Threads is a static object and we need a fully initialized // engine at this point due to allocation of Endgames in Thread c'tor. void ThreadPool::init() { sleepWhileIdle = true; timer = new TimerThread(); push_back(new MainThread()); read_uci_options(); } // exit() cleanly terminates the threads before the program exits void ThreadPool::exit() { delete timer; // As first because check_time() accesses threads data for (iterator it = begin(); it != end(); ++it) delete *it; } // read_uci_options() updates internal threads parameters from the corresponding // UCI options and creates/destroys threads to match the requested number. Thread // objects are dynamically allocated to avoid creating in advance all possible // threads, with included pawns and material tables, if only few are used. void ThreadPool::read_uci_options() { maxThreadsPerSplitPoint = Options["Max Threads per Split Point"]; minimumSplitDepth = Options["Min Split Depth"] * ONE_PLY; size_t requested = Options["Threads"]; assert(requested > 0); while (size() < requested) push_back(new Thread()); while (size() > requested) { delete back(); pop_back(); } } // slave_available() tries to find an idle thread which is available as a slave // for the thread 'master'. Thread* ThreadPool::available_slave(Thread* master) const { for (const_iterator it = begin(); it != end(); ++it) if ((*it)->is_available_to(master)) return *it; return NULL; } // split() does the actual work of distributing the work at a node between // several available threads. If it does not succeed in splitting the node // (because no idle threads are available), the function immediately returns. // If splitting is possible, a SplitPoint object is initialized with all the // data that must be copied to the helper threads and then helper threads are // told that they have been assigned work. This will cause them to instantly // leave their idle loops and call search(). When all threads have returned from // search() then split() returns. template void Thread::split(Position& pos, Stack* ss, Value alpha, Value beta, Value* bestValue, Move* bestMove, Depth depth, Move threatMove, int moveCount, MovePicker* movePicker, int nodeType) { assert(pos.pos_is_ok()); assert(*bestValue <= alpha && alpha < beta && beta <= VALUE_INFINITE); assert(*bestValue > -VALUE_INFINITE); assert(depth >= Threads.minimumSplitDepth); assert(searching); assert(splitPointsSize < MAX_SPLITPOINTS_PER_THREAD); // Pick the next available split point from the split point stack SplitPoint& sp = splitPoints[splitPointsSize]; sp.masterThread = this; sp.parentSplitPoint = activeSplitPoint; sp.slavesMask = 1ULL << idx; sp.depth = depth; sp.bestValue = *bestValue; sp.bestMove = *bestMove; sp.threatMove = threatMove; sp.alpha = alpha; sp.beta = beta; sp.nodeType = nodeType; sp.movePicker = movePicker; sp.moveCount = moveCount; sp.pos = &pos; sp.nodes = 0; sp.cutoff = false; sp.ss = ss; // Try to allocate available threads and ask them to start searching setting // 'searching' flag. This must be done under lock protection to avoid concurrent // allocation of the same slave by another master. Threads.mutex.lock(); sp.mutex.lock(); splitPointsSize++; activeSplitPoint = &sp; activePosition = NULL; size_t slavesCnt = 1; // This thread is always included Thread* slave; while ( (slave = Threads.available_slave(this)) != NULL && ++slavesCnt <= Threads.maxThreadsPerSplitPoint && !Fake) { sp.slavesMask |= 1ULL << slave->idx; slave->activeSplitPoint = &sp; slave->searching = true; // Slave leaves idle_loop() slave->notify_one(); // Could be sleeping } // Everything is set up. The master thread enters the idle loop, from which // it will instantly launch a search, because its 'searching' flag is set. // The thread will return from the idle loop when all slaves have finished // their work at this split point. if (slavesCnt > 1 || Fake) { sp.mutex.unlock(); Threads.mutex.unlock(); Thread::idle_loop(); // Force a call to base class idle_loop() // In helpful master concept a master can help only a sub-tree of its split // point, and because here is all finished is not possible master is booked. assert(!searching); assert(!activePosition); // We have returned from the idle loop, which means that all threads are // finished. Note that setting 'searching' and decreasing splitPointsSize is // done under lock protection to avoid a race with Thread::is_available_to(). Threads.mutex.lock(); sp.mutex.lock(); } searching = true; splitPointsSize--; activeSplitPoint = sp.parentSplitPoint; activePosition = &pos; pos.set_nodes_searched(pos.nodes_searched() + sp.nodes); *bestMove = sp.bestMove; *bestValue = sp.bestValue; sp.mutex.unlock(); Threads.mutex.unlock(); } // Explicit template instantiations template void Thread::split(Position&, Stack*, Value, Value, Value*, Move*, Depth, Move, int, MovePicker*, int); template void Thread::split< true>(Position&, Stack*, Value, Value, Value*, Move*, Depth, Move, int, MovePicker*, int); // wait_for_think_finished() waits for main thread to go to sleep then returns void ThreadPool::wait_for_think_finished() { MainThread* t = main_thread(); t->mutex.lock(); while (t->thinking) sleepCondition.wait(t->mutex); t->mutex.unlock(); } // start_thinking() wakes up the main thread sleeping in MainThread::idle_loop() // so to start a new search, then returns immediately. void ThreadPool::start_thinking(const Position& pos, const LimitsType& limits, const std::vector& searchMoves, StateStackPtr& states) { wait_for_think_finished(); SearchTime = Time::now(); // As early as possible Signals.stopOnPonderhit = Signals.firstRootMove = false; Signals.stop = Signals.failedLowAtRoot = false; RootPos = pos; Limits = limits; SetupStates = states; // Ownership transfer here RootMoves.clear(); for (MoveList ml(pos); !ml.end(); ++ml) if ( searchMoves.empty() || std::count(searchMoves.begin(), searchMoves.end(), ml.move())) RootMoves.push_back(RootMove(ml.move())); main_thread()->thinking = true; main_thread()->notify_one(); // Starts main thread } stockfish-3.0.0+git20130508/Copying.txt0000644000175000017500000010575512142540127016657 0ustar oliveroliver GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program 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. This program 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. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read .