Direction step = to > from ? WEST : EAST;
for (Square s = to; s != from; s += step)
- if (attackers_to(s) & pieces(~us))
+ if (attackers_to(s, ~us))
return false;
+ // TODO: need to consider touching kings
+ if (var->extinctionPseudoRoyal && attackers_to(from, ~us))
+ return false;
+
+ // Will the gate be blocked by king or rook?
+ Square rto = to + (to_sq(m) > from_sq(m) ? WEST : EAST);
+ if (is_gating(m) && (gating_square(m) == to || gating_square(m) == rto))
+ return false;
+
- // In case of Chess960, verify that when moving the castling rook we do
- // not discover some hidden checker.
+ // In case of Chess960, verify if the Rook blocks some checks
// For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1.
- return !chess960
- || !(attackers_to(to, pieces() ^ to_sq(m), ~us));
- return !chess960 || !(blockers_for_king(us) & to_sq(m));
++ return !chess960 || !attackers_to(to, pieces() ^ to_sq(m), ~us);
}
- // If the moving piece is a king, check whether the destination square is
- // attacked by the opponent.
- if (type_of(piece_on(from)) == KING)
- return !(attackers_to(to) & pieces(~us));
+ Bitboard occupied = (type_of(m) != DROP ? pieces() ^ from : pieces()) | to;
+
+ // Flying general rule and bikjang
+ // In case of bikjang passing is always allowed, even when in check
+ if (st->bikjang && is_pass(m))
+ return true;
+ if ((var->flyingGeneral && count<KING>(us)) || st->bikjang)
+ {
+ Square s = type_of(moved_piece(m)) == KING ? to : square<KING>(us);
+ if (attacks_bb(~us, ROOK, s, occupied) & pieces(~us, KING) & ~square_bb(to))
+ return false;
+ }
- // A non-king move is legal if and only if it is not pinned or it
- // is moving along the ray towards or away from the king.
- return !(blockers_for_king(us) & from)
- || aligned(from, to, square<KING>(us));
+ // Makpong rule
+ if (var->makpongRule && checkers() && type_of(moved_piece(m)) == KING && (checkers() ^ to))
+ return false;
+
+ // If the moving piece is a king, check whether the destination
+ // square is attacked by the opponent. Castling moves are checked
+ // for legality during move generation.
+ if (type_of(moved_piece(m)) == KING)
+ return type_of(m) == CASTLING || !attackers_to(to, occupied, ~us);
+
+ Bitboard janggiCannons = pieces(JANGGI_CANNON);
+ if (type_of(moved_piece(m)) == JANGGI_CANNON)
+ janggiCannons = (type_of(m) == DROP ? janggiCannons : janggiCannons ^ from) | to;
+ else if (janggiCannons & to)
+ janggiCannons ^= to;
+
+ // A non-king move is legal if the king is not under attack after the move.
+ return !count<KING>(us) || !(attackers_to(square<KING>(us), occupied, ~us, janggiCannons) & ~SquareBB[to]);
}
Square to = to_sq(m);
Piece pc = moved_piece(m);
+ // Illegal moves to squares outside of board
+ if (!(board_bb() & to))
+ return false;
+
+ // Use a fast check for piece drops
+ if (type_of(m) == DROP)
+ return piece_drops()
+ && pc != NO_PIECE
+ && color_of(pc) == us
+ && count_in_hand(us, in_hand_piece_type(m))
+ && (drop_region(us, type_of(pc)) & ~pieces() & to)
+ && ( type_of(pc) == in_hand_piece_type(m)
+ || (drop_promoted() && type_of(pc) == promoted_piece_type(in_hand_piece_type(m))));
+
// Use a slower but simpler function for uncommon cases
+ // yet we skip the legality check of MoveList<LEGAL>().
- if (type_of(m) != NORMAL)
+ if (type_of(m) != NORMAL || is_gating(m) || arrow_gating())
- return MoveList<LEGAL>(*this).contains(m);
+ return checkers() ? MoveList< EVASIONS>(*this).contains(m)
+ : MoveList<NON_EVASIONS>(*this).contains(m);
+ // Handle the case where a mandatory piece promotion/demotion is not taken
+ if ( mandatory_piece_promotion()
+ && (is_promoted(from) ? piece_demotion() : promoted_piece_type(type_of(pc)) != NO_PIECE_TYPE)
+ && (zone_bb(us, promotion_rank(), max_rank()) & (SquareBB[from] | to))
+ && (!piece_promotion_on_capture() || capture(m)))
+ return false;
+
// Is not a promotion, so promotion piece must be empty
- if (promotion_type(m) - KNIGHT != NO_PIECE_TYPE)
+ if (promotion_type(m) != NO_PIECE_TYPE)
return false;
// If the 'from' square is not occupied by a piece belonging to the side to
Square capsq = make_square(file_of(to), rank_of(from));
Bitboard b = (pieces() ^ from ^ capsq) | to;
- return (attacks_bb< ROOK>(square<KING>(~sideToMove), b) & pieces(sideToMove, QUEEN, ROOK))
- | (attacks_bb<BISHOP>(square<KING>(~sideToMove), b) & pieces(sideToMove, QUEEN, BISHOP));
+ return attackers_to(square<KING>(~sideToMove), b) & pieces(sideToMove) & b;
}
- case CASTLING:
+ default: //CASTLING
{
+ // Castling is encoded as 'king captures the rook'
- Square ksq = square<KING>(~sideToMove);
- Square rto = relative_square(sideToMove, to > from ? SQ_F1 : SQ_D1);
+ Square kfrom = from;
- Square rfrom = to; // Castling is encoded as 'king captures the rook'
++ Square rfrom = to;
+ Square kto = make_square(rfrom > kfrom ? castling_kingside_file() : castling_queenside_file(), castling_rank(sideToMove));
+ Square rto = kto + (rfrom > kfrom ? WEST : EAST);
- return (attacks_bb<ROOK>(rto) & ksq)
- && (attacks_bb<ROOK>(rto, pieces() ^ from ^ to) & ksq);
+ return (PseudoAttacks[sideToMove][type_of(piece_on(rfrom))][rto] & square<KING>(~sideToMove))
+ && (attacks_bb(sideToMove, type_of(piece_on(rfrom)), rto, (pieces() ^ kfrom ^ rfrom) | rto | kto) & square<KING>(~sideToMove));
}
- default:
- assert(false);
- return false;
}
}