From: Fabian Fichter Date: Mon, 16 Sep 2019 19:55:09 +0000 (+0200) Subject: Merge official-stockfish/master X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=3ff4a4c865d241f5059f79bc4e4229e8a71ef204;p=fairystockfish.git Merge official-stockfish/master bench: 3815926 --- 3ff4a4c865d241f5059f79bc4e4229e8a71ef204 diff --cc src/Makefile index ce35fbc,70246f5..1a844ff --- a/src/Makefile +++ b/src/Makefile @@@ -420,12 -405,8 +420,12 @@@ help @echo "Advanced examples, for experienced users: " @echo "" @echo "make build ARCH=x86-64 COMP=clang" - @echo "make profile-build ARCH=x86-64-modern COMP=gcc COMPCXX=g++-4.8" + @echo "make profile-build ARCH=x86-64-bmi2 COMP=gcc COMPCXX=g++-4.8" @echo "" + @echo "Version for large boards (only GCC and mingw, 64-bit required): " + @echo "" + @echo "make build ARCH=x86-64 COMP=gcc largeboards=yes" + @echo "" .PHONY: help build profile-build strip install clean objclean profileclean help \ diff --cc src/evaluate.cpp index 7e0acb4,a7a091a..03f6d49 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@@ -179,9 -168,8 +180,9 @@@ namespace template Score threats() const; template Score passed() const; template Score space() const; + template Score variant() const; ScaleFactor scale_factor(Value eg) const; - Score initiative(Value eg) const; + Score initiative(Score score) const; const Position& pos; Material::Entry* me; @@@ -388,9 -344,13 +389,13 @@@ if (Pt == ROOK) { // Bonus for aligning rook with enemy pawns on the same rank/file - if (relative_rank(Us, s) >= RANK_5) - score += RookOnPawn * popcount(pos.pieces(Them, PAWN) & PseudoAttacks[ROOK][s]); + if (relative_rank(Us, s, pos.max_rank()) >= RANK_5) + score += RookOnPawn * popcount(pos.pieces(Them, PAWN) & PseudoAttacks[Us][ROOK][s]); + // Bonus for rook on the same file as a queen + if (file_bb(s) & pos.pieces(QUEEN)) + score += RookOnQueenFile; + // Bonus for rook on an open or semi-open file if (pos.is_on_semiopen_file(Us, s)) score += RookOnFile[bool(pos.is_on_semiopen_file(Them, s))]; @@@ -473,67 -407,44 +478,63 @@@ b1 = attacks_bb(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)); b2 = attacks_bb(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)); - // Enemy rooks checks - rookChecks = b1 & safe & attackedBy[Them][ROOK]; - - if (rookChecks) - kingDanger += RookSafeCheck; - else - unsafeChecks |= b1 & attackedBy[Them][ROOK]; - - // Enemy queen safe checks: we count them only if they are from squares from - // which we can't give a rook check, because rook checks are more valuable. - queenChecks = (b1 | b2) - & attackedBy[Them][QUEEN] - & safe - & ~attackedBy[Us][QUEEN] - & ~rookChecks; - - if (queenChecks) - kingDanger += QueenSafeCheck; - - // Enemy bishops checks: we count them only if they are from squares from - // which we can't give a queen check, because queen checks are more valuable. - bishopChecks = b2 - & attackedBy[Them][BISHOP] - & safe - & ~queenChecks; - - if (bishopChecks) - kingDanger += BishopSafeCheck; - else - unsafeChecks |= b2 & attackedBy[Them][BISHOP]; + std::function get_attacks = [this](Color c, PieceType pt) { + return attackedBy[c][pt] | (pos.captures_to_hand() && pos.count_in_hand(c, pt) ? ~pos.pieces() : Bitboard(0)); + }; + for (PieceType pt : pos.piece_types()) + { + switch (pt) + { + case QUEEN: + // Enemy queen safe checks: we count them only if they are from squares from + // which we can't give a rook check, because rook checks are more valuable. + queenChecks = (b1 | b2) + & get_attacks(Them, QUEEN) + & safe + & ~attackedBy[Us][QUEEN] + & ~(b1 & attackedBy[Them][ROOK]); + + if (queenChecks) + kingDanger += QueenSafeCheck; + break; + case ROOK: + case BISHOP: + case KNIGHT: + knightChecks = attacks_bb(Us, pt, ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)) & get_attacks(Them, pt) & pos.board_bb(); + if (knightChecks & safe) + kingDanger += pt == ROOK ? RookSafeCheck + : pt == BISHOP ? BishopSafeCheck + : KnightSafeCheck; + else + unsafeChecks |= knightChecks; + break; + case PAWN: + if (pos.captures_to_hand() && pos.count_in_hand(Them, pt)) + { + pawnChecks = attacks_bb(Us, pt, ksq, pos.pieces()) & ~pos.pieces() & pos.board_bb(); + if (pawnChecks & safe) + kingDanger += OtherSafeCheck; + else + unsafeChecks |= pawnChecks; + } + break; + case SHOGI_PAWN: + case KING: + break; + default: + otherChecks = attacks_bb(Us, pt, ksq, pos.pieces()) & get_attacks(Them, pt) & pos.board_bb(); + if (otherChecks & safe) + kingDanger += OtherSafeCheck; + else + unsafeChecks |= otherChecks; + } + } - // Enemy knights checks - knightChecks = pos.attacks_from(ksq) & attackedBy[Them][KNIGHT]; + if (pos.check_counting()) + kingDanger *= 2; - // Unsafe or occupied checking squares will also be considered, as long as - // the square is in the attacker's mobility area. - unsafeChecks &= mobilityArea[Them]; - - if (knightChecks & safe) - kingDanger += KnightSafeCheck; - else - unsafeChecks |= knightChecks; + Square s = file_of(ksq) == FILE_A ? ksq + EAST : file_of(ksq) == pos.max_file() ? ksq + WEST : ksq; + Bitboard kingFlank = pos.max_file() == FILE_H ? KingFlank[file_of(ksq)] : file_bb(s) | adjacent_files_bb(s); // Find the squares that opponent attacks in our king flank, and the squares // which are attacked twice in that flank. @@@ -543,13 -454,13 +544,13 @@@ int kingFlankAttacks = popcount(b1) + popcount(b2); kingDanger += kingAttackersCount[Them] * kingAttackersWeight[Them] - + 69 * kingAttacksCount[Them] - + 185 * popcount(kingRing[Us] & weak) + + 69 * kingAttacksCount[Them] * (2 + 8 * pos.check_counting() + pos.captures_to_hand()) / 2 + + 185 * popcount(kingRing[Us] & weak) * (1 + pos.captures_to_hand() + pos.check_counting()) - 100 * bool(attackedBy[Us][KNIGHT] & attackedBy[Us][KING]) - 35 * bool(attackedBy[Us][BISHOP] & attackedBy[Us][KING]) - - 10 * bool(attackedBy2[Us] & attackedBy[Us][KING]) * pos.captures_to_hand() - + 150 * popcount(pos.blockers_for_king(Us) | unsafeChecks) + + 148 * popcount(unsafeChecks) + + 98 * popcount(pos.blockers_for_king(Us)) - - 873 * !pos.count(Them) + - 873 * !(pos.major_pieces(Them) || pos.captures_to_hand()) / (1 + pos.check_counting()) - 6 * mg_value(score) / 8 + mg_value(mobility[Them] - mobility[Us]) + 5 * kingFlankAttacks * kingFlankAttacks / 16 @@@ -671,15 -562,9 +677,9 @@@ b &= ~attackedBy[Them][PAWN] & safe; // Bonus for safe pawn threats on the next move - b = pawn_attacks_bb(b) & nonPawnEnemies; + b = (pawn_attacks_bb(b) | shift(shift(pos.pieces(Us, SHOGI_PAWN)))) & nonPawnEnemies; score += ThreatByPawnPush * popcount(b); - // Our safe or protected pawns - b = pos.pieces(Us, PAWN) & safe; - - b = (pawn_attacks_bb(b) | shift(pos.pieces(Us, SHOGI_PAWN))) & nonPawnEnemies; - score += ThreatBySafePawn * popcount(b); - // Bonus for threats on the next moves against enemy queen if (pos.count(Them) == 1) { @@@ -953,15 -717,13 +953,18 @@@ // known attacking/defending status of the players. template - Score Evaluation::initiative(Value eg) const { + Score Evaluation::initiative(Score score) const { + + Value mg = mg_value(score); + Value eg = eg_value(score); - int outflanking = distance(pos.square(WHITE), pos.square(BLACK)) - - distance(pos.square(WHITE), pos.square(BLACK)); + // No initiative bonus for extinction variants + if (pos.extinction_value() != VALUE_NONE || pos.captures_to_hand() || pos.connect_n()) + return SCORE_ZERO; + + int outflanking = !pos.count(WHITE) || !pos.count(BLACK) ? 0 + : distance(pos.square(WHITE), pos.square(BLACK)) + - distance(pos.square(WHITE), pos.square(BLACK)); bool pawnsOnBothFlanks = (pos.pieces(PAWN) & QueenSide) && (pos.pieces(PAWN) & KingSide); @@@ -1065,10 -825,9 +1075,10 @@@ score += king< WHITE>() - king< BLACK>() + threats() - threats() + passed< WHITE>() - passed< BLACK>() - + space< WHITE>() - space< BLACK>(); + + space< WHITE>() - space< BLACK>() + + variant() - variant(); - score += initiative(eg_value(score)); + score += initiative(score); // Interpolate between a middlegame and a (scaled by 'sf') endgame score ScaleFactor sf = scale_factor(eg_value(score)); diff --cc src/movegen.cpp index e4c7487,fc99ec2..a3e0ab2 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@@ -316,41 -224,28 +316,41 @@@ namespace constexpr bool Checks = Type == QUIET_CHECKS; // Reduce template instantations moveList = generate_pawn_moves(pos, moveList, target); - moveList = generate_moves(pos, moveList, Us, target); - moveList = generate_moves(pos, moveList, Us, target); - moveList = generate_moves< ROOK, Checks>(pos, moveList, Us, target); - moveList = generate_moves< QUEEN, Checks>(pos, moveList, Us, target); - - if (Type != QUIET_CHECKS && Type != EVASIONS) + for (PieceType pt = PieceType(PAWN + 1); pt < KING; ++pt) + moveList = generate_moves(pos, moveList, Us, pt, target); + // generate drops + if (pos.piece_drops() && Type != CAPTURES && pos.count_in_hand(Us, ALL_PIECES)) + for (PieceType pt = PAWN; pt <= KING; ++pt) + moveList = generate_drops(pos, moveList, pt, target & ~pos.pieces(~Us)); + + if (Type != QUIET_CHECKS && Type != EVASIONS && pos.count(Us)) { Square ksq = pos.square(Us); - Bitboard b = pos.attacks_from(ksq) & target; + Bitboard b = pos.attacks_from(Us, ksq) & target; while (b) - *moveList++ = make_move(ksq, pop_lsb(&b)); + moveList = make_move_and_gating(pos, moveList, Us, ksq, pop_lsb(&b)); - if (Type != CAPTURES && pos.can_castle(CastlingRight(OO | OOO))) + if (Type != CAPTURES && pos.can_castle(CastlingRights(OO | OOO))) { if (!pos.castling_impeded(OO) && pos.can_castle(OO)) - *moveList++ = make(ksq, pos.castling_rook_square(OO)); + moveList = make_move_and_gating(pos, moveList, Us, ksq, pos.castling_rook_square(OO)); if (!pos.castling_impeded(OOO) && pos.can_castle(OOO)) - *moveList++ = make(ksq, pos.castling_rook_square(OOO)); + moveList = make_move_and_gating(pos, moveList, Us, ksq, pos.castling_rook_square(OOO)); } } + // Castling with non-king piece - if (!pos.count(Us) && Type != CAPTURES && pos.can_castle(CastlingRight(OO | OOO))) ++ if (!pos.count(Us) && Type != CAPTURES && pos.can_castle(CastlingRights(OO | OOO))) + { + Square from = make_square(FILE_E, relative_rank(Us, pos.castling_rank(), pos.max_rank())); + if (!pos.castling_impeded(OO) && pos.can_castle(OO)) + moveList = make_move_and_gating(pos, moveList, Us, from, pos.castling_rook_square(OO)); + + if (!pos.castling_impeded(OOO) && pos.can_castle(OOO)) + moveList = make_move_and_gating(pos, moveList, Us, from, pos.castling_rook_square(OOO)); + } + return moveList; } diff --cc src/pawns.cpp index 716df21,1ae65bf..199472b --- a/src/pawns.cpp +++ b/src/pawns.cpp @@@ -138,41 -137,16 +139,36 @@@ namespace } else if (!neighbours) - score -= Isolated * (1 + 2 * pos.must_capture()) + WeakUnopposed * int(!opposed); - score -= Isolated + WeakUnopposed * !opposed; ++ score -= Isolated * (1 + 2 * pos.must_capture()) + WeakUnopposed * !opposed; else if (backward) - score -= Backward + WeakUnopposed * int(!opposed); + score -= Backward + WeakUnopposed * !opposed; - if (doubled && !support) - score -= Doubled; + if (!support) + score -= Doubled * doubled + + WeakLever * more_than_one(lever); } - // Penalize the unsupported and non passed pawns attacked twice by the enemy - b = ourPawns - & doubleAttackThem - & ~(e->pawnAttacks[Us] | e->passedPawns[Us]); - score -= WeakLever * popcount(b); - + // Double pawn evaluation if there are no non-pawn pieces + if (pos.count(Us) == pos.count(Us)) + score = score * 2; + + const Square* pl_shogi = pos.squares(Us); + + ourPawns = pos.pieces(Us, SHOGI_PAWN); + theirPawns = pos.pieces(Them, SHOGI_PAWN); + + // Loop through all shogi pawns of the current color and score each one + while ((s = *pl_shogi++) != SQ_NONE) + { + assert(pos.piece_on(s) == make_piece(Us, SHOGI_PAWN)); + + neighbours = ourPawns & adjacent_files_bb(s); + + if (!neighbours) + score -= Isolated / 2; + } + return score; } @@@ -219,16 -193,16 +215,16 @@@ Score Entry::evaluate_shelter(const Pos for (File f = File(center - 1); f <= File(center + 1); ++f) { b = ourPawns & file_bb(f); - Rank ourRank = b ? relative_rank(Us, frontmost_sq(Them, b), pos.max_rank()) : RANK_1; - int ourRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : 0; ++ int ourRank = b ? relative_rank(Us, frontmost_sq(Them, b), pos.max_rank()) : 0; b = theirPawns & file_bb(f); - Rank theirRank = b ? relative_rank(Us, frontmost_sq(Them, b), pos.max_rank()) : RANK_1; - int theirRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : 0; ++ int theirRank = b ? relative_rank(Us, frontmost_sq(Them, b), pos.max_rank()) : 0; - int d = std::min(f, ~f); - bonus += make_score(ShelterStrength[d][ourRank], 0); + int d = std::min(std::min(f, File(pos.max_file() - f)), FILE_D); + bonus += make_score(ShelterStrength[d][ourRank], 0) * (1 + (pos.captures_to_hand() && ourRank <= RANK_2)); if (ourRank && (ourRank == theirRank - 1)) - bonus -= make_score(82 * (theirRank == RANK_3), 82 * (theirRank == RANK_3)); + bonus -= BlockedStorm * int(theirRank == RANK_3); else bonus -= make_score(UnblockedStorm[d][theirRank], 0); } @@@ -248,12 -221,27 +243,27 @@@ Score Entry::do_king_safety(const Posit kingSquares[Us] = ksq; castlingRights[Us] = pos.castling_rights(Us); + Score shelters[3] = { evaluate_shelter(pos, ksq), + make_score(-VALUE_INFINITE, 0), + make_score(-VALUE_INFINITE, 0) }; + + // If we can castle use the bonus after castling if it is bigger + if (pos.can_castle(Us & KING_SIDE)) - shelters[1] = evaluate_shelter(pos, relative_square(Us, SQ_G1)); ++ shelters[1] = evaluate_shelter(pos, make_square(pos.castling_kingside_file(), Us == WHITE ? RANK_1 : pos.max_rank())); + + if (pos.can_castle(Us & QUEEN_SIDE)) - shelters[2] = evaluate_shelter(pos, relative_square(Us, SQ_C1)); ++ shelters[2] = evaluate_shelter(pos, make_square(pos.castling_queenside_file(), Us == WHITE ? RANK_1 : pos.max_rank())); + + for (int i : {1, 2}) + if (mg_value(shelters[i]) > mg_value(shelters[0])) + shelters[0] = shelters[i]; + + // In endgame we like to bring our king near our closest pawn Bitboard pawns = pos.pieces(Us, PAWN); int minPawnDist = pawns ? 8 : 0; - if (pawns & PseudoAttacks[KING][ksq]) + if (pawns & PseudoAttacks[Us][KING][ksq]) minPawnDist = 1; - else while (pawns) minPawnDist = std::min(minPawnDist, distance(ksq, pop_lsb(&pawns))); diff --cc src/position.cpp index ff9cacb,6336a5e..1f683d7 --- a/src/position.cpp +++ b/src/position.cpp @@@ -471,18 -329,16 +471,17 @@@ Position& Position::set(const Variant* void Position::set_castling_right(Color c, Square rfrom) { - Square kfrom = square(c); + Square kfrom = count(c) ? square(c) : make_square(FILE_E, relative_rank(c, castling_rank(), max_rank())); - CastlingSide cs = kfrom < rfrom ? KING_SIDE : QUEEN_SIDE; - CastlingRight cr = (c | cs); + CastlingRights cr = c & (kfrom < rfrom ? KING_SIDE: QUEEN_SIDE); st->castlingRights |= cr; castlingRightsMask[kfrom] |= cr; castlingRightsMask[rfrom] |= cr; castlingRookSquare[cr] = rfrom; - Square kto = make_square(cs == KING_SIDE ? castling_kingside_file() : castling_queenside_file(), - Square kto = relative_square(c, cr & KING_SIDE ? SQ_G1 : SQ_C1); - Square rto = relative_square(c, cr & KING_SIDE ? SQ_F1 : SQ_D1); ++ Square kto = make_square(cr & KING_SIDE ? castling_kingside_file() : castling_queenside_file(), + relative_rank(c, castling_rank(), max_rank())); - Square rto = kto + (cs == KING_SIDE ? WEST : EAST); ++ Square rto = kto + (cr & KING_SIDE ? WEST : EAST); castlingPath[cr] = (between_bb(rfrom, rto) | between_bb(kfrom, kto) | rto | kto) & ~(square_bb(kfrom) | rfrom); @@@ -2013,28 -1287,26 +2012,28 @@@ bool Position::pos_is_ok() const if (std::memcmp(&si, st, sizeof(StateInfo))) assert(0 && "pos_is_ok: State"); - for (Piece pc : Pieces) - { - if ( pieceCount[pc] != popcount(pieces(color_of(pc), type_of(pc))) - || pieceCount[pc] != std::count(board, board + SQUARE_NB, pc)) - assert(0 && "pos_is_ok: Pieces"); - - for (int i = 0; i < pieceCount[pc]; ++i) - if (board[pieceList[pc][i]] != pc || index[pieceList[pc][i]] != i) - assert(0 && "pos_is_ok: Index"); - } + for (Color c : {WHITE, BLACK}) + for (PieceType pt = PAWN; pt <= KING; ++pt) + { + Piece pc = make_piece(c, pt); + if ( pieceCount[pc] != popcount(pieces(c, pt)) + || pieceCount[pc] != std::count(board, board + SQUARE_NB, pc)) + assert(0 && "pos_is_ok: Pieces"); + + for (int i = 0; i < pieceCount[pc]; ++i) + if (board[pieceList[pc][i]] != pc || index[pieceList[pc][i]] != i) + assert(0 && "pos_is_ok: Index"); + } for (Color c : { WHITE, BLACK }) - for (CastlingSide s : {KING_SIDE, QUEEN_SIDE}) + for (CastlingRights cr : {c & KING_SIDE, c & QUEEN_SIDE}) { - if (!can_castle(c | s)) + if (!can_castle(cr)) continue; - if ( piece_on(castlingRookSquare[c | s]) != make_piece(c, ROOK) - || castlingRightsMask[castlingRookSquare[c | s]] != (c | s) - || (castlingRightsMask[square(c)] & (c | s)) != (c | s)) + if ( piece_on(castlingRookSquare[cr]) != make_piece(c, ROOK) + || castlingRightsMask[castlingRookSquare[cr]] != cr + || (castlingRightsMask[square(c)] & cr) != cr) assert(0 && "pos_is_ok: Castling"); } diff --cc src/position.h index 75125aa,a0a9a30..db9756e --- a/src/position.h +++ b/src/position.h @@@ -709,16 -264,11 +709,16 @@@ inline Square Position::ep_square() con return st->epSquare; } +inline Bitboard Position::gates(Color c) const { + assert(var != nullptr); + return st->gatesBB[c]; +} + inline bool Position::is_on_semiopen_file(Color c, Square s) const { - return !(pieces(c, PAWN) & file_bb(s)); + return !(pieces(c, PAWN, SHOGI_PAWN) & file_bb(s)); } - inline bool Position::can_castle(CastlingRight cr) const { + inline bool Position::can_castle(CastlingRights cr) const { return st->castlingRights & cr; } diff --cc src/search.cpp index 9942d41,79942bc..f53382b --- a/src/search.cpp +++ b/src/search.cpp @@@ -812,19 -800,18 +816,20 @@@ namespace // Step 9. Null move search with verification search (~40 Elo) if ( !PvNode && (ss-1)->currentMove != MOVE_NULL - && (ss-1)->statScore < 23200 + && (ss-1)->statScore < 22661 && eval >= beta - && ss->staticEval >= beta - 36 * depth / ONE_PLY + 225 + && eval >= ss->staticEval + && ss->staticEval >= beta - 33 * depth / ONE_PLY + 299 - improving * 30 && !excludedMove && pos.non_pawn_material(us) + && (pos.pieces(~us) ^ pos.pieces(~us, PAWN)) + && (pos.pieces() ^ pos.pieces(BREAKTHROUGH_PIECE) ^ pos.pieces(CLOBBER_PIECE)) && (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor)) { assert(eval - beta >= 0); // Null move dynamic reduction based on depth and value - Depth R = ((823 - 150 * !pos.checking_permitted() + 67 * depth / ONE_PLY) / 256 + std::min(int(eval - beta) / 200, 3)) * ONE_PLY; - Depth R = ((835 + 70 * depth / ONE_PLY) / 256 + std::min(int(eval - beta) / 185, 3)) * ONE_PLY; ++ Depth R = ((835 - 150 * !pos.checking_permitted() + 70 * depth / ONE_PLY) / 256 + std::min(int(eval - beta) / 185, 3)) * ONE_PLY; ss->currentMove = MOVE_NULL; ss->continuationHistory = &thisThread->continuationHistory[NO_PIECE][0]; @@@ -865,10 -852,9 +870,10 @@@ // much above beta, we can (almost) safely prune the previous move. if ( !PvNode && depth >= 5 * ONE_PLY + && (pos.pieces() ^ pos.pieces(CLOBBER_PIECE)) && abs(beta) < VALUE_MATE_IN_MAX_PLY) { - Value raisedBeta = std::min(beta + 216 * (1 + pos.check_counting() + (pos.extinction_value() != VALUE_NONE)) - 48 * improving, VALUE_INFINITE); - Value raisedBeta = std::min(beta + 191 - 46 * improving, VALUE_INFINITE); ++ Value raisedBeta = std::min(beta + 191 * (1 + pos.check_counting() + (pos.extinction_value() != VALUE_NONE)) - 46 * improving, VALUE_INFINITE); MovePicker mp(pos, ttMove, raisedBeta - ss->staticEval, &thisThread->captureHistory); int probCutCount = 0; @@@ -900,9 -886,9 +905,9 @@@ } // Step 11. Internal iterative deepening (~2 Elo) - if (depth >= (8 - 2 * pos.captures_to_hand()) * ONE_PLY && !ttMove) - if (depth >= 7 * ONE_PLY && !ttMove) ++ if (depth >= (7 - 2 * pos.captures_to_hand()) * ONE_PLY && !ttMove) { - search(pos, ss, alpha, beta, depth - 7 * ONE_PLY, cutNode); + search(pos, ss, alpha, beta, depth - (7 - 2 * pos.captures_to_hand()) * ONE_PLY, cutNode); tte = TT.probe(posKey, ttHit); ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE; @@@ -951,14 -937,8 +956,8 @@@ moves_loop: // When in check, search st if (rootNode && thisThread == Threads.main() && Time.elapsed() > 3000) sync_cout << "info depth " << depth / ONE_PLY - << " currmove " << UCI::move(move, pos.is_chess960()) + << " currmove " << UCI::move(pos, move) << " currmovenumber " << moveCount + thisThread->pvIdx << sync_endl; - - // In MultiPV mode also skip moves which will be searched later as PV moves - if (rootNode && std::count(thisThread->rootMoves.begin() + thisThread->pvIdx + 1, - thisThread->rootMoves.begin() + thisThread->multiPV, move)) - continue; - if (PvNode) (ss+1)->pv = nullptr; @@@ -1062,26 -1035,23 +1061,26 @@@ lmrDepth /= ONE_PLY; // Countermoves based pruning (~20 Elo) - if ( lmrDepth < 3 + ((ss-1)->statScore > 0 || (ss-1)->moveCount == 1) + if ( lmrDepth < 4 + ((ss-1)->statScore > 0 || (ss-1)->moveCount == 1) - && (*contHist[0])[movedPiece][to_sq(move)] < CounterMovePruneThreshold - && (*contHist[1])[movedPiece][to_sq(move)] < CounterMovePruneThreshold) + && (*contHist[0])[history_slot(movedPiece)][to_sq(move)] < CounterMovePruneThreshold + && (*contHist[1])[history_slot(movedPiece)][to_sq(move)] < CounterMovePruneThreshold) continue; // Futility pruning: parent node (~2 Elo) - if ( lmrDepth < 7 + if ( lmrDepth < 6 && !inCheck + && !( pos.extinction_value() == -VALUE_MATE + && pos.extinction_piece_types().find(ALL_PIECES) == pos.extinction_piece_types().end()) - && ss->staticEval + 256 + 200 * lmrDepth <= alpha) + && ss->staticEval + 250 + 211 * lmrDepth <= alpha) continue; // Prune moves with negative SEE (~10 Elo) - if (!pos.see_ge(move, Value(-(31 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth))) + if (!pos.must_capture() && !pos.see_ge(move, Value(-(31 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth))) continue; } - else if ( (!givesCheck || !extension) + else if ( !(givesCheck && extension) - && !pos.see_ge(move, Value(-199) * (depth / ONE_PLY))) // (~20 Elo) + && !pos.must_capture() - && !pos.see_ge(move, -(PawnValueEg + 120 * pos.captures_to_hand()) * (depth / ONE_PLY))) // (~20 Elo) ++ && !pos.see_ge(move, Value(-199 - 120 * pos.captures_to_hand()) * (depth / ONE_PLY))) // (~20 Elo) continue; } @@@ -1105,11 -1075,12 +1104,13 @@@ // Step 16. Reduced depth search (LMR). If the move fails high it will be // re-searched at full depth. if ( depth >= 3 * ONE_PLY - && moveCount > 1 + 3 * rootNode + && moveCount > 1 + 2 * rootNode + && (!rootNode || thisThread->best_move_count(move) == 0) && ( !captureOrPromotion || moveCountPruning - || ss->staticEval + PieceValue[EG][pos.captured_piece()] <= alpha) + || ss->staticEval + PieceValue[EG][pos.captured_piece()] <= alpha - || cutNode)) ++ || cutNode) + && !(pos.must_capture() && MoveList(pos).size())) { Depth r = reduction(improving, depth, moveCount); @@@ -1125,10 -1096,10 +1126,10 @@@ if ((ss-1)->moveCount > 15) r -= ONE_PLY; - // Decrease reduction if move has been singularly extended + // Decrease reduction if ttMove has been singularly extended r -= singularLMR * ONE_PLY; - if (!captureOrPromotion) + if (!captureOrPromotion && !(pos.must_capture() && MoveList(pos).size())) { // Increase reduction if ttMove is a capture (~0 Elo) if (ttCapture) @@@ -1146,10 -1117,10 +1147,10 @@@ r -= 2 * ONE_PLY; ss->statScore = thisThread->mainHistory[us][from_to(move)] - + (*contHist[0])[movedPiece][to_sq(move)] - + (*contHist[1])[movedPiece][to_sq(move)] - + (*contHist[3])[movedPiece][to_sq(move)] + + (*contHist[0])[history_slot(movedPiece)][to_sq(move)] + + (*contHist[1])[history_slot(movedPiece)][to_sq(move)] + + (*contHist[3])[history_slot(movedPiece)][to_sq(move)] - - 4000; + - 4729; // Reset statScore to zero if negative and most stats shows >= 0 if ( ss->statScore < 0 diff --cc src/types.h index 69c7e11,c77d804..e553616 --- a/src/types.h +++ b/src/types.h @@@ -589,11 -363,11 +592,11 @@@ constexpr Rank operator~(Rank r) } constexpr Piece operator~(Piece pc) { - return Piece(pc ^ 8); // Swap color of piece B_KNIGHT -> W_KNIGHT + return Piece(pc ^ PIECE_TYPE_NB); // Swap color of piece BLACK KNIGHT -> WHITE KNIGHT } - constexpr CastlingRight operator|(Color c, CastlingSide s) { - return CastlingRight(WHITE_OO << ((s == QUEEN_SIDE) + 2 * c)); + constexpr CastlingRights operator&(Color c, CastlingRights cr) { + return CastlingRights((c == WHITE ? WHITE_CASTLING : BLACK_CASTLING) & cr); } constexpr Value mate_in(int ply) { @@@ -655,68 -423,41 +658,70 @@@ constexpr Direction pawn_push(Color c) return c == WHITE ? NORTH : SOUTH; } - inline MoveType type_of(Move m) { -constexpr Square from_sq(Move m) { - return Square((m >> 6) & 0x3F); ++constexpr MoveType type_of(Move m) { + return MoveType(m & (15 << (2 * SQUARE_BITS))); } constexpr Square to_sq(Move m) { - return Square(m & 0x3F); + return Square(m & SQUARE_BIT_MASK); +} + - inline Square from_sq(Move m) { - if (type_of(m) == DROP) - return SQ_NONE; - return Square((m >> SQUARE_BITS) & SQUARE_BIT_MASK); ++constexpr Square from_sq(Move m) { ++ return type_of(m) == DROP ? SQ_NONE : Square((m >> SQUARE_BITS) & SQUARE_BIT_MASK); } -constexpr int from_to(Move m) { - return m & 0xFFF; +inline int from_to(Move m) { + return to_sq(m) + (from_sq(m) << SQUARE_BITS); } -constexpr MoveType type_of(Move m) { - return MoveType(m & (3 << 14)); +inline PieceType promotion_type(Move m) { + return type_of(m) == PROMOTION ? PieceType((m >> (2 * SQUARE_BITS + MOVE_TYPE_BITS)) & (PIECE_TYPE_NB - 1)) : NO_PIECE_TYPE; } -constexpr PieceType promotion_type(Move m) { - return PieceType(((m >> 12) & 3) + KNIGHT); +inline PieceType gating_type(Move m) { + return PieceType((m >> (2 * SQUARE_BITS + MOVE_TYPE_BITS)) & (PIECE_TYPE_NB - 1)); +} + +inline Square gating_square(Move m) { + return Square((m >> (2 * SQUARE_BITS + MOVE_TYPE_BITS + PIECE_TYPE_BITS)) & SQUARE_BIT_MASK); +} + +inline bool is_gating(Move m) { + return gating_type(m) && (type_of(m) == NORMAL || type_of(m) == CASTLING); } constexpr Move make_move(Square from, Square to) { - return Move((from << 6) + to); + return Move((from << SQUARE_BITS) + to); +} + +template +inline Move make(Square from, Square to, PieceType pt = NO_PIECE_TYPE) { + return Move((pt << (2 * SQUARE_BITS + MOVE_TYPE_BITS)) + T + (from << SQUARE_BITS) + to); +} + +constexpr Move make_drop(Square to, PieceType pt_in_hand, PieceType pt_dropped) { + return Move((pt_in_hand << (2 * SQUARE_BITS + MOVE_TYPE_BITS + PIECE_TYPE_BITS)) + (pt_dropped << (2 * SQUARE_BITS + MOVE_TYPE_BITS)) + DROP + to); } + constexpr Move reverse_move(Move m) { + return make_move(to_sq(m), from_sq(m)); + } + template -constexpr Move make(Square from, Square to, PieceType pt = KNIGHT) { - return Move(T + ((pt - KNIGHT) << 12) + (from << 6) + to); +constexpr Move make_gating(Square from, Square to, PieceType pt, Square gate) { + return Move((gate << (2 * SQUARE_BITS + MOVE_TYPE_BITS + PIECE_TYPE_BITS)) + (pt << (2 * SQUARE_BITS + MOVE_TYPE_BITS)) + T + (from << SQUARE_BITS) + to); +} + +constexpr PieceType dropped_piece_type(Move m) { + return PieceType((m >> (2 * SQUARE_BITS + MOVE_TYPE_BITS)) & (PIECE_TYPE_NB - 1)); +} + +constexpr PieceType in_hand_piece_type(Move m) { + return PieceType((m >> (2 * SQUARE_BITS + MOVE_TYPE_BITS + PIECE_TYPE_BITS)) & (PIECE_TYPE_NB - 1)); } -constexpr bool is_ok(Move m) { - return from_sq(m) != to_sq(m); // Catch MOVE_NULL and MOVE_NONE +inline bool is_ok(Move m) { + return from_sq(m) != to_sq(m) || type_of(m) == PROMOTION; // Catch MOVE_NULL and MOVE_NONE } #endif // #ifndef TYPES_H_INCLUDED