Merge official-stockfish/master
authorFabian Fichter <ianfab@users.noreply.github.com>
Sat, 9 Feb 2019 16:58:41 +0000 (17:58 +0100)
committerFabian Fichter <ianfab@users.noreply.github.com>
Sat, 9 Feb 2019 16:58:41 +0000 (17:58 +0100)
1  2 
src/position.cpp
src/position.h

@@@ -309,131 -257,60 +305,131 @@@ Position& Position::set(const Variant* 
            put_piece(Piece(idx), sq);
            ++sq;
        }
 +      // Promoted shogi pieces
 +      else if (token == '+')
 +      {
 +          ss >> token;
 +          idx = piece_to_char().find(token);
 +          unpromotedBoard[sq] = Piece(idx);
 +          promotedPieces |= SquareBB[sq];
 +          put_piece(make_piece(color_of(Piece(idx)), promoted_piece_type(type_of(Piece(idx)))), sq);
 +          ++sq;
 +      }
 +      // Set flag for promoted pieces
 +      else if (captures_to_hand() && !drop_loop() && token == '~')
 +          promotedPieces |= SquareBB[sq - 1];
 +      // Stop before pieces in hand
 +      else if (token == '[')
 +          break;
    }
 +  // Pieces in hand
 +  if (!isspace(token))
 +      while ((ss >> token) && !isspace(token))
 +      {
 +          if (token == ']')
 +              continue;
 +          else if ((idx = piece_to_char().find(token)) != string::npos)
-               add_to_hand(color_of(Piece(idx)), type_of(Piece(idx)));
++              add_to_hand(Piece(idx));
 +      }
  
    // 2. Active color
    ss >> token;
    sideToMove = (token == 'w' ? WHITE : BLACK);
 +  // Invert side to move for SFEN
 +  if (sfen)
 +      sideToMove = ~sideToMove;
    ss >> token;
  
 -  // 3. Castling availability. Compatible with 3 standards: Normal FEN standard,
 -  // Shredder-FEN that uses the letters of the columns on which the rooks began
 -  // the game instead of KQkq and also X-FEN standard that, in case of Chess960,
 -  // if an inner rook is associated with the castling right, the castling tag is
 -  // replaced by the file letter of the involved rook, as for the Shredder-FEN.
 -  while ((ss >> token) && !isspace(token))
 +  // 3-4. Skip parsing castling and en passant flags if not present
 +  st->epSquare = SQ_NONE;
 +  if (!isdigit(ss.peek()) && !sfen)
    {
 -      Square rsq;
 -      Color c = islower(token) ? BLACK : WHITE;
 -      Piece rook = make_piece(c, ROOK);
 +      // 3. Castling availability. Compatible with 3 standards: Normal FEN standard,
 +      // Shredder-FEN that uses the letters of the columns on which the rooks began
 +      // the game instead of KQkq and also X-FEN standard that, in case of Chess960,
 +      // if an inner rook is associated with the castling right, the castling tag is
 +      // replaced by the file letter of the involved rook, as for the Shredder-FEN.
 +      while ((ss >> token) && !isspace(token))
 +      {
 +          Square rsq;
 +          Color c = islower(token) ? BLACK : WHITE;
 +          Piece rook = make_piece(c, ROOK);
  
 -      token = char(toupper(token));
 +          token = char(toupper(token));
  
 -      if (token == 'K')
 -          for (rsq = relative_square(c, SQ_H1); piece_on(rsq) != rook; --rsq) {}
 +          if (token == 'K')
 +              for (rsq = make_square(FILE_MAX, relative_rank(c, RANK_1, max_rank())); piece_on(rsq) != rook; --rsq) {}
  
 -      else if (token == 'Q')
 -          for (rsq = relative_square(c, SQ_A1); piece_on(rsq) != rook; ++rsq) {}
 +          else if (token == 'Q')
 +              for (rsq = make_square(FILE_A, relative_rank(c, RANK_1, max_rank())); piece_on(rsq) != rook; ++rsq) {}
  
 -      else if (token >= 'A' && token <= 'H')
 -          rsq = make_square(File(token - 'A'), relative_rank(c, RANK_1));
 +          else if (token >= 'A' && token <= 'A' + max_file())
 +              rsq = make_square(File(token - 'A'), relative_rank(c, RANK_1, max_rank()));
  
 -      else
 -          continue;
 +          else
 +              continue;
 +
 +          set_castling_right(c, rsq);
 +      }
 +
 +      // counting limit
 +      if (counting_rule() && isdigit(ss.peek()))
 +          ss >> st->countingLimit;
  
 -      set_castling_right(c, rsq);
 +      // 4. En passant square. Ignore if no pawn capture is possible
 +      else if (   ((ss >> col) && (col >= 'a' && col <= 'a' + max_file()))
 +               && ((ss >> row) && (row >= '1' && row <= '1' + max_rank())))
 +      {
 +          st->epSquare = make_square(File(col - 'a'), Rank(row - '1'));
 +
 +          if (   !(attackers_to(st->epSquare) & pieces(sideToMove, PAWN))
 +              || !(pieces(~sideToMove, PAWN) & (st->epSquare + pawn_push(~sideToMove))))
 +              st->epSquare = SQ_NONE;
 +      }
    }
  
 -  // 4. En passant square. Ignore if no pawn capture is possible
 -  if (   ((ss >> col) && (col >= 'a' && col <= 'h'))
 -      && ((ss >> row) && (row == '3' || row == '6')))
 -  {
 -      st->epSquare = make_square(File(col - 'a'), Rank(row - '1'));
 +  // Check counter for nCheck
 +  ss >> std::skipws >> token >> std::noskipws;
  
 -      if (   !(attackers_to(st->epSquare) & pieces(sideToMove, PAWN))
 -          || !(pieces(~sideToMove, PAWN) & (st->epSquare + pawn_push(~sideToMove))))
 -          st->epSquare = SQ_NONE;
 +  if (max_check_count() && ss.peek() == '+')
 +  {
 +      st->checksGiven[WHITE] = CheckCount(std::max(max_check_count() - std::max(token - '0', 0), 0));
 +      ss >> token >> token;
 +      st->checksGiven[BLACK] = CheckCount(std::max(max_check_count() - std::max(token - '0', 0), 0));
    }
    else
 -      st->epSquare = SQ_NONE;
 +      ss.putback(token);
  
    // 5-6. Halfmove clock and fullmove number
 -  ss >> std::skipws >> st->rule50 >> gamePly;
 +  if (sfen)
 +  {
 +      // Pieces in hand for SFEN
 +      while ((ss >> token) && !isspace(token))
 +      {
 +          if (token == '-')
 +              continue;
 +          else if ((idx = piece_to_char().find(token)) != string::npos)
-               add_to_hand(color_of(Piece(idx)), type_of(Piece(idx)));
++              add_to_hand(Piece(idx));
 +      }
 +      // Move count is in ply for SFEN
 +      ss >> std::skipws >> gamePly;
 +      gamePly = std::max(gamePly - 1, 0);
 +  }
 +  else
 +  {
 +      ss >> std::skipws >> st->rule50 >> gamePly;
 +
 +      // Convert from fullmove starting from 1 to gamePly starting from 0,
 +      // handle also common incorrect FEN with fullmove = 0.
 +      gamePly = std::max(2 * (gamePly - 1), 0) + (sideToMove == BLACK);
 +  }
  
 -  // Convert from fullmove starting from 1 to gamePly starting from 0,
 -  // handle also common incorrect FEN with fullmove = 0.
 -  gamePly = std::max(2 * (gamePly - 1), 0) + (sideToMove == BLACK);
 +  // counting rules
 +  if (st->countingLimit && st->rule50)
 +  {
 +      st->countingPly = st->rule50;
 +      st->rule50 = 0;
 +  }
  
    chess960 = isChess960;
    thisThread = th;
@@@ -499,8 -377,7 +495,7 @@@ void Position::set_state(StateInfo* si
    si->key = si->materialKey = 0;
    si->pawnKey = Zobrist::noPawns;
    si->nonPawnMaterial[WHITE] = si->nonPawnMaterial[BLACK] = VALUE_ZERO;
-   si->psq = SCORE_ZERO;
 -  si->checkersBB = attackers_to(square<KING>(sideToMove)) & pieces(~sideToMove);
 +  si->checkersBB = count<KING>(sideToMove) ? attackers_to(square<KING>(sideToMove), ~sideToMove) : 0;
  
    set_check_info(si);
  
@@@ -1064,19 -778,6 +1050,18 @@@ void Position::do_move(Move m, StateInf
  
        // Update board and piece lists
        remove_piece(captured, capsq);
 +      if (captures_to_hand())
 +      {
 +          st->capturedpromoted = is_promoted(to);
 +          Piece pieceToHand =  !is_promoted(to)   ? ~captured
 +                             : unpromotedCaptured ? ~unpromotedCaptured
 +                                                  : make_piece(~color_of(captured), PAWN);
-           add_to_hand(color_of(pieceToHand), type_of(pieceToHand));
-           st->psq += PSQT::psq[pieceToHand][SQ_NONE];
++          add_to_hand(pieceToHand);
 +          k ^=  Zobrist::inHand[pieceToHand][pieceCountInHand[color_of(pieceToHand)][type_of(pieceToHand)] - 1]
 +              ^ Zobrist::inHand[pieceToHand][pieceCountInHand[color_of(pieceToHand)][type_of(pieceToHand)]];
 +          promotedPieces -= to;
 +      }
 +      unpromotedBoard[to] = NO_PIECE;
  
        // Update material hash key and prefetch access to materialTable
        k ^= Zobrist::psq[captured][capsq];
        // Reset rule 50 draw counter
        st->rule50 = 0;
    }
 +  else if (type_of(m) == PIECE_PROMOTION)
 +  {
 +      Piece promotion = make_piece(us, promoted_piece_type(type_of(pc)));
 +
 +      remove_piece(pc, to);
 +      put_piece(promotion, to);
 +      promotedPieces |= to;
 +      unpromotedBoard[to] = pc;
 +
 +      // Update hash keys
 +      k ^= Zobrist::psq[pc][to] ^ Zobrist::psq[promotion][to];
 +      st->materialKey ^=  Zobrist::psq[promotion][pieceCount[promotion]-1]
 +                        ^ Zobrist::psq[pc][pieceCount[pc]];
 +
-       // Update incremental score
-       st->psq += PSQT::psq[promotion][to] - PSQT::psq[pc][to];
 +      // Update material
 +      st->nonPawnMaterial[us] += PieceValue[MG][promotion] - PieceValue[MG][pc];
 +  }
 +  else if (type_of(m) == PIECE_DEMOTION)
 +  {
 +      Piece demotion = unpromoted_piece_on(from);
 +
 +      remove_piece(pc, to);
 +      put_piece(demotion, to);
 +      promotedPieces ^= from;
 +      unpromotedBoard[from] = NO_PIECE;
 +
 +      // Update hash keys
 +      k ^= Zobrist::psq[pc][to] ^ Zobrist::psq[demotion][to];
 +      st->materialKey ^=  Zobrist::psq[demotion][pieceCount[demotion]-1]
 +                        ^ Zobrist::psq[pc][pieceCount[pc]];
 +
-       // Update incremental score
-       st->psq += PSQT::psq[demotion][to] - PSQT::psq[pc][to];
 +      // Update material
 +      st->nonPawnMaterial[us] += PieceValue[MG][demotion] - PieceValue[MG][pc];
 +  }
  
-   // Update incremental scores
-   st->psq += PSQT::psq[pc][to] - PSQT::psq[pc][from];
    // Set capture piece
    st->capturedPiece = captured;
 +  st->unpromotedCapturedPiece = captured ? unpromotedCaptured : NO_PIECE;
 +  if (captures_to_hand() && !captured)
 +      st->capturedpromoted = false;
  
    // Update the key with the final value
    st->key = k;
@@@ -1365,17 -920,6 +1335,16 @@@ void Position::undo_move(Move m) 
            }
  
            put_piece(st->capturedPiece, capsq); // Restore the captured piece
 +          if (captures_to_hand())
 +          {
-               remove_from_hand(~color_of(st->capturedPiece),
-                                !drop_loop() && st->capturedpromoted ? (st->unpromotedCapturedPiece ? type_of(st->unpromotedCapturedPiece)
-                                                                                                    : PAWN)
-                                                                     : type_of(st->capturedPiece));
++              remove_from_hand(!drop_loop() && st->capturedpromoted ? (st->unpromotedCapturedPiece ? ~st->unpromotedCapturedPiece
++                                                                                                   : make_piece(~color_of(st->capturedPiece), PAWN))
++                                                                    : ~st->capturedPiece);
 +              if (!drop_loop() && st->capturedpromoted)
 +                  promotedPieces |= to;
 +          }
 +          if (st->unpromotedCapturedPiece)
 +              unpromotedBoard[to] = st->unpromotedCapturedPiece;
        }
    }
  
