From: Fabian Fichter Date: Sat, 16 Nov 2019 20:00:42 +0000 (+0100) Subject: Merge official-stockfish/master X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=4e1f3f412170cc2afd374601bdc6412c9ddae121;p=fairystockfish.git Merge official-stockfish/master bench: 4552352 --- 4e1f3f412170cc2afd374601bdc6412c9ddae121 diff --cc src/bitboard.h index fdc8848,8d748ee..e1680b8 --- a/src/bitboard.h +++ b/src/bitboard.h @@@ -162,9 -119,12 +162,15 @@@ inline Bitboard operator^( Bitboard b inline Bitboard& operator|=(Bitboard& b, Square s) { return b |= square_bb(s); } inline Bitboard& operator^=(Bitboard& b, Square s) { return b ^= square_bb(s); } +inline Bitboard operator-( Bitboard b, Square s) { return b & ~square_bb(s); } +inline Bitboard& operator-=(Bitboard& b, Square s) { return b &= ~square_bb(s); } + + inline Bitboard operator&(Square s, Bitboard b) { return b & s; } + inline Bitboard operator|(Square s, Bitboard b) { return b | s; } + inline Bitboard operator^(Square s, Bitboard b) { return b ^ s; } + + inline Bitboard operator|(Square s, Square s2) { return square_bb(s) | square_bb(s2); } + constexpr bool more_than_one(Bitboard b) { return b & (b - 1); } @@@ -458,13 -315,7 +464,13 @@@ inline Square lsb(Bitboard b) inline Square msb(Bitboard b) { assert(b); - return Square(63 ^ __builtin_clzll(b)); +#ifdef LARGEBOARDS + if (b >> 64) - return Square(SQUARE_BIT_MASK ^ __builtin_clzll(b >> 64)); - return Square(SQUARE_BIT_MASK ^ (__builtin_clzll(b) + 64)); ++ return Square(int(SQUARE_BIT_MASK) ^ __builtin_clzll(b >> 64)); ++ return Square(int(SQUARE_BIT_MASK) ^ (__builtin_clzll(b) + 64)); +#else - return Square(SQUARE_BIT_MASK ^ __builtin_clzll(b)); ++ return Square(int(SQUARE_BIT_MASK) ^ __builtin_clzll(b)); +#endif } #elif defined(_MSC_VER) // MSVC diff --cc src/endgame.cpp index 861ea77,ca38a66..8af27b9 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@@ -574,8 -413,8 +574,8 @@@ ScaleFactor Endgame::operator() && relative_rank(weakSide, pos.square(strongSide)) >= RANK_4 && relative_rank(weakSide, rsq) == RANK_3 && ( pos.pieces(weakSide, PAWN) - & pos.attacks_from(weakSide, kingSq) - & pos.attacks_from(strongSide, rsq))) - & pos.attacks_from(kingSq) ++ & pos.attacks_from(kingSq, weakSide) + & pos.attacks_from(rsq, strongSide))) return SCALE_FACTOR_DRAW; return SCALE_FACTOR_NONE; @@@ -856,14 -695,14 +856,14 @@@ ScaleFactor Endgame::operator() if ( ksq == blockSq1 && opposite_colors(ksq, wbsq) && ( bbsq == blockSq2 - || (pos.attacks_from(weakSide, blockSq2) & pos.pieces(weakSide, BISHOP)) - || (pos.attacks_from(blockSq2) & pos.pieces(weakSide, BISHOP)) ++ || (pos.attacks_from(blockSq2, weakSide) & pos.pieces(weakSide, BISHOP)) || distance(psq1, psq2) >= 2)) return SCALE_FACTOR_DRAW; else if ( ksq == blockSq2 && opposite_colors(ksq, wbsq) && ( bbsq == blockSq1 - || (pos.attacks_from(weakSide, blockSq1) & pos.pieces(weakSide, BISHOP)))) - || (pos.attacks_from(blockSq1) & pos.pieces(weakSide, BISHOP)))) ++ || (pos.attacks_from(blockSq1, weakSide) & pos.pieces(weakSide, BISHOP)))) return SCALE_FACTOR_DRAW; else return SCALE_FACTOR_NONE; @@@ -931,7 -770,7 +931,7 @@@ ScaleFactor Endgame::operator()( // King needs to get close to promoting pawn to prevent knight from blocking. // Rules for this are very tricky, so just approximate. - if (forward_file_bb(strongSide, pawnSq) & pos.attacks_from(weakSide, bishopSq)) - if (forward_file_bb(strongSide, pawnSq) & pos.attacks_from(bishopSq)) ++ if (forward_file_bb(strongSide, pawnSq) & pos.attacks_from(bishopSq, weakSide)) return ScaleFactor(distance(weakKingSq, pawnSq)); return SCALE_FACTOR_NONE; diff --cc src/evaluate.cpp index 8ff84e8,07bacf8..2315c70 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@@ -133,10 -125,12 +133,15 @@@ namespace constexpr Score PassedRank[RANK_NB] = { S(0, 0), S(10, 28), S(17, 33), S(15, 41), S(62, 72), S(168, 177), S(276, 260) }; + + // OutpostRank[Rank] contains a bonus according to the rank of the outpost + constexpr Score OutpostRank[RANK_NB] = { + S(0, 0), S(0, 0), S(0, 0), S(28, 18), S(30, 24), S(32, 19) + }; + // KingProximity contains a penalty according to distance from king + constexpr Score KingProximity = S(1, 3); + // Assorted bonuses and penalties constexpr Score BishopPawns = S( 3, 7); constexpr Score CorneredBishop = S( 50, 50); @@@ -228,11 -218,11 +233,11 @@@ void Evaluation::initialize() { constexpr Color Them = (Us == WHITE ? BLACK : WHITE); - constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH); - constexpr Direction Down = (Us == WHITE ? SOUTH : NORTH); + constexpr Direction Up = pawn_push(Us); + constexpr Direction Down = -Up; - constexpr Bitboard LowRanks = (Us == WHITE ? Rank2BB | Rank3BB : Rank7BB | Rank6BB); + Bitboard LowRanks = rank_bb(relative_rank(Us, RANK_2, pos.max_rank())) | rank_bb(relative_rank(Us, RANK_3, pos.max_rank())); - const Square ksq = pos.square(Us); + const Square ksq = pos.count(Us) ? pos.square(Us) : SQ_NONE; Bitboard dblAttackByPawn = pawn_double_attacks_bb(pos.pieces(Us, PAWN)); @@@ -241,31 -231,18 +246,30 @@@ // Squares occupied by those pawns, by our king or queen or controlled by // enemy pawns are excluded from the mobility area. - mobilityArea[Us] = ~(b | pos.pieces(Us, KING, QUEEN) | pe->pawn_attacks(Them)); + if (pos.must_capture()) + mobilityArea[Us] = AllSquares; + else + mobilityArea[Us] = ~(b | pos.pieces(Us, KING, QUEEN) | pe->pawn_attacks(Them) | shift(pos.pieces(Them, SHOGI_PAWN))); // Initialize attackedBy[] for king and pawns - attackedBy[Us][KING] = pos.count(Us) ? pos.attacks_from(Us, ksq) : Bitboard(0); - attackedBy[Us][KING] = pos.attacks_from(ksq); ++ attackedBy[Us][KING] = pos.count(Us) ? pos.attacks_from(ksq, Us) : Bitboard(0); attackedBy[Us][PAWN] = pe->pawn_attacks(Us); - attackedBy[Us][ALL_PIECES] = attackedBy[Us][KING] | attackedBy[Us][PAWN]; - attackedBy2[Us] = dblAttackByPawn | (attackedBy[Us][KING] & attackedBy[Us][PAWN]); + attackedBy[Us][SHOGI_PAWN] = shift(pos.pieces(Us, SHOGI_PAWN)); + attackedBy[Us][ALL_PIECES] = attackedBy[Us][KING] | attackedBy[Us][PAWN] | attackedBy[Us][SHOGI_PAWN]; + attackedBy2[Us] = (attackedBy[Us][KING] & attackedBy[Us][PAWN]) + | (attackedBy[Us][KING] & attackedBy[Us][SHOGI_PAWN]) + | (attackedBy[Us][PAWN] & attackedBy[Us][SHOGI_PAWN]) + | dblAttackByPawn; // Init our king safety tables - kingRing[Us] = attackedBy[Us][KING]; - if (pos.count(Us) && relative_rank(Us, ksq, pos.max_rank()) == RANK_1) - kingRing[Us] |= shift(kingRing[Us]); - - if (pos.count(Us) && file_of(ksq) == pos.max_file()) - kingRing[Us] |= shift(kingRing[Us]); - - else if (pos.count(Us) && file_of(ksq) == FILE_A) - kingRing[Us] |= shift(kingRing[Us]); - Square s = make_square(clamp(file_of(ksq), FILE_B, FILE_G), - clamp(rank_of(ksq), RANK_2, RANK_7)); - kingRing[Us] = s | PseudoAttacks[KING][s]; ++ if (!pos.count(Us)) ++ kingRing[Us] = Bitboard(0); ++ else ++ { ++ Square s = make_square(clamp(file_of(ksq), FILE_B, File(pos.max_file() - 1)), ++ clamp(rank_of(ksq), RANK_2, Rank(pos.max_rank() - 1))); ++ kingRing[Us] = s | PseudoAttacks[Us][KING][s]; ++ } kingAttackersCount[Them] = popcount(kingRing[Us] & pe->pawn_attacks(Them)); kingAttacksCount[Them] = kingAttackersWeight[Them] = 0; @@@ -279,14 -253,14 +283,14 @@@ // Evaluation::pieces() scores pieces of a given color and type - template template - Score Evaluation::pieces() { + template template + Score Evaluation::pieces(PieceType Pt) { constexpr Color Them = (Us == WHITE ? BLACK : WHITE); - constexpr Direction Down = (Us == WHITE ? SOUTH : NORTH); + constexpr Direction Down = -pawn_push(Us); constexpr Bitboard OutpostRanks = (Us == WHITE ? Rank4BB | Rank5BB | Rank6BB : Rank5BB | Rank4BB | Rank3BB); - const Square* pl = pos.squares(Us); + const Square* pl = pos.squares(Us, Pt); Bitboard b, bb; Score score = SCORE_ZERO; @@@ -546,18 -447,16 +550,18 @@@ int kingFlankAttacks = popcount(b1) + popcount(b2); kingDanger += kingAttackersCount[Them] * kingAttackersWeight[Them] - + 185 * popcount(kingRing[Us] & weak) + + kingAttackersCountInHand[Them] * kingAttackersWeight[Them] + + kingAttackersCount[Them] * kingAttackersWeightInHand[Them] - + 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]) + 148 * popcount(unsafeChecks) + 98 * popcount(pos.blockers_for_king(Us)) - + 69 * kingAttacksCount[Them] ++ + 69 * kingAttacksCount[Them] * (2 + 8 * pos.check_counting() + pos.captures_to_hand()) / 2 + + 3 * kingFlankAttacks * kingFlankAttacks / 8 + + mg_value(mobility[Them] - mobility[Us]) - - 873 * !pos.count(Them) + - 873 * !(pos.major_pieces(Them) || pos.captures_to_hand() || pos.xiangqi_general()) / (1 + pos.check_counting()) + - 100 * bool(attackedBy[Us][KNIGHT] & attackedBy[Us][KING]) + - 35 * bool(attackedBy[Us][BISHOP] & attackedBy[Us][KING]) - 6 * mg_value(score) / 8 - + mg_value(mobility[Them] - mobility[Us]) - + 3 * kingFlankAttacks * kingFlankAttacks / 8 - 7; // Transform the kingDanger units into a Score, and subtract it from the evaluation @@@ -680,12 -554,12 +684,12 @@@ Square s = pos.square(Them); safe = mobilityArea[Us] & ~stronglyProtected; - b = attackedBy[Us][KNIGHT] & pos.attacks_from(Us, s); - b = attackedBy[Us][KNIGHT] & pos.attacks_from(s); ++ b = attackedBy[Us][KNIGHT] & pos.attacks_from(s, Us); score += KnightOnQueen * popcount(b & safe); - b = (attackedBy[Us][BISHOP] & pos.attacks_from(Us, s)) - | (attackedBy[Us][ROOK ] & pos.attacks_from(Us, s)); - b = (attackedBy[Us][BISHOP] & pos.attacks_from(s)) - | (attackedBy[Us][ROOK ] & pos.attacks_from(s)); ++ b = (attackedBy[Us][BISHOP] & pos.attacks_from(s, Us)) ++ | (attackedBy[Us][ROOK ] & pos.attacks_from(s, Us)); score += SliderOnQueen * popcount(b & safe & attackedBy2[Us]); } @@@ -703,10 -577,10 +707,10 @@@ Score Evaluation::passed() const { constexpr Color Them = (Us == WHITE ? BLACK : WHITE); - constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH); + constexpr Direction Up = pawn_push(Us); auto king_proximity = [&](Color c, Square s) { - return std::min(distance(pos.square(c), s), 5); + return pos.count(c) ? std::min(distance(pos.square(c), s), 5) : 5; }; Bitboard b, bb, squaresToQueen, unsafeSquares; @@@ -720,8 -594,7 +724,7 @@@ assert(!(pos.pieces(Them, PAWN) & forward_file_bb(Us, s + Up))); - int r = relative_rank(Us, s); + int r = std::max(RANK_8 - std::max(pos.promotion_rank() - relative_rank(Us, s, pos.max_rank()), 0), 0); - File f = file_of(s); Score bonus = PassedRank[r]; @@@ -775,36 -644,7 +778,36 @@@ || (pos.pieces(PAWN) & (s + Up))) bonus = bonus / 2; - score += bonus - PassedFile * std::min(f, File(pos.max_file() - f)); - score += bonus - PassedFile * map_to_queenside(file_of(s)); ++ score += bonus - PassedFile * std::min(file_of(s), File(pos.max_file() - file_of(s))); + } + + // Scale by maximum promotion piece value + Value maxMg = VALUE_ZERO, maxEg = VALUE_ZERO; + for (PieceType pt : pos.promotion_piece_types()) + { + maxMg = std::max(maxMg, PieceValue[MG][pt]); + maxEg = std::max(maxEg, PieceValue[EG][pt]); + } + score = make_score(mg_value(score) * int(maxMg - PawnValueMg) / (QueenValueMg - PawnValueMg), + eg_value(score) * int(maxEg - PawnValueEg) / (QueenValueEg - PawnValueEg)); + + // Score passed shogi pawns + const Square* pl = pos.squares(Us, SHOGI_PAWN); + Square s; + + PieceType pt = pos.promoted_piece_type(SHOGI_PAWN); + if (pt != NO_PIECE_TYPE) + { + while ((s = *pl++) != SQ_NONE) + { + if ((pos.pieces(Them, SHOGI_PAWN) & forward_file_bb(Us, s)) || relative_rank(Us, s, pos.max_rank()) == pos.max_rank()) + continue; + + Square blockSq = s + Up; + int d = std::max(pos.promotion_rank() - relative_rank(Us, s, pos.max_rank()), 1); + d += !!(attackedBy[Them][ALL_PIECES] & ~attackedBy2[Us] & blockSq); + score += make_score(PieceValue[MG][pt], PieceValue[EG][pt]) / (4 * d * d); + } } if (T) @@@ -1004,9 -751,9 +1007,9 @@@ && pos.non_pawn_material() == 2 * BishopValueMg) sf = 16 + 4 * pe->passed_count(); else - sf = std::min(sf, 36 + (pos.opposite_bishops() ? 2 : 7) * pos.count(strongSide)); + sf = std::min(sf, 36 + (pos.opposite_bishops() ? 2 : 7) * (pos.count(strongSide) + pos.count(strongSide))); - sf = std::max(0, sf - (pos.rule50_count() - 12) / 4 ); + sf = std::max(0, sf - (pos.rule50_count() - 12) / 4); } return ScaleFactor(sf); diff --cc src/movegen.cpp index 6232eac,0b91582..03ac9ff --- a/src/movegen.cpp +++ b/src/movegen.cpp @@@ -84,23 -54,17 +84,25 @@@ namespace // Compute some compile time parameters relative to the white side constexpr Color Them = (Us == WHITE ? BLACK : WHITE); - constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH); - constexpr Direction Down = (Us == WHITE ? SOUTH : NORTH); - constexpr Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB); - constexpr Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); + constexpr Direction Up = pawn_push(Us); ++ constexpr Direction Down = -pawn_push(Us); constexpr Direction UpRight = (Us == WHITE ? NORTH_EAST : SOUTH_WEST); constexpr Direction UpLeft = (Us == WHITE ? NORTH_WEST : SOUTH_EAST); - const Square ksq = pos.square(Them); ++ const Square ksq = pos.count(Them) ? pos.square(Them) : SQ_NONE; ++ ++ Bitboard TRank8BB = pos.mandatory_pawn_promotion() ? rank_bb(relative_rank(Us, pos.promotion_rank(), pos.max_rank())) ++ : promotion_zone_bb(Us, pos.promotion_rank(), pos.max_rank()); ++ Bitboard TRank7BB = shift(TRank8BB); + // Define squares a pawn can pass during a double step + Bitboard TRank3BB = rank_bb(relative_rank(Us, Rank(pos.double_step_rank() + 1), pos.max_rank())); + if (pos.first_rank_double_steps()) + TRank3BB |= rank_bb(relative_rank(Us, RANK_2, pos.max_rank())); + Bitboard emptySquares; - Bitboard TRank8BB = pos.mandatory_pawn_promotion() ? rank_bb(relative_rank(Us, pos.promotion_rank(), pos.max_rank())) - : promotion_zone_bb(Us, pos.promotion_rank(), pos.max_rank()); - Bitboard TRank7BB = shift(TRank8BB); Bitboard pawnsOn7 = pos.pieces(Us, PAWN) & TRank7BB; - Bitboard pawnsNotOn7 = pos.pieces(Us, PAWN) & ~TRank7BB; + Bitboard pawnsNotOn7 = pos.pieces(Us, PAWN) & (pos.mandatory_pawn_promotion() ? ~TRank7BB : AllSquares); Bitboard enemies = (Type == EVASIONS ? pos.pieces(Them) & target: Type == CAPTURES ? target : pos.pieces(Them)); @@@ -119,12 -83,10 +121,10 @@@ b2 &= target; } - if (Type == QUIET_CHECKS) + if (Type == QUIET_CHECKS && pos.count(Them)) { - Square ksq = pos.square(Them); - - b1 &= pos.attacks_from(Them, ksq); - b2 &= pos.attacks_from(Them, ksq); + b1 &= pos.attacks_from(ksq, Them); + b2 &= pos.attacks_from(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 @@@ -316,19 -221,17 +316,19 @@@ 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(Us, ksq) & target; - Bitboard b = pos.attacks_from(ksq) & target; ++ Bitboard b = pos.attacks_from(ksq, Us) & 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(CastlingRights(OO | OOO))) { @@@ -450,18 -319,7 +450,18 @@@ ExtMove* generate(const Posit Color us = pos.side_to_move(); Square ksq = pos.square(us); Bitboard sliderAttacks = 0; - Bitboard sliders = pos.checkers() & ~pos.pieces(KNIGHT, PAWN); + Bitboard sliders = pos.checkers(); + + // Consider all evasion moves for special pieces + if (sliders & (pos.pieces(CANNON, BANNER) | pos.pieces(HORSE, ELEPHANT))) + { + Bitboard target = pos.board_bb() & ~pos.pieces(us); - Bitboard b = pos.attacks_from(us, ksq) & target; ++ Bitboard b = pos.attacks_from(ksq, us) & target; + while (b) + moveList = make_move_and_gating(pos, moveList, us, ksq, pop_lsb(&b)); + return us == WHITE ? generate_all(pos, moveList, target) + : generate_all(pos, moveList, target); + } // Find all the squares attacked by slider checkers. We will remove them from // the king evasions in order to skip known illegal moves, which avoids any @@@ -473,9 -331,9 +473,9 @@@ } // Generate evasions for king, capture and non capture moves - Bitboard b = pos.attacks_from(us, ksq) & ~pos.pieces(us) & ~sliderAttacks; - Bitboard b = pos.attacks_from(ksq) & ~pos.pieces(us) & ~sliderAttacks; ++ Bitboard b = pos.attacks_from(ksq, us) & ~pos.pieces(us) & ~sliderAttacks; while (b) - *moveList++ = make_move(ksq, pop_lsb(&b)); + moveList = make_move_and_gating(pos, moveList, us, ksq, pop_lsb(&b)); if (more_than_one(pos.checkers())) return moveList; // Double check, only a king move can save the day diff --cc src/pawns.cpp index 35e35ed,3ddf703..904675b --- a/src/pawns.cpp +++ b/src/pawns.cpp @@@ -107,9 -107,8 +107,9 @@@ namespace // A pawn is backward when it is behind all pawns of the same color on // the adjacent files and cannot safely advance. - backward = !(neighbours & forward_ranks_bb(Them, s + Up)) - && (leverPush | blocked); + backward = is_ok(s + Up) + && !(neighbours & forward_ranks_bb(Them, s + Up)) - && (stoppers & (leverPush | blocked)); ++ && (stoppers & blocked); // Compute additional span if pawn is not backward nor blocked if (!backward && !blocked) diff --cc src/position.cpp index c76e99f,6336a5e..251680c --- a/src/position.cpp +++ b/src/position.cpp @@@ -999,20 -618,18 +999,20 @@@ bool Position::pseudo_legal(const Move { // We have already handled promotion moves, so destination // cannot be on the 8th/1st rank. - if ((Rank8BB | Rank1BB) & to) + if (mandatory_pawn_promotion() && rank_of(to) == relative_rank(us, promotion_rank(), max_rank())) return false; - if ( !(attacks_from(us, from) & pieces(~us) & to) // Not a capture + if ( !(attacks_from(from, us) & pieces(~us) & to) // Not a capture && !((from + pawn_push(us) == to) && empty(to)) // Not a single push && !( (from + 2 * pawn_push(us) == to) // Not a double push - && (rank_of(from) == relative_rank(us, RANK_2)) + && (rank_of(from) == relative_rank(us, double_step_rank(), max_rank()) + || (first_rank_double_steps() && rank_of(from) == relative_rank(us, RANK_1, max_rank()))) && empty(to) - && empty(to - pawn_push(us)))) + && empty(to - pawn_push(us)) + && double_step_enabled())) return false; } - else if (!(attacks_from(type_of(pc), from) & to)) + else if (!((capture(m) ? attacks_from(us, type_of(pc), from) : moves_from(us, type_of(pc), from)) & to)) return false; // Evasions generator already takes care to avoid some kind of illegal moves @@@ -1292,9 -825,8 +1292,9 @@@ void Position::do_move(Move m, StateInf if (type_of(pc) == PAWN) { // Set en-passant square if the moved pawn can be captured - if ( (int(to) ^ int(from)) == 16 + if ( std::abs(int(to) - int(from)) == 2 * NORTH + && relative_rank(us, rank_of(from), max_rank()) == double_step_rank() - && (attacks_from(us, to - pawn_push(us)) & pieces(them, PAWN))) + && (attacks_from(to - pawn_push(us), us) & pieces(them, PAWN))) { st->epSquare = to - pawn_push(us); k ^= Zobrist::enpassant[file_of(st->epSquare)]; diff --cc src/position.h index d0eb490,2ec2729..d572cd8 --- a/src/position.h +++ b/src/position.h @@@ -194,13 -112,11 +194,13 @@@ public // Attacks to/from a given square Bitboard attackers_to(Square s) const; + Bitboard attackers_to(Square s, Color c) const; Bitboard attackers_to(Square s, Bitboard occupied) const; - Bitboard attacks_from(PieceType pt, Square s) const; - template Bitboard attacks_from(Square s) const; + Bitboard attackers_to(Square s, Bitboard occupied, Color c) const; + Bitboard attacks_from(Color c, PieceType pt, Square s) const; - template Bitboard attacks_from(Color c, Square s) const; + template Bitboard attacks_from(Square s, Color c) const; - Bitboard slider_blockers(Bitboard sliders, Square s, Bitboard& pinners) const; + Bitboard moves_from(Color c, PieceType pt, Square s) const; + Bitboard slider_blockers(Bitboard sliders, Square s, Bitboard& pinners, Color c) const; // Properties of moves bool legal(Move m) const; @@@ -777,16 -285,21 +777,16 @@@ inline Square Position::castling_rook_s } template - inline Bitboard Position::attacks_from(Color c, Square s) const { -inline Bitboard Position::attacks_from(Square s) const { - static_assert(Pt != PAWN, "Pawn attacks need color"); - - return Pt == BISHOP || Pt == ROOK ? attacks_bb(s, byTypeBB[ALL_PIECES]) - : Pt == QUEEN ? attacks_from(s) | attacks_from(s) - : PseudoAttacks[Pt][s]; ++inline Bitboard Position::attacks_from(Square s, Color c) const { + return attacks_bb(c, Pt, s, byTypeBB[ALL_PIECES]) & board_bb(c, Pt); } -template<> -inline Bitboard Position::attacks_from(Square s, Color c) const { - return PawnAttacks[c][s]; +inline Bitboard Position::attacks_from(Color c, PieceType pt, Square s) const { + return attacks_bb(c, pt, s, byTypeBB[ALL_PIECES]) & board_bb(c, pt); } -inline Bitboard Position::attacks_from(PieceType pt, Square s) const { - return attacks_bb(pt, s, byTypeBB[ALL_PIECES]); +inline Bitboard Position::moves_from(Color c, PieceType pt, Square s) const { + return moves_bb(c, pt, s, byTypeBB[ALL_PIECES]) & board_bb(c, pt); } inline Bitboard Position::attackers_to(Square s) const { @@@ -925,7 -430,7 +925,7 @@@ inline void Position::move_piece(Piece // index[from] is not updated and becomes stale. This works as long as index[] // is accessed just by known occupied squares. - Bitboard fromTo = square_bb(from) ^ square_bb(to); - Bitboard fromTo = from | to; ++ Bitboard fromTo = square_bb(from) ^ to; // from == to needs to cancel out byTypeBB[ALL_PIECES] ^= fromTo; byTypeBB[type_of(pc)] ^= fromTo; byColorBB[color_of(pc)] ^= fromTo; diff --cc src/psqt.cpp index 82d306f,60d17ad..83c8de3 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@@ -91,18 -77,17 +91,18 @@@ constexpr Score Bonus[PIECE_TYPE_NB][RA { S(-4,-38), S(10,-18), S( 6,-12), S( 8, 1) }, { S(-5,-50), S( 6,-27), S(10,-24), S( 8, -8) }, { S(-2,-75), S(-2,-52), S( 1,-43), S(-2,-36) } - }, - { // King + } +}; + +constexpr Score KingBonus[RANK_NB][int(FILE_NB) / 2] = { - { S(272, 0), S(325, 41), S(273, 80), S(190, 93) }, - { S(277, 57), S(305, 98), S(241,138), S(183,131) }, - { S(198, 86), S(253,138), S(168,165), S(120,173) }, - { S(169,103), S(191,152), S(136,168), S(108,169) }, - { S(145, 98), S(176,166), S(112,197), S( 69,194) }, - { S(122, 87), S(159,164), S( 85,174), S( 36,189) }, - { S( 87, 40), S(120, 99), S( 64,128), S( 25,141) }, - { S( 64, 5), S( 87, 60), S( 49, 75), S( 0, 75) } + { S(271, 1), S(327, 45), S(270, 85), S(192, 76) }, + { S(278, 53), S(303,100), S(230,133), S(174,135) }, + { S(195, 88), S(258,130), S(169,169), S(120,175) }, + { S(164,103), S(190,156), S(138,172), S( 98,172) }, + { S(154, 96), S(179,166), S(105,199), S( 70,199) }, + { S(123, 92), S(145,172), S( 81,184), S( 31,191) }, + { S( 88, 47), S(120,121), S( 65,116), S( 33,131) }, + { S( 59, 11), S( 89, 59), S( 45, 73), S( -1, 78) } - } }; constexpr Score PBonus[RANK_NB][FILE_NB] = diff --cc src/search.cpp index 15fd1e6,b484dcb..f3248ae --- a/src/search.cpp +++ b/src/search.cpp @@@ -680,9 -659,9 +681,9 @@@ namespace // 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 = pos.key() ^ Key(excludedMove << 16); // Isn't a very good hash + posKey = pos.key() ^ (Key(excludedMove) << 16); // Isn't a very good hash tte = TT.probe(posKey, ttHit); - ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE; + ttValue = ttHit ? value_from_tt(tte->value(), ss->ply, pos.rule50_count()) : VALUE_NONE; ttMove = rootNode ? thisThread->rootMoves[thisThread->pvIdx].pv[0] : ttHit ? tte->move() : MOVE_NONE; ttPv = PvNode || (ttHit && tte->is_pv()); @@@ -929,12 -894,12 +930,12 @@@ } // Step 11. Internal iterative deepening (~2 Elo) - if (depth >= 7 && !ttMove) + if (depth >= (7 - 2 * pos.captures_to_hand()) && !ttMove) { - search(pos, ss, alpha, beta, depth - 7, cutNode); + search(pos, ss, alpha, beta, depth - (7 - 2 * pos.captures_to_hand()), cutNode); tte = TT.probe(posKey, ttHit); - ttValue = ttHit ? value_from_tt(tte->value(), ss->ply) : VALUE_NONE; + ttValue = ttHit ? value_from_tt(tte->value(), ss->ply, pos.rule50_count()) : VALUE_NONE; ttMove = ttHit ? tte->move() : MOVE_NONE; } @@@ -1072,13 -1022,8 +1065,9 @@@ moves_loop: // When in check, search st if ( !captureOrPromotion && !givesCheck - && (!PvNode || !pos.advanced_pawn_push(move) || pos.non_pawn_material(~us) > BishopValueMg)) + && (!pos.must_capture() || !pos.attackers_to(to_sq(move), ~us)) - && (!pos.advanced_pawn_push(move) || pos.non_pawn_material(~us) > BishopValueMg || pos.count(us) == pos.count(us))) ++ && (!PvNode || !pos.advanced_pawn_push(move) || pos.non_pawn_material(~us) > BishopValueMg || pos.count(us) == pos.count(us))) { - // Move count based pruning - if (moveCountPruning) - continue; - // Reduced depth of the next LMR search int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount), 0); @@@ -1324,22 -1265,12 +1313,12 @@@ if (!moveCount) bestValue = excludedMove ? alpha - : inCheck ? mated_in(ss->ply) : VALUE_DRAW; + : inCheck ? pos.checkmate_value(ss->ply) : pos.stalemate_value(ss->ply); - else if (bestMove) - { - // Quiet best move: update move sorting heuristics - if (!pos.capture_or_promotion(bestMove)) - update_quiet_stats(pos, ss, bestMove, quietsSearched, quietCount, - stat_bonus(depth + (bestValue > beta + PawnValueMg))); - - update_capture_stats(pos, bestMove, capturesSearched, captureCount, stat_bonus(depth + 1)); - // Extra penalty for a quiet TT or main killer move in previous ply when it gets refuted - if ( ((ss-1)->moveCount == 1 || ((ss-1)->currentMove == (ss-1)->killers[0])) - && !priorCapture) - update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -stat_bonus(depth + 1)); + else if (bestMove) + update_all_stats(pos, ss, bestMove, bestValue, beta, prevSq, + quietsSearched, quietCount, capturesSearched, captureCount, depth); - } // Bonus for prior countermove that caused the fail low else if ( (depth >= 3 || PvNode) && !priorCapture) @@@ -1622,36 -1544,59 +1601,59 @@@ } - // update_continuation_histories() updates histories of the move pairs formed - // by moves at ply -1, -2, and -4 with current move. + // update_all_stats() updates stats at the end of search() when a bestMove is found - void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) { + void update_all_stats(const Position& pos, Stack* ss, Move bestMove, Value bestValue, Value beta, Square prevSq, + Move* quietsSearched, int quietCount, Move* capturesSearched, int captureCount, Depth depth) { - for (int i : {1, 2, 4, 6}) - if (is_ok((ss-i)->currentMove)) - (*(ss-i)->continuationHistory)[history_slot(pc)][to] << bonus; - } + int bonus1, bonus2; + Color us = pos.side_to_move(); + Thread* thisThread = pos.this_thread(); + CapturePieceToHistory& captureHistory = thisThread->captureHistory; + Piece moved_piece = pos.moved_piece(bestMove); + PieceType captured = type_of(pos.piece_on(to_sq(bestMove))); + + bonus1 = stat_bonus(depth + 1); + bonus2 = bestValue > beta + PawnValueMg ? bonus1 // larger bonus + : stat_bonus(depth); // smaller bonus + + if (!pos.capture_or_promotion(bestMove)) + { + update_quiet_stats(pos, ss, bestMove, bonus2); + + // Decrease all the non-best quiet moves + for (int i = 0; i < quietCount; ++i) + { + thisThread->mainHistory[us][from_to(quietsSearched[i])] << -bonus2; + update_continuation_histories(ss, pos.moved_piece(quietsSearched[i]), to_sq(quietsSearched[i]), -bonus2); + } + } + else + captureHistory[moved_piece][to_sq(bestMove)][captured] << bonus1; + // Extra penalty for a quiet TT or main killer move in previous ply when it gets refuted + if ( ((ss-1)->moveCount == 1 || ((ss-1)->currentMove == (ss-1)->killers[0])) + && !pos.captured_piece()) + update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -bonus1); - // update_capture_stats() updates move sorting heuristics when a new capture best move is found + // Decrease all the non-best capture moves + for (int i = 0; i < captureCount; ++i) + { + moved_piece = pos.moved_piece(capturesSearched[i]); + captured = type_of(pos.piece_on(to_sq(capturesSearched[i]))); + captureHistory[moved_piece][to_sq(capturesSearched[i])][captured] << -bonus1; + } + } - void update_capture_stats(const Position& pos, Move move, - Move* captures, int captureCount, int bonus) { - CapturePieceToHistory& captureHistory = pos.this_thread()->captureHistory; - Piece moved_piece = pos.moved_piece(move); - PieceType captured = type_of(pos.piece_on(to_sq(move))); + // update_continuation_histories() updates histories of the move pairs formed + // by moves at ply -1, -2, and -4 with current move. - if (pos.capture_or_promotion(move)) - captureHistory[moved_piece][to_sq(move)][captured] << bonus; + void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) { - // Decrease all the other played capture moves - for (int i = 0; i < captureCount; ++i) - { - moved_piece = pos.moved_piece(captures[i]); - captured = type_of(pos.piece_on(to_sq(captures[i]))); - captureHistory[moved_piece][to_sq(captures[i])][captured] << -bonus; - } + for (int i : {1, 2, 4, 6}) + if (is_ok((ss-i)->currentMove)) - (*(ss-i)->continuationHistory)[pc][to] << bonus; ++ (*(ss-i)->continuationHistory)[history_slot(pc)][to] << bonus; } diff --cc src/thread.cpp index a8c18a6,6eb00d6..53d214a --- a/src/thread.cpp +++ b/src/thread.cpp @@@ -207,10 -207,10 +207,10 @@@ void ThreadPool::start_thinking(Positio for (Thread* th : *this) { - th->shuffleExts = th->nodes = th->tbHits = th->nmpMinPly = 0; + th->nodes = th->tbHits = th->nmpMinPly = 0; th->rootDepth = th->completedDepth = 0; th->rootMoves = rootMoves; - th->rootPos.set(pos.fen(), pos.is_chess960(), &setupStates->back(), th); + th->rootPos.set(pos.variant(), pos.fen(), pos.is_chess960(), &setupStates->back(), th); } setupStates->back() = tmp; diff --cc src/types.h index aee2271,13c3bbf..6f1eb9a --- a/src/types.h +++ b/src/types.h @@@ -311,40 -180,10 +311,40 @@@ enum Value : int VALUE_MATED_IN_MAX_PLY = -VALUE_MATE + 2 * MAX_PLY, PawnValueMg = 128, PawnValueEg = 213, - KnightValueMg = 782, KnightValueEg = 865, - BishopValueMg = 830, BishopValueEg = 918, - RookValueMg = 1289, RookValueEg = 1378, - QueenValueMg = 2529, QueenValueEg = 2687, + KnightValueMg = 781, KnightValueEg = 854, + BishopValueMg = 825, BishopValueEg = 915, + RookValueMg = 1276, RookValueEg = 1380, + QueenValueMg = 2538, QueenValueEg = 2682, + FersValueMg = 420, FersValueEg = 450, + AlfilValueMg = 330, AlfilValueEg = 300, + FersAlfilValueMg = 600, FersAlfilValueEg = 600, + SilverValueMg = 630, SilverValueEg = 630, + AiwokValueMg = 2500, AiwokValueEg = 2500, + BersValueMg = 2000, BersValueEg = 2000, + ArchbishopValueMg = 2200, ArchbishopValueEg = 2200, + ChancellorValueMg = 2300, ChancellorValueEg = 2600, + AmazonValueMg = 3000, AmazonValueEg = 3000, + KnibisValueMg = 1100, KnibisValueEg = 1200, + BiskniValueMg = 750, BiskniValueEg = 700, + KnirooValueMg = 900, KnirooValueEg = 900, + RookniValueMg = 900, RookniValueEg = 900, + ShogiPawnValueMg = 90, ShogiPawnValueEg = 100, + LanceValueMg = 350, LanceValueEg = 250, + ShogiKnightValueMg = 350, ShogiKnightValueEg = 300, + EuroShogiKnightValueMg = 400, EuroShogiKnightValueEg = 400, + GoldValueMg = 640, GoldValueEg = 640, + DragonHorseValueMg = 1500, DragonHorseValueEg = 1500, + ClobberPieceValueMg = 300, ClobberPieceValueEg = 300, + BreakthroughPieceValueMg = 300, BreakthroughPieceValueEg = 300, + ImmobilePieceValueMg = 100, ImmobilePieceValueEg = 100, + CannonPieceValueMg = 800, CannonPieceValueEg = 700, + SoldierValueMg = 150, SoldierValueEg = 300, + HorseValueMg = 500, HorseValueEg = 800, + ElephantValueMg = 300, ElephantValueEg = 300, + BannerValueMg = 3500, BannerValueEg = 3500, + WazirValueMg = 400, WazirValueEg = 400, + CommonerValueMg = 700, CommonerValueEg = 900, + CentaurValueMg = 1500, CentaurValueEg = 1500, MidgameLimit = 15258, EndgameLimit = 3915 };