Merge official-stockfish/master
authorFabian Fichter <ianfab@users.noreply.github.com>
Mon, 16 Sep 2019 19:55:09 +0000 (21:55 +0200)
committerFabian Fichter <ianfab@users.noreply.github.com>
Mon, 16 Sep 2019 19:55:31 +0000 (21:55 +0200)
bench: 3815926

12 files changed:
1  2 
src/Makefile
src/bitboard.h
src/endgame.h
src/evaluate.cpp
src/movegen.cpp
src/pawns.cpp
src/position.cpp
src/position.h
src/search.cpp
src/syzygy/tbprobe.cpp
src/thread.cpp
src/types.h

diff --cc 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/bitboard.h
Simple merge
diff --cc src/endgame.h
Simple merge
@@@ -179,9 -168,8 +180,9 @@@ namespace 
      template<Color Us> Score threats() const;
      template<Color Us> Score passed() const;
      template<Color Us> Score space() const;
 +    template<Color Us> 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;
          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))];
      b1 = attacks_bb<ROOK  >(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN));
      b2 = attacks_bb<BISHOP>(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 <Bitboard (Color, PieceType)> 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<KNIGHT>(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.
      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<QUEEN>(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
      b &= ~attackedBy[Them][PAWN] & safe;
  
      // Bonus for safe pawn threats on the next move
 -    b = pawn_attacks_bb<Us>(b) & nonPawnEnemies;
 +    b = (pawn_attacks_bb<Us>(b) | shift<Up>(shift<Up>(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<Us>(b) | shift<Up>(pos.pieces(Us, SHOGI_PAWN))) & nonPawnEnemies;
-     score += ThreatBySafePawn * popcount(b);
      // Bonus for threats on the next moves against enemy queen
      if (pos.count<QUEEN>(Them) == 1)
      {
    // known attacking/defending status of the players.
  
    template<Tracing T>
-   Score Evaluation<T>::initiative(Value eg) const {
+   Score Evaluation<T>::initiative(Score score) const {
+     Value mg = mg_value(score);
+     Value eg = eg_value(score);
  
 -    int outflanking =  distance<File>(pos.square<KING>(WHITE), pos.square<KING>(BLACK))
 -                     - distance<Rank>(pos.square<KING>(WHITE), pos.square<KING>(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<KING>(WHITE) || !pos.count<KING>(BLACK) ? 0
 +                     :  distance<File>(pos.square<KING>(WHITE), pos.square<KING>(BLACK))
 +                      - distance<Rank>(pos.square<KING>(WHITE), pos.square<KING>(BLACK));
  
      bool pawnsOnBothFlanks =   (pos.pieces(PAWN) & QueenSide)
                              && (pos.pieces(PAWN) & KingSide);
      score +=  king<   WHITE>() - king<   BLACK>()
              + threats<WHITE>() - threats<BLACK>()
              + passed< WHITE>() - passed< BLACK>()
 -            + space<  WHITE>() - space<  BLACK>();
 +            + space<  WHITE>() - space<  BLACK>()
 +            + variant<WHITE>() - variant<BLACK>();
  
-     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
@@@ -316,41 -224,28 +316,41 @@@ namespace 
      constexpr bool Checks = Type == QUIET_CHECKS; // Reduce template instantations
  
      moveList = generate_pawn_moves<Us, Type>(pos, moveList, target);
 -    moveList = generate_moves<KNIGHT, Checks>(pos, moveList, Us, target);
 -    moveList = generate_moves<BISHOP, Checks>(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<Checks>(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<Us, Checks>(pos, moveList, pt, target & ~pos.pieces(~Us));
 +
 +    if (Type != QUIET_CHECKS && Type != EVASIONS && pos.count<KING>(Us))
      {
          Square ksq = pos.square<KING>(Us);
 -        Bitboard b = pos.attacks_from<KING>(ksq) & target;
 +        Bitboard b = pos.attacks_from<KING>(Us, ksq) & target;
          while (b)
 -            *moveList++ = make_move(ksq, pop_lsb(&b));
 +            moveList = make_move_and_gating<NORMAL>(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<CASTLING>(ksq, pos.castling_rook_square(OO));
 +                moveList = make_move_and_gating<CASTLING>(pos, moveList, Us, ksq, pos.castling_rook_square(OO));
  
              if (!pos.castling_impeded(OOO) && pos.can_castle(OOO))
 -                *moveList++ = make<CASTLING>(ksq, pos.castling_rook_square(OOO));
 +                moveList = make_move_and_gating<CASTLING>(pos, moveList, Us, ksq, pos.castling_rook_square(OOO));
          }
      }
  
 +    // Castling with non-king piece
-     if (!pos.count<KING>(Us) && Type != CAPTURES && pos.can_castle(CastlingRight(OO | OOO)))
++    if (!pos.count<KING>(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<CASTLING>(pos, moveList, Us, from, pos.castling_rook_square(OO));
 +
 +        if (!pos.castling_impeded(OOO) && pos.can_castle(OOO))
 +            moveList = make_move_and_gating<CASTLING>(pos, moveList, Us, from, pos.castling_rook_square(OOO));
 +    }
 +
      return moveList;
    }
  
diff --cc 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<ALL_PIECES>(Us) == pos.count<PAWN>(Us))
 +        score = score * 2;
 +
 +    const Square* pl_shogi = pos.squares<SHOGI_PAWN>(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<Us>(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<Us>(pos, relative_square(Us, SQ_G1));
++      shelters[1] = evaluate_shelter<Us>(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<Us>(pos, relative_square(Us, SQ_C1));
++      shelters[2] = evaluate_shelter<Us>(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)));
  
@@@ -471,18 -329,16 +471,17 @@@ Position& Position::set(const Variant* 
  
  void Position::set_castling_right(Color c, Square rfrom) {
  
 -  Square kfrom = square<KING>(c);
 +  Square kfrom = count<KING>(c) ? square<KING>(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<KING>(c)] & (c | s)) != (c | s))
+           if (   piece_on(castlingRookSquare[cr]) != make_piece(c, ROOK)
+               || castlingRightsMask[castlingRookSquare[cr]] != cr
+               || (castlingRightsMask[square<KING>(c)] & cr) != cr)
                assert(0 && "pos_is_ok: Castling");
        }
  
diff --cc 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
@@@ -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];
      // 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;
  
      }
  
      // 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<NT>(pos, ss, alpha, beta, depth - 7 * ONE_PLY, cutNode);
 +        search<NT>(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;
  
                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;
        }
  
        // 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<CAPTURES>(pos).size()))
        {
            Depth r = reduction(improving, depth, moveCount);
  
            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<CAPTURES>(pos).size()))
            {
                // Increase reduction if ttMove is a capture (~0 Elo)
                if (ttCapture)
                    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
Simple merge
diff --cc src/thread.cpp
Simple merge
diff --cc 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<MoveType T>
 +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<MoveType T>
 -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