diff --cc src/position.h
@@@ -45,10 -43,6 +45,9 @@@ struct StateInfo 
    int    castlingRights;
    int    rule50;
    int    pliesFromNull;
 +  int    countingPly;
 +  int    countingLimit;
 +  CheckCount checksGiven[COLOR_NB];
-   Score  psq;
    Square epSquare;
  
    // Not copied when making a move (will be recomputed anyhow)
@@@ -262,327 -187,18 +261,332 @@@ private
    Bitboard castlingPath[CASTLING_RIGHT_NB];
    int gamePly;
    Color sideToMove;
+   Score psq;
    Thread* thisThread;
    StateInfo* st;
 +
 +  // variant-specific
 +  const Variant* var;
    bool chess960;
 +  int pieceCountInHand[COLOR_NB][PIECE_TYPE_NB];
 +  Bitboard promotedPieces;
-   void add_to_hand(Color c, PieceType pt);
-   void remove_from_hand(Color c, PieceType pt);
++  void add_to_hand(Piece pc);
++  void remove_from_hand(Piece pc);
 +  void drop_piece(Piece pc_hand, Piece pc_drop, Square s);
 +  void undrop_piece(Piece pc_hand, Piece pc_drop, Square s);
  };
  
+ namespace PSQT {
 -  extern Score psq[PIECE_NB][SQUARE_NB];
++  extern Score psq[PIECE_NB][SQUARE_NB + 1];
+ }
  extern std::ostream& operator<<(std::ostream& os, const Position& pos);
  
 +inline const Variant* Position::variant() const {
 +  assert(var != nullptr);
 +  return var;
 +}
 +
 +inline Rank Position::max_rank() const {
 +  assert(var != nullptr);
 +  return var->maxRank;
 +}
 +
 +inline File Position::max_file() const {
 +  assert(var != nullptr);
 +  return var->maxFile;
 +}
 +
 +inline Bitboard Position::board_bb() const {
 +  assert(var != nullptr);
 +  return board_size_bb(var->maxFile, var->maxRank);
 +}
 +
 +inline const std::set<PieceType>& Position::piece_types() const {
 +  assert(var != nullptr);
 +  return var->pieceTypes;
 +}
 +
 +inline const std::string Position::piece_to_char() const {
 +  assert(var != nullptr);
 +  return var->pieceToChar;
 +}
 +
 +inline Rank Position::promotion_rank() const {
 +  assert(var != nullptr);
 +  return var->promotionRank;
 +}
 +
 +inline const std::set<PieceType, std::greater<PieceType> >& Position::promotion_piece_types() const {
 +  assert(var != nullptr);
 +  return var->promotionPieceTypes;
 +}
 +
 +inline bool Position::sittuyin_promotion() const {
 +  assert(var != nullptr);
 +  return var->sittuyinPromotion;
 +}
 +
 +inline PieceType Position::promoted_piece_type(PieceType pt) const {
 +  assert(var != nullptr);
 +  return var->promotedPieceType[pt];
 +}
 +
 +inline bool Position::mandatory_piece_promotion() const {
 +  assert(var != nullptr);
 +  return var->mandatoryPiecePromotion;
 +}
 +
 +inline bool Position::piece_demotion() const {
 +  assert(var != nullptr);
 +  return var->pieceDemotion;
 +}
 +
 +inline bool Position::endgame_eval() const {
 +  assert(var != nullptr);
 +  return var->endgameEval;
 +}
 +
 +inline bool Position::double_step_enabled() const {
 +  assert(var != nullptr);
 +  return var->doubleStep;
 +}
 +
 +inline bool Position::first_rank_double_steps() const {
 +  assert(var != nullptr);
 +  return var->firstRankDoubleSteps;
 +}
 +
 +inline bool Position::castling_enabled() const {
 +  assert(var != nullptr);
 +  return var->castling;
 +}
 +
 +inline bool Position::castling_dropped_piece() const {
 +  assert(var != nullptr);
 +  return var->castlingDroppedPiece;
 +}
 +
 +inline File Position::castling_kingside_file() const {
 +  assert(var != nullptr);
 +  return var->castlingKingsideFile;
 +}
 +
 +inline File Position::castling_queenside_file() const {
 +  assert(var != nullptr);
 +  return var->castlingQueensideFile;
 +}
 +
 +inline bool Position::checking_permitted() const {
 +  assert(var != nullptr);
 +  return var->checking;
 +}
 +
 +inline bool Position::must_capture() const {
 +  assert(var != nullptr);
 +  return var->mustCapture;
 +}
 +
 +inline bool Position::must_drop() const {
 +  assert(var != nullptr);
 +  return var->mustDrop;
 +}
 +
 +inline bool Position::piece_drops() const {
 +  assert(var != nullptr);
 +  return var->pieceDrops;
 +}
 +
 +inline bool Position::drop_loop() const {
 +  assert(var != nullptr);
 +  return var->dropLoop;
 +}
 +
 +inline bool Position::captures_to_hand() const {
 +  assert(var != nullptr);
 +  return var->capturesToHand;
 +}
 +
 +inline bool Position::first_rank_drops() const {
 +  assert(var != nullptr);
 +  return var->firstRankDrops;
 +}
 +
 +inline bool Position::drop_on_top() const {
 +  assert(var != nullptr);
 +  return var->dropOnTop;
 +}
 +
 +inline Bitboard Position::drop_region(Color c) const {
 +  assert(var != nullptr);
 +  return c == WHITE ? var->whiteDropRegion : var->blackDropRegion;
 +}
 +
 +inline Bitboard Position::drop_region(Color c, PieceType pt) const {
 +  Bitboard b = drop_region(c) & board_bb();
 +
 +  // Connect4-style drops
 +  if (drop_on_top())
 +      b &= shift<NORTH>(pieces()) | Rank1BB;
 +  // Pawns on back ranks
 +  if (pt == PAWN)
 +  {
 +      b &= ~promotion_zone_bb(c, promotion_rank(), max_rank());
 +      if (!first_rank_drops())
 +          b &= ~rank_bb(relative_rank(c, RANK_1, max_rank()));
 +  }
 +  // Doubled shogi pawns
 +  if (pt == SHOGI_PAWN && !shogi_doubled_pawn())
 +      for (File f = FILE_A; f <= max_file(); ++f)
 +          if (file_bb(f) & pieces(c, pt))
 +              b &= ~file_bb(f);
 +  // Sittuyin rook drops
 +  if (pt == ROOK && sittuyin_rook_drop())
 +      b &= rank_bb(relative_rank(c, RANK_1, max_rank()));
 +
 +  return b;
 +}
 +
 +inline bool Position::sittuyin_rook_drop() const {
 +  assert(var != nullptr);
 +  return var->sittuyinRookDrop;
 +}
 +
 +inline bool Position::drop_opposite_colored_bishop() const {
 +  assert(var != nullptr);
 +  return var->dropOppositeColoredBishop;
 +}
 +
 +inline bool Position::drop_promoted() const {
 +  assert(var != nullptr);
 +  return var->dropPromoted;
 +}
 +
 +inline bool Position::shogi_doubled_pawn() const {
 +  assert(var != nullptr);
 +  return var->shogiDoubledPawn;
 +}
 +
 +inline bool Position::immobility_illegal() const {
 +  assert(var != nullptr);
 +  return var->immobilityIllegal;
 +}
 +
 +inline int Position::n_move_rule() const {
 +  assert(var != nullptr);
 +  return var->nMoveRule;
 +}
 +
 +inline int Position::n_fold_rule() const {
 +  assert(var != nullptr);
 +  return var->nFoldRule;
 +}
 +
 +inline Value Position::stalemate_value(int ply) const {
 +  assert(var != nullptr);
 +  return convert_mate_value(var->stalemateValue, ply);
 +}
 +
 +inline Value Position::checkmate_value(int ply) const {
 +  assert(var != nullptr);
 +  // Check for illegal mate by shogi pawn drop
 +  if (    var->shogiPawnDropMateIllegal
 +      && !(checkers() & ~pieces(SHOGI_PAWN))
 +      && !st->capturedPiece
 +      &&  st->pliesFromNull > 0
 +      && (st->materialKey != st->previous->materialKey))
 +  {
 +      return mate_in(ply);
 +  }
 +  // Check for shatar mate rule
 +  if (var->shatarMateRule)
 +  {
 +      // Mate by knight is illegal
 +      if (!(checkers() & ~pieces(KNIGHT)))
 +          return mate_in(ply);
 +
 +      StateInfo* stp = st;
 +      while (stp->checkersBB)
 +      {
 +          // Return mate score if there is at least one shak in series of checks
 +          if (stp->shak)
 +              return convert_mate_value(var->checkmateValue, ply);
 +
 +          if (stp->pliesFromNull < 2)
 +              break;
 +
 +          stp = stp->previous->previous;
 +      }
 +      // Niol
 +      return VALUE_DRAW;
 +  }
 +  // Return mate value
 +  return convert_mate_value(var->checkmateValue, ply);
 +}
 +
 +inline Value Position::bare_king_value(int ply) const {
 +  assert(var != nullptr);
 +  return convert_mate_value(var->bareKingValue, ply);
 +}
 +
 +inline Value Position::extinction_value(int ply) const {
 +  assert(var != nullptr);
 +  return convert_mate_value(var->extinctionValue, ply);
 +}
 +
 +inline bool Position::bare_king_move() const {
 +  assert(var != nullptr);
 +  return var->bareKingMove;
 +}
 +
 +inline const std::set<PieceType>& Position::extinction_piece_types() const {
 +  assert(var != nullptr);
 +  return var->extinctionPieceTypes;
 +}
 +
 +inline PieceType Position::capture_the_flag_piece() const {
 +  assert(var != nullptr);
 +  return var->flagPiece;
 +}
 +
 +inline Bitboard Position::capture_the_flag(Color c) const {
 +  assert(var != nullptr);
 +  return c == WHITE ? var->whiteFlag : var->blackFlag;
 +}
 +
 +inline bool Position::flag_move() const {
 +  assert(var != nullptr);
 +  return var->flagMove;
 +}
 +
 +inline CheckCount Position::max_check_count() const {
 +  assert(var != nullptr);
 +  return var->maxCheckCount;
 +}
 +
 +inline int Position::connect_n() const {
 +  assert(var != nullptr);
 +  return var->connectN;
 +}
 +
 +inline CheckCount Position::checks_given(Color c) const {
 +  return st->checksGiven[c];
 +}
 +
 +inline CountingRule Position::counting_rule() const {
 +  assert(var != nullptr);
 +  return var->countingRule;
 +}
 +
 +inline bool Position::is_immediate_game_end() const {
 +  Value result;
 +  return is_immediate_game_end(result);
 +}
 +
 +inline bool Position::is_game_end(Value& result, int ply) const {
 +  return is_immediate_game_end(result, ply) || is_optional_game_end(result, ply);
 +}
 +
  inline Color Position::side_to_move() const {
    return sideToMove;
  }
@@@ -827,31 -428,4 +834,33 @@@ inline void Position::do_move(Move m, S
    do_move(m, newSt, gives_check(m));
  }
  
 +inline int Position::count_in_hand(Color c, PieceType pt) const {
 +  return pieceCountInHand[c][pt];
 +}
 +
- inline void Position::add_to_hand(Color c, PieceType pt) {
-   pieceCountInHand[c][pt]++;
-   pieceCountInHand[c][ALL_PIECES]++;
++inline void Position::add_to_hand(Piece pc) {
++  pieceCountInHand[color_of(pc)][type_of(pc)]++;
++  pieceCountInHand[color_of(pc)][ALL_PIECES]++;
++  psq += PSQT::psq[pc][SQ_NONE];
 +}
 +
- inline void Position::remove_from_hand(Color c, PieceType pt) {
-   pieceCountInHand[c][pt]--;
-   pieceCountInHand[c][ALL_PIECES]--;
++inline void Position::remove_from_hand(Piece pc) {
++  pieceCountInHand[color_of(pc)][type_of(pc)]--;
++  pieceCountInHand[color_of(pc)][ALL_PIECES]--;
++  psq -= PSQT::psq[pc][SQ_NONE];
 +}
 +
 +inline void Position::drop_piece(Piece pc_hand, Piece pc_drop, Square s) {
 +  assert(pieceCountInHand[color_of(pc_hand)][type_of(pc_hand)]);
 +  put_piece(pc_drop, s);
-   remove_from_hand(color_of(pc_hand), type_of(pc_hand));
++  remove_from_hand(pc_hand);
 +}
 +
 +inline void Position::undrop_piece(Piece pc_hand, Piece pc_drop, Square s) {
 +  remove_piece(pc_drop, s);
 +  board[s] = NO_PIECE;
-   add_to_hand(color_of(pc_hand), type_of(pc_hand));
++  add_to_hand(pc_hand);
 +  assert(pieceCountInHand[color_of(pc_hand)][type_of(pc_hand)]);
 +}
 +
  #endif // #ifndef POSITION_H_INCLUDED