Merge official-stockfish/master
authorFabian Fichter <ianfab@users.noreply.github.com>
Tue, 25 Aug 2020 20:53:34 +0000 (22:53 +0200)
committerFabian Fichter <ianfab@users.noreply.github.com>
Tue, 25 Aug 2020 20:53:34 +0000 (22:53 +0200)
1  2 
src/bitbase.cpp
src/bitboard.h
src/endgame.cpp
src/evaluate.cpp
src/movegen.cpp
src/pawns.cpp
src/position.cpp
src/position.h

diff --cc src/bitbase.cpp
Simple merge
diff --cc src/bitboard.h
@@@ -249,6 -176,12 +249,12 @@@ constexpr Bitboard pawn_attacks_bb(Bitb
                      : shift<SOUTH_WEST>(b) | shift<SOUTH_EAST>(b);
  }
  
+ inline Bitboard pawn_attacks_bb(Color c, Square s) {
+   assert(is_ok(s));
 -  return PawnAttacks[c][s];
++  return PseudoAttacks[c][PAWN][s];
+ }
  
  /// pawn_double_attacks_bb() returns the squares doubly attacked by pawns of the
  /// given color from the squares in the given bitboard.
@@@ -360,76 -269,49 +366,96 @@@ inline int edge_distance(Rank r, Rank m
  inline Bitboard safe_destination(Square s, int step)
  {
      Square to = Square(s + step);
 -    return is_ok(to) && distance(s, to) <= 2 ? square_bb(to) : Bitboard(0);
 +    return is_ok(to) && distance(s, to) <= 3 ? square_bb(to) : Bitboard(0);
 +}
 +
 +template<RiderType R>
 +inline Bitboard rider_attacks_bb(Square s, Bitboard occupied) {
 +
 +  assert(R == RIDER_BISHOP || R == RIDER_ROOK_H || R == RIDER_ROOK_V || R == RIDER_CANNON_H || R == RIDER_CANNON_V
 +         || R == RIDER_HORSE || R == RIDER_ELEPHANT || R == RIDER_JANGGI_ELEPHANT);
 +  const Magic& m =  R == RIDER_ROOK_H ? RookMagicsH[s]
 +                  : R == RIDER_ROOK_V ? RookMagicsV[s]
 +                  : R == RIDER_CANNON_H ? CannonMagicsH[s]
 +                  : R == RIDER_CANNON_V ? CannonMagicsV[s]
 +                  : R == RIDER_HORSE ? HorseMagics[s]
 +                  : R == RIDER_ELEPHANT ? ElephantMagics[s]
 +                  : R == RIDER_JANGGI_ELEPHANT ? JanggiElephantMagics[s]
 +                  : BishopMagics[s];
 +  return m.attacks[m.index(occupied)];
  }
  
- /// attacks_bb() returns a bitboard representing all the squares attacked by a
- /// piece of type Pt (bishop or rook) placed on 's'.
+ /// attacks_bb(Square) returns the pseudo attacks of the give piece type
+ /// assuming an empty board.
+ template<PieceType Pt>
+ inline Bitboard attacks_bb(Square s) {
+   assert((Pt != PAWN) && (is_ok(s)));
 -  return PseudoAttacks[Pt][s];
++  return PseudoAttacks[WHITE][Pt][s];
+ }
+ /// attacks_bb(Square, Bitboard) returns the attacks by the given piece
+ /// assuming the board is occupied according to the passed Bitboard.
+ /// Sliding piece attacks do not continue passed an occupied square.
  
  template<PieceType Pt>
  inline Bitboard attacks_bb(Square s, Bitboard occupied) {
  
-   assert(Pt == BISHOP || Pt == ROOK);
-   return Pt == BISHOP ? rider_attacks_bb<RIDER_BISHOP>(s, occupied)
-                       : rider_attacks_bb<RIDER_ROOK_H>(s, occupied) | rider_attacks_bb<RIDER_ROOK_V>(s, occupied);
+   assert((Pt != PAWN) && (is_ok(s)));
+   switch (Pt)
+   {
 -  case BISHOP: return BishopMagics[s].attacks[BishopMagics[s].index(occupied)];
 -  case ROOK  : return   RookMagics[s].attacks[  RookMagics[s].index(occupied)];
++  case BISHOP: return rider_attacks_bb<RIDER_BISHOP>(s, occupied);
++  case ROOK  : return rider_attacks_bb<RIDER_ROOK_H>(s, occupied) | rider_attacks_bb<RIDER_ROOK_V>(s, occupied);
+   case QUEEN : return attacks_bb<BISHOP>(s, occupied) | attacks_bb<ROOK>(s, occupied);
 -  default    : return PseudoAttacks[Pt][s];
++  default    : return PseudoAttacks[WHITE][Pt][s];
+   }
  }
  
 -inline Bitboard attacks_bb(PieceType pt, Square s, Bitboard occupied) {
 -  assert((pt != PAWN) && (is_ok(s)));
 -
 -  switch (pt)
 -  {
 -  case BISHOP: return attacks_bb<BISHOP>(s, occupied);
 -  case ROOK  : return attacks_bb<  ROOK>(s, occupied);
 -  case QUEEN : return attacks_bb<BISHOP>(s, occupied) | attacks_bb<ROOK>(s, occupied);
 -  default    : return PseudoAttacks[pt][s];
 -  }
 +inline Bitboard attacks_bb(Color c, PieceType pt, Square s, Bitboard occupied) {
 +  Bitboard b = LeaperAttacks[c][pt][s];
 +  if (AttackRiderTypes[pt] & RIDER_BISHOP)
 +      b |= rider_attacks_bb<RIDER_BISHOP>(s, occupied);
 +  if (AttackRiderTypes[pt] & RIDER_ROOK_H)
 +      b |= rider_attacks_bb<RIDER_ROOK_H>(s, occupied);
 +  if (AttackRiderTypes[pt] & RIDER_ROOK_V)
 +      b |= rider_attacks_bb<RIDER_ROOK_V>(s, occupied);
 +  if (AttackRiderTypes[pt] & RIDER_CANNON_H)
 +      b |= rider_attacks_bb<RIDER_CANNON_H>(s, occupied);
 +  if (AttackRiderTypes[pt] & RIDER_CANNON_V)
 +      b |= rider_attacks_bb<RIDER_CANNON_V>(s, occupied);
 +  if (AttackRiderTypes[pt] & RIDER_HORSE)
 +      b |= rider_attacks_bb<RIDER_HORSE>(s, occupied);
 +  if (AttackRiderTypes[pt] & RIDER_ELEPHANT)
 +      b |= rider_attacks_bb<RIDER_ELEPHANT>(s, occupied);
 +  if (AttackRiderTypes[pt] & RIDER_JANGGI_ELEPHANT)
 +      b |= rider_attacks_bb<RIDER_JANGGI_ELEPHANT>(s, occupied);
 +  return b & PseudoAttacks[c][pt][s];
 +}
 +
++
 +inline Bitboard moves_bb(Color c, PieceType pt, Square s, Bitboard occupied) {
 +  Bitboard b = LeaperMoves[c][pt][s];
 +  if (MoveRiderTypes[pt] & RIDER_BISHOP)
 +      b |= rider_attacks_bb<RIDER_BISHOP>(s, occupied);
 +  if (MoveRiderTypes[pt] & RIDER_ROOK_H)
 +      b |= rider_attacks_bb<RIDER_ROOK_H>(s, occupied);
 +  if (MoveRiderTypes[pt] & RIDER_ROOK_V)
 +      b |= rider_attacks_bb<RIDER_ROOK_V>(s, occupied);
 +  if (MoveRiderTypes[pt] & RIDER_CANNON_H)
 +      b |= rider_attacks_bb<RIDER_CANNON_H>(s, occupied);
 +  if (MoveRiderTypes[pt] & RIDER_CANNON_V)
 +      b |= rider_attacks_bb<RIDER_CANNON_V>(s, occupied);
 +  if (MoveRiderTypes[pt] & RIDER_HORSE)
 +      b |= rider_attacks_bb<RIDER_HORSE>(s, occupied);
 +  if (MoveRiderTypes[pt] & RIDER_ELEPHANT)
 +      b |= rider_attacks_bb<RIDER_ELEPHANT>(s, occupied);
 +  if (MoveRiderTypes[pt] & RIDER_JANGGI_ELEPHANT)
 +      b |= rider_attacks_bb<RIDER_JANGGI_ELEPHANT>(s, occupied);
 +  return b & PseudoMoves[c][pt][s];
  }
  
  
diff --cc src/endgame.cpp
Simple merge
@@@ -245,33 -232,18 +245,33 @@@ namespace 
  
      // Squares occupied by those pawns, by our king or queen, by blockers to attacks on our king
      // or controlled by enemy pawns are excluded from the mobility area.
 -    mobilityArea[Us] = ~(b | pos.pieces(Us, KING, QUEEN) | pos.blockers_for_king(Us) | pe->pawn_attacks(Them));
 +    if (pos.must_capture())
 +        mobilityArea[Us] = AllSquares;
 +    else
 +        mobilityArea[Us] = ~(b | pos.pieces(Us, KING, QUEEN) | pos.blockers_for_king(Us) | pe->pawn_attacks(Them)
 +                               | shift<Down>(pos.pieces(Them, SHOGI_PAWN, SOLDIER))
 +                               | shift<EAST>(pos.promoted_soldiers(Them))
 +                               | shift<WEST>(pos.promoted_soldiers(Them)));
  
      // Initialize attackedBy[] for king and pawns
-     attackedBy[Us][KING] = pos.count<KING>(Us) ? pos.attacks_from<KING>(ksq, Us) : Bitboard(0);
 -    attackedBy[Us][KING] = attacks_bb<KING>(ksq);
++    attackedBy[Us][KING] = pos.count<KING>(Us) ? pos.attacks_from(Us, KING, ksq) : 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<Up>(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
 -    Square s = make_square(Utility::clamp(file_of(ksq), FILE_B, FILE_G),
 -                           Utility::clamp(rank_of(ksq), RANK_2, RANK_7));
 -    kingRing[Us] = attacks_bb<KING>(s) | s;
 +    if (!pos.count<KING>(Us))
 +        kingRing[Us] = Bitboard(0);
 +    else
 +    {
 +        Square s = make_square(Utility::clamp(file_of(ksq), FILE_B, File(pos.max_file() - 1)),
 +                               Utility::clamp(rank_of(ksq), RANK_2, Rank(pos.max_rank() - 1)));
-         kingRing[Us] = PseudoAttacks[Us][KING][s] | s;
++        kingRing[Us] = attacks_bb<KING>(s) | s;
 +    }
  
      kingAttackersCount[Them] = popcount(kingRing[Us] & pe->pawn_attacks(Them));
      kingAttacksCount[Them] = kingAttackersWeight[Them] = 0;
          // Find attacked squares, including x-ray attacks for bishops and rooks
          b = Pt == BISHOP ? attacks_bb<BISHOP>(s, pos.pieces() ^ pos.pieces(QUEEN))
            : Pt ==   ROOK ? attacks_bb<  ROOK>(s, pos.pieces() ^ pos.pieces(QUEEN) ^ pos.pieces(Us, ROOK))
 -                         : attacks_bb<Pt>(s, pos.pieces());
 +                         : pos.attacks_from(Us, Pt, s);
 +
 +        // Restrict mobility to actual squares of board
-         b &= pos.board_bb();
++        b &= pos.board_bb(Us, Pt);
  
          if (pos.blockers_for_king(Us) & s)
              b &= LineBB[pos.square<KING>(Us)][s];
diff --cc src/movegen.cpp
@@@ -138,10 -82,10 +138,10 @@@ namespace 
              b2 &= target;
          }
  
 -        if (Type == QUIET_CHECKS)
 +        if (Type == QUIET_CHECKS && pos.count<KING>(Them))
          {
-             b1 &= pos.attacks_from<PAWN>(ksq, Them);
-             b2 &= pos.attacks_from<PAWN>(ksq, Them);
+             b1 &= pawn_attacks_bb(Them, ksq);
+             b2 &= pawn_attacks_bb(Them, ksq);
  
              // 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
@@@ -472,13 -303,13 +472,13 @@@ ExtMove* generate<QUIET_CHECKS>(const P
       Square from = pop_lsb(&dc);
       PieceType pt = type_of(pos.piece_on(from));
  
 -     Bitboard b = attacks_bb(pt, from, pos.pieces()) & ~pos.pieces();
 +     Bitboard b = pos.moves_from(us, pt, from) & ~pos.pieces();
  
 -     if (pt == KING)
 +     if (pt == KING && pos.king_type() == KING)
-          b &= ~PseudoAttacks[~us][QUEEN][pos.square<KING>(~us)];
+          b &= ~attacks_bb<QUEEN>(pos.square<KING>(~us));
  
       while (b)
 -         *moveList++ = make_move(from, pop_lsb(&b));
 +         moveList = make_move_and_gating<NORMAL>(pos, moveList, us, from, pop_lsb(&b));
    }
  
    return us == WHITE ? generate_all<WHITE, QUIET_CHECKS>(pos, moveList)
diff --cc src/pawns.cpp
@@@ -98,14 -98,14 +98,14 @@@ namespace 
  
          // Flag the pawn
          opposed    = theirPawns & forward_file_bb(Us, s);
 -        blocked    = theirPawns & (s + Up);
 +        blocked    = is_ok(s + Up) ? theirPawns & (s + Up) : Bitboard(0);
          stoppers   = theirPawns & passed_pawn_span(Us, s);
-         lever      = theirPawns & PseudoAttacks[Us][PAWN][s];
-         leverPush  = relative_rank(Them, s, pos.max_rank()) > RANK_1 ? theirPawns & PseudoAttacks[Us][PAWN][s + Up] : Bitboard(0);
+         lever      = theirPawns & pawn_attacks_bb(Us, s);
 -        leverPush  = theirPawns & pawn_attacks_bb(Us, s + Up);
 -        doubled    = ourPawns   & (s - Up);
++        leverPush  = relative_rank(Them, s, pos.max_rank()) > RANK_1 ? theirPawns & pawn_attacks_bb(Us, s + Up) : Bitboard(0);
 +        doubled    = r > RANK_1 ? ourPawns & (s - Up) : Bitboard(0);
          neighbours = ourPawns   & adjacent_files_bb(s);
          phalanx    = neighbours & rank_bb(s);
 -        support    = neighbours & rank_bb(s - Up);
 +        support    = r > RANK_1 ? neighbours & rank_bb(s - Up) : Bitboard(0);
  
          // A pawn is backward when it is behind all pawns of the same color on
          // the adjacent files and cannot safely advance.
@@@ -176,13 -136,10 +176,13 @@@ void Position::init() 
    std::memset(cuckoo, 0, sizeof(cuckoo));
    std::memset(cuckooMove, 0, sizeof(cuckooMove));
    int count = 0;
 -  for (Piece pc : Pieces)
 -      for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
 -          for (Square s2 = Square(s1 + 1); s2 <= SQ_H8; ++s2)
 -              if ((type_of(pc) != PAWN) && (attacks_bb(type_of(pc), s1, 0) & s2))
 +  for (Color c : {WHITE, BLACK})
 +      for (PieceType pt = KNIGHT; pt <= QUEEN || pt == KING; pt != QUEEN ? ++pt : pt = KING)
 +      {
 +      Piece pc = make_piece(c, pt);
 +      for (Square s1 = SQ_A1; s1 <= SQ_MAX; ++s1)
 +          for (Square s2 = Square(s1 + 1); s2 <= SQ_MAX; ++s2)
-               if (PseudoAttacks[WHITE][type_of(pc)][s1] & s2)
++              if ((type_of(pc) != PAWN) && (attacks_bb(c, type_of(pc), s1, 0) & s2))
                {
                    Move move = make_move(s1, s2);
                    Key key = Zobrist::psq[pc][s1] ^ Zobrist::psq[pc][s2] ^ Zobrist::side;
@@@ -1029,26 -585,20 +1029,26 @@@ 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<PAWN>(from, us) & pieces(~us) & to) // Not a capture
+       if (   !(pawn_attacks_bb(us, from) & 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
 -               && (relative_rank(us, from) == 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_bb(type_of(pc), from, pieces()) & to))
 +  else if (!((capture(m) ? attacks_from(us, type_of(pc), from) : moves_from(us, type_of(pc), from)) & to))
        return false;
  
 +  // Janggi cannon
 +  if (type_of(pc) == JANGGI_CANNON && (pieces(JANGGI_CANNON) & (between_bb(from, to) | to)))
 +       return false;
 +
    // Evasions generator already takes care to avoid some kind of illegal moves
    // and legal() relies on this. We therefore have to take care that the same
    // kind of moves are filtered out here.
@@@ -1386,9 -793,8 +1386,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<PAWN>(to - pawn_push(us), us) & pieces(them, PAWN)))
+           && (pawn_attacks_bb(us, to - pawn_push(us)) & pieces(them, PAWN)))
        {
            st->epSquare = to - pawn_push(us);
            k ^= Zobrist::enpassant[file_of(st->epSquare)];
diff --cc src/position.h
@@@ -210,14 -111,8 +210,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 slider_blockers(Bitboard sliders, Square s, Bitboard& pinners) const;
 +  Bitboard attackers_to(Square s, Bitboard occupied, Color c) const;
 +  Bitboard attackers_to(Square s, Bitboard occupied, Color c, Bitboard janggiCannons) const;
 +  Bitboard attacks_from(Color c, PieceType pt, Square s) const;
-   template<PieceType> Bitboard attacks_from(Square s, Color c) 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;
@@@ -902,67 -281,6 +901,62 @@@ inline Square Position::castling_rook_s
    return castlingRookSquare[cr];
  }
  
- template<PieceType Pt>
- inline Bitboard Position::attacks_from(Square s, Color c) const {
-   return attacks_from(c, Pt, s);
- }
 +inline Bitboard Position::attacks_from(Color c, PieceType pt, Square s) const {
 +  PieceType movePt = pt == KING ? king_type() : pt;
 +  Bitboard b = attacks_bb(c, movePt, s, byTypeBB[ALL_PIECES]);
 +  // Xiangqi soldier
 +  if (pt == SOLDIER && !(promoted_soldiers(c) & s))
 +      b &= file_bb(file_of(s));
 +  // Janggi cannon restrictions
 +  if (pt == JANGGI_CANNON)
 +  {
 +      b &= ~pieces(pt);
 +      b &= attacks_bb(c, pt, s, pieces() ^ pieces(pt));
 +  }
 +  // Janggi palace moves
 +  if (diagonal_lines() & s)
 +  {
 +      PieceType diagType = movePt == WAZIR ? FERS : movePt == SOLDIER ? PAWN : movePt == ROOK ? BISHOP : NO_PIECE_TYPE;
 +      if (diagType)
 +          b |= attacks_bb(c, diagType, s, pieces()) & diagonal_lines();
 +      else if (movePt == JANGGI_CANNON)
 +          // TODO: fix for longer diagonals
 +          b |=   attacks_bb(c, ALFIL, s, pieces())
 +              & ~attacks_bb(c, ELEPHANT, s, pieces() ^ pieces(pt))
 +              & ~pieces(pt)
 +              & diagonal_lines();
 +  }
 +  return b & board_bb(c, pt);
 +}
 +
 +inline Bitboard Position::moves_from(Color c, PieceType pt, Square s) const {
 +  PieceType movePt = pt == KING ? king_type() : pt;
 +  Bitboard b = moves_bb(c, movePt, s, byTypeBB[ALL_PIECES]);
 +  // Xiangqi soldier
 +  if (pt == SOLDIER && !(promoted_soldiers(c) & s))
 +      b &= file_bb(file_of(s));
 +  // Janggi cannon restrictions
 +  if (pt == JANGGI_CANNON)
 +  {
 +      b &= ~pieces(pt);
 +      b &= attacks_bb(c, pt, s, pieces() ^ pieces(pt));
 +  }
 +  // Janggi palace moves
 +  if (diagonal_lines() & s)
 +  {
 +      PieceType diagType = movePt == WAZIR ? FERS : movePt == SOLDIER ? PAWN : movePt == ROOK ? BISHOP : NO_PIECE_TYPE;
 +      if (diagType)
 +          b |= attacks_bb(c, diagType, s, pieces()) & diagonal_lines();
 +      else if (movePt == JANGGI_CANNON)
 +          // TODO: fix for longer diagonals
 +          b |=   attacks_bb(c, ALFIL, s, pieces())
 +              & ~attacks_bb(c, ELEPHANT, s, pieces() ^ pieces(pt))
 +              & ~pieces(pt)
 +              & diagonal_lines();
 +  }
 +  return b & board_bb(c, pt);
 +}
 +
  inline Bitboard Position::attackers_to(Square s) const {
    return attackers_to(s, pieces());
  }