: 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.
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];
}
// 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];
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
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)
// 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.
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;
{
// 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.
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)];
// 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;
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());
}