S(0, 0), S(10, 28), S(17, 33), S(15, 41), S(62, 72), S(168, 177), S(276, 260)
};
+ // KingProximity contains a penalty according to distance from king
+ constexpr Score KingProximity = S(2, 4);
+ constexpr Score EndgameKingProximity = S(0, 10);
+
// Assorted bonuses and penalties
constexpr Score BishopPawns = S( 3, 7);
+ constexpr Score BishopOnKingRing = S( 24, 0);
constexpr Score BishopXRayPawns = S( 4, 5);
constexpr Score CorneredBishop = S( 50, 50);
constexpr Score FlankAttacks = S( 8, 0);
if (b & kingRing[Them])
{
kingAttackersCount[Us]++;
- kingAttackersWeight[Us] += KingAttackWeights[Pt];
+ kingAttackersWeight[Us] += KingAttackWeights[std::min(int(Pt), QUEEN + 1)];
kingAttacksCount[Us] += popcount(b & attackedBy[Them][KING]);
}
+
else if (Pt == ROOK && (file_bb(s) & kingRing[Them]))
score += RookOnKingRing;
+ else if (Pt == BISHOP && (attacks_bb<BISHOP>(s, pos.pieces(PAWN)) & kingRing[Them]))
+ score += BishopOnKingRing;
+
+ if (Pt > QUEEN)
+ b = (b & pos.pieces()) | (pos.moves_from(Us, Pt, s) & ~pos.pieces() & pos.board_bb());
+
int mob = popcount(b & mobilityArea[Us]);
- mobility[Us] += MobilityBonus[Pt - 2][mob];
+ if (Pt <= QUEEN)
+ mobility[Us] += MobilityBonus[Pt - 2][mob];
+ else
+ mobility[Us] += MaxMobility * (mob - 2) / (8 + mob);
+
+ // Piece promotion bonus
+ if (pos.promoted_piece_type(Pt) != NO_PIECE_TYPE)
+ {
+ if (promotion_zone_bb(Us, pos.promotion_rank(), pos.max_rank()) & (b | s))
+ score += make_score(PieceValue[MG][pos.promoted_piece_type(Pt)] - PieceValue[MG][Pt],
+ PieceValue[EG][pos.promoted_piece_type(Pt)] - PieceValue[EG][Pt]) / 10;
+ }
+ else if (pos.piece_demotion() && pos.unpromoted_piece_on(s))
+ score -= make_score(PieceValue[MG][Pt] - PieceValue[MG][pos.unpromoted_piece_on(s)],
+ PieceValue[EG][Pt] - PieceValue[EG][pos.unpromoted_piece_on(s)]) / 4;
+ else if (pos.captures_to_hand() && pos.unpromoted_piece_on(s))
+ score += make_score(PieceValue[MG][Pt] - PieceValue[MG][pos.unpromoted_piece_on(s)],
+ PieceValue[EG][Pt] - PieceValue[EG][pos.unpromoted_piece_on(s)]) / 8;
+
+ // Penalty if the piece is far from the kings in drop variants
+ if ((pos.captures_to_hand() || pos.two_boards()) && pos.count<KING>(Them) && pos.count<KING>(Us))
+ score -= KingProximity * distance(s, pos.square<KING>(Us)) * distance(s, pos.square<KING>(Them));
+
+ else if (pos.count<KING>(Us) && (Pt == FERS || Pt == SILVER))
+ score -= EndgameKingProximity * (distance(s, pos.square<KING>(Us)) - 2);
if (Pt == BISHOP || Pt == KNIGHT)
{
}
- template<bool Checks>
- ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Color us, PieceType pt,
- Bitboard target) {
- template<Color Us, PieceType Pt, bool Checks>
- ExtMove* generate_moves(const Position& pos, ExtMove* moveList, Bitboard target) {
++ template<Color Us, bool Checks>
++ ExtMove* generate_moves(const Position& pos, ExtMove* moveList, PieceType pt, Bitboard target) {
- static_assert(Pt != KING && Pt != PAWN, "Unsupported piece type in generate_moves()");
+ assert(pt != KING && pt != PAWN);
- const Square* pl = pos.squares(us, pt);
- const Square* pl = pos.squares<Pt>(Us);
++ const Square* pl = pos.squares(Us, pt);
for (Square from = *pl; from != SQ_NONE; from = *++pl)
{
+ // Avoid generating discovered checks twice
- if (Checks && (pos.blockers_for_king(~us) & from))
++ if (Checks && (pos.blockers_for_king(~Us) & from))
+ continue;
+
- Bitboard b1 = ( (pos.attacks_from(us, pt, from) & pos.pieces())
- | (pos.moves_from(us, pt, from) & ~pos.pieces())) & target;
++ Bitboard b1 = ( (pos.attacks_from(Us, pt, from) & pos.pieces())
++ | (pos.moves_from(Us, pt, from) & ~pos.pieces())) & target;
+ PieceType prom_pt = pos.promoted_piece_type(pt);
- Bitboard b2 = prom_pt && (!pos.promotion_limit(prom_pt) || pos.promotion_limit(prom_pt) > pos.count(us, prom_pt)) ? b1 : Bitboard(0);
++ Bitboard b2 = prom_pt && (!pos.promotion_limit(prom_pt) || pos.promotion_limit(prom_pt) > pos.count(Us, prom_pt)) ? b1 : Bitboard(0);
+ Bitboard b3 = pos.piece_demotion() && pos.is_promoted(from) ? b1 : Bitboard(0);
+
if (Checks)
{
- if ( (Pt == BISHOP || Pt == ROOK || Pt == QUEEN)
- && !(attacks_bb<Pt>(from) & target & pos.check_squares(Pt)))
- continue;
+ b1 &= pos.check_squares(pt);
+ if (b2)
+ b2 &= pos.check_squares(pos.promoted_piece_type(pt));
+ if (b3)
+ b3 &= pos.check_squares(type_of(pos.unpromoted_piece_on(from)));
+ }
- if (pos.blockers_for_king(~Us) & from)
- continue;
+ // Restrict target squares considering promotion zone
+ if (b2 | b3)
+ {
- Bitboard promotion_zone = promotion_zone_bb(us, pos.promotion_rank(), pos.max_rank());
++ Bitboard promotion_zone = promotion_zone_bb(Us, pos.promotion_rank(), pos.max_rank());
+ if (pos.mandatory_piece_promotion())
+ b1 &= (promotion_zone & from ? Bitboard(0) : ~promotion_zone) | (pos.piece_promotion_on_capture() ? ~pos.pieces() : Bitboard(0));
+ // Exclude quiet promotions/demotions
+ if (pos.piece_promotion_on_capture())
+ {
+ b2 &= pos.pieces();
+ b3 &= pos.pieces();
+ }
+ // Consider promotions/demotions into promotion zone
+ if (!(promotion_zone & from))
+ {
+ b2 &= promotion_zone;
+ b3 &= promotion_zone;
+ }
}
- Bitboard b = attacks_bb<Pt>(from, pos.pieces()) & target;
+ while (b1)
- moveList = make_move_and_gating<NORMAL>(pos, moveList, us, from, pop_lsb(&b1));
++ moveList = make_move_and_gating<NORMAL>(pos, moveList, Us, from, pop_lsb(&b1));
- if (Checks)
- b &= pos.check_squares(Pt);
+ // Shogi-style piece promotions
+ while (b2)
+ *moveList++ = make<PIECE_PROMOTION>(from, pop_lsb(&b2));
- while (b)
- *moveList++ = make_move(from, pop_lsb(&b));
+ // Piece demotions
+ while (b3)
+ *moveList++ = make<PIECE_DEMOTION>(from, pop_lsb(&b3));
}
return moveList;
default:
static_assert(true, "Unsupported type in generate_all()");
}
+ target &= pos.board_bb();
moveList = generate_pawn_moves<Us, Type>(pos, moveList, target);
- moveList = generate_moves<Us, KNIGHT, Checks>(pos, moveList, target);
- moveList = generate_moves<Us, BISHOP, Checks>(pos, moveList, target);
- moveList = generate_moves<Us, ROOK, Checks>(pos, moveList, target);
- moveList = generate_moves<Us, QUEEN, Checks>(pos, moveList, target);
-
- if (Type != QUIET_CHECKS && Type != EVASIONS)
+ for (PieceType pt : pos.piece_types())
+ if (pt != PAWN && pt != KING)
- moveList = generate_moves<Checks>(pos, moveList, Us, pt, target);
++ moveList = generate_moves<Us, Checks>(pos, moveList, pt, target);
+ // generate drops
+ if (pos.piece_drops() && Type != CAPTURES && pos.count_in_hand(Us, ALL_PIECES))
+ for (PieceType pt : pos.piece_types())
+ moveList = generate_drops<Us, Checks>(pos, moveList, pt, target & ~pos.pieces(~Us));
+
+ if (Type != QUIET_CHECKS && Type != EVASIONS && pos.count<KING>(Us))
{
Square ksq = pos.square<KING>(Us);
- Bitboard b = attacks_bb<KING>(ksq) & target;
+ Bitboard b = ( (pos.attacks_from(Us, KING, ksq) & pos.pieces())
+ | (pos.moves_from(Us, KING, ksq) & ~pos.pieces())) & target;
while (b)
- *moveList++ = make_move(ksq, pop_lsb(&b));
+ moveList = make_move_and_gating<NORMAL>(pos, moveList, Us, ksq, pop_lsb(&b));
+
+ // Passing move by king
+ if (pos.pass())
+ *moveList++ = make<SPECIAL>(ksq, ksq);
if ((Type != CAPTURES) && pos.can_castle(Us & ANY_CASTLING))
for(CastlingRights cr : { Us & KING_SIDE, Us & QUEEN_SIDE } )