Merge official-stockfish/master
authorFabian Fichter <ianfab@users.noreply.github.com>
Sun, 18 Jul 2021 13:26:37 +0000 (15:26 +0200)
committerFabian Fichter <ianfab@users.noreply.github.com>
Sun, 18 Jul 2021 13:26:37 +0000 (15:26 +0200)
No functional change.

1  2 
src/position.cpp

@@@ -924,119 -502,24 +924,123 @@@ bool Position::legal(Move m) const 
    Square to = to_sq(m);
  
    assert(color_of(moved_piece(m)) == us);
 -  assert(piece_on(square<KING>(us)) == make_piece(us, KING));
 +  assert(!count<KING>(us) || piece_on(square<KING>(us)) == make_piece(us, KING));
 +  assert(board_bb() & to);
 +
 +  // Illegal checks
 +  if ((!checking_permitted() || (sittuyin_promotion() && type_of(m) == PROMOTION) || (!drop_checks() && type_of(m) == DROP)) && gives_check(m))
 +      return false;
 +
 +  // Illegal quiet moves
 +  if (must_capture() && !capture(m) && has_capture())
 +      return false;
 +
 +  // Illegal non-drop moves
 +  if (must_drop() && type_of(m) != DROP && count_in_hand(us, var->mustDropType) > 0)
 +  {
 +      if (checkers())
 +      {
 +          for (const auto& mevasion : MoveList<EVASIONS>(*this))
 +              if (type_of(mevasion) == DROP && legal(mevasion))
 +                  return false;
 +      }
 +      else
 +      {
 +          for (const auto& mquiet : MoveList<QUIETS>(*this))
 +              if (type_of(mquiet) == DROP && legal(mquiet))
 +                  return false;
 +      }
 +  }
 +
 +  // Illegal drop move
 +  if (drop_opposite_colored_bishop() && type_of(m) == DROP)
 +  {
 +      if (type_of(moved_piece(m)) != BISHOP)
 +      {
 +          Bitboard remaining = drop_region(us, BISHOP) & ~pieces() & ~square_bb(to);
 +          // Are enough squares available to drop bishops on opposite colors?
 +          if (  (!( DarkSquares & pieces(us, BISHOP)) && ( DarkSquares & remaining))
 +              + (!(~DarkSquares & pieces(us, BISHOP)) && (~DarkSquares & remaining)) < count_in_hand(us, BISHOP))
 +              return false;
 +      }
 +      else
 +          // Drop resulting in same-colored bishops
 +          if ((DarkSquares & to ? DarkSquares : ~DarkSquares) & pieces(us, BISHOP))
 +              return false;
 +  }
 +
 +  // No legal moves from target square
 +  if (immobility_illegal() && (type_of(m) == DROP || type_of(m) == NORMAL) && !(moves_bb(us, type_of(moved_piece(m)), to, 0) & board_bb()))
 +      return false;
 +
 +  // Illegal king passing move
 +  if (pass_on_stalemate() && is_pass(m) && !checkers())
 +  {
 +      for (const auto& move : MoveList<NON_EVASIONS>(*this))
 +          if (!is_pass(move) && legal(move))
 +              return false;
 +  }
 +
 +  // Check for attacks to pseudo-royal pieces
 +  if (var->extinctionPseudoRoyal)
 +  {
 +      Square kto = to;
 +      Bitboard occupied = (type_of(m) != DROP ? pieces() ^ from : pieces()) | kto;
 +      if (type_of(m) == CASTLING)
 +      {
 +          // After castling, the rook and king final positions are the same in
 +          // Chess960 as they would be in standard chess.
 +          kto = make_square(to > from ? castling_kingside_file() : castling_queenside_file(), castling_rank(us));
 +          Direction step = kto > from ? EAST : WEST;
 +          Square rto = kto - step;
 +          // Pseudo-royal king
 +          if (st->pseudoRoyals & from)
 +              for (Square s = from; s != kto; s += step)
 +                  if (  !(blast_on_capture() && (attacks_bb<KING>(s) & st->pseudoRoyals & pieces(~sideToMove)))
 +                      && attackers_to(s, pieces() ^ from, ~us))
 +                      return false;
 +          occupied = (pieces() ^ from ^ to) | kto | rto;
 +      }
 +      if (type_of(m) == EN_PASSANT)
 +          occupied &= ~square_bb(kto - pawn_push(us));
 +      if (capture(m) && blast_on_capture())
 +          occupied &= ~((attacks_bb<KING>(kto) & (pieces() ^ pieces(PAWN))) | kto);
 +      Bitboard pseudoRoyals = st->pseudoRoyals & pieces(sideToMove);
 +      Bitboard pseudoRoyalsTheirs = st->pseudoRoyals & pieces(~sideToMove);
 +      if (is_ok(from) && (pseudoRoyals & from))
 +          pseudoRoyals ^= square_bb(from) ^ kto;
 +      if (type_of(m) == PROMOTION && extinction_piece_types().find(promotion_type(m)) != extinction_piece_types().end())
 +          pseudoRoyals |= kto;
 +      // Self-explosions are illegal
 +      if (pseudoRoyals & ~occupied)
 +          return false;
 +      // Check for legality unless we capture a pseudo-royal piece
 +      if (!(pseudoRoyalsTheirs & ~occupied))
 +          while (pseudoRoyals)
 +          {
 +              Square sr = pop_lsb(pseudoRoyals);
 +              // Touching pseudo-royal pieces are immune
 +              if (  !(blast_on_capture() && (pseudoRoyalsTheirs & attacks_bb<KING>(sr)))
 +                  && (attackers_to(sr, occupied, ~us) & (occupied & ~square_bb(kto))))
 +                  return false;
 +          }
 +  }
  
-   // st->previous->blockersForKing consider capsq as empty.
-   // If pinned, it has to move along the king ray.
-   if (type_of(m) == EN_PASSANT)
+   // En passant captures are a tricky special case. Because they are rather
+   // uncommon, we do it simply by testing whether the king is attacked after
+   // the move is made.
 -  if (type_of(m) == EN_PASSANT)
++  if (type_of(m) == EN_PASSANT && count<KING>(us))
    {
-       if (!count<KING>(us))
-           return true;
+       Square ksq = square<KING>(us);
        Square capsq = to - pawn_push(us);
        Bitboard occupied = (pieces() ^ from ^ capsq) | to;
  
-       return !(attackers_to(square<KING>(us), occupied, ~us) & occupied);
+       assert(to == ep_square());
+       assert(moved_piece(m) == make_piece(us, PAWN));
+       assert(piece_on(capsq) == make_piece(~us, PAWN));
+       assert(piece_on(to) == NO_PIECE);
 -      return   !(attacks_bb<  ROOK>(ksq, occupied) & pieces(~us, QUEEN, ROOK))
 -            && !(attacks_bb<BISHOP>(ksq, occupied) & pieces(~us, QUEEN, BISHOP));
++      return !(attackers_to(ksq, occupied, ~us) & occupied);
    }
  
    // Castling moves generation does not check if the castling path is clear of
@@@ -1272,18 -651,12 +1276,18 @@@ bool Position::gives_check(Move m) cons
        return false;
  
    case PROMOTION:
 -      return attacks_bb(promotion_type(m), to, pieces() ^ from) & square<KING>(~sideToMove);
 +      return attacks_bb(sideToMove, promotion_type(m), to, pieces() ^ from) & square<KING>(~sideToMove);
 +
 +  case PIECE_PROMOTION:
 +      return attacks_bb(sideToMove, promoted_piece_type(type_of(moved_piece(m))), to, pieces() ^ from) & square<KING>(~sideToMove);
 +
 +  case PIECE_DEMOTION:
 +      return attacks_bb(sideToMove, type_of(unpromoted_piece_on(from)), to, pieces() ^ from) & square<KING>(~sideToMove);
  
-   // The double-pushed pawn blocked a check? En Passant will remove the blocker.
-   // The only discovery check that wasn't handle is through capsq and fromsq
-   // So the King must be in the same rank as fromsq to consider this possibility.
-   // st->previous->blockersForKing consider capsq as empty.
+   // En passant capture with check? We have already handled the case
+   // of direct checks and ordinary discovered check, so the only case we
+   // need to handle is the unusual case of a discovered check through
+   // the captured pawn.
    case EN_PASSANT:
    {
        Square capsq = make_square(file_of(to), rank_of(from));