1
0
Fork 0
mirror of https://github.com/sockspls/badfish synced 2025-07-11 11:39:15 +00:00

Remove redundancy in move generation

Introduce generate_all_moves() and remove a good
bunch of redundant code.

No functional change.
This commit is contained in:
Marco Costalba 2012-09-09 14:30:22 +02:00
parent 0dacab65eb
commit 1598a3edf8

View file

@ -31,7 +31,7 @@
(*mlist++).move = make_move(to - (d), to); } (*mlist++).move = make_move(to - (d), to); }
namespace { namespace {
template<CastlingSide Side, bool OnlyChecks> template<CastlingSide Side, bool Checks>
MoveStack* generate_castle(const Position& pos, MoveStack* mlist, Color us) { MoveStack* generate_castle(const Position& pos, MoveStack* mlist, Color us) {
if (pos.castle_impeded(us, Side) || !pos.can_castle(make_castle_right(us, Side))) if (pos.castle_impeded(us, Side) || !pos.can_castle(make_castle_right(us, Side)))
@ -59,7 +59,7 @@ namespace {
(*mlist++).move = make<CASTLE>(kfrom, rfrom); (*mlist++).move = make<CASTLE>(kfrom, rfrom);
if (OnlyChecks && !pos.move_gives_check((mlist - 1)->move, CheckInfo(pos))) if (Checks && !pos.move_gives_check((mlist - 1)->move, CheckInfo(pos)))
mlist--; mlist--;
return mlist; return mlist;
@ -79,7 +79,8 @@ namespace {
template<GenType Type, Square Delta> template<GenType Type, Square Delta>
inline MoveStack* generate_promotions(MoveStack* mlist, Bitboard pawnsOn7, Bitboard target, Square ksq) { inline MoveStack* generate_promotions(MoveStack* mlist, Bitboard pawnsOn7,
Bitboard target, const CheckInfo* ci) {
Bitboard b = move_pawns<Delta>(pawnsOn7) & target; Bitboard b = move_pawns<Delta>(pawnsOn7) & target;
@ -99,10 +100,10 @@ namespace {
// Knight-promotion is the only one that can give a direct check not // Knight-promotion is the only one that can give a direct check not
// already included in the queen-promotion. // already included in the queen-promotion.
if (Type == QUIET_CHECKS && (StepAttacksBB[W_KNIGHT][to] & ksq)) if (Type == QUIET_CHECKS && (StepAttacksBB[W_KNIGHT][to] & ci->ksq))
(*mlist++).move = make<PROMOTION>(to - Delta, to, KNIGHT); (*mlist++).move = make<PROMOTION>(to - Delta, to, KNIGHT);
else else
(void)ksq; // Silence a warning under MSVC (void)ci; // Silence a warning under MSVC
} }
return mlist; return mlist;
@ -110,7 +111,8 @@ namespace {
template<Color Us, GenType Type> template<Color Us, GenType Type>
MoveStack* generate_pawn_moves(const Position& pos, MoveStack* mlist, Bitboard target, Square ksq = SQ_NONE) { MoveStack* generate_pawn_moves(const Position& pos, MoveStack* mlist,
Bitboard target, const CheckInfo* ci) {
// Compute our parametrized parameters at compile time, named according to // Compute our parametrized parameters at compile time, named according to
// the point of view of white side. // the point of view of white side.
@ -133,7 +135,7 @@ namespace {
// Single and double pawn pushes, no promotions // Single and double pawn pushes, no promotions
if (Type != CAPTURES) if (Type != CAPTURES)
{ {
emptySquares = (Type == QUIETS ? target : ~pos.pieces()); emptySquares = (Type == QUIETS || Type == QUIET_CHECKS ? target : ~pos.pieces());
b1 = move_pawns<UP>(pawnsNotOn7) & emptySquares; b1 = move_pawns<UP>(pawnsNotOn7) & emptySquares;
b2 = move_pawns<UP>(b1 & TRank3BB) & emptySquares; b2 = move_pawns<UP>(b1 & TRank3BB) & emptySquares;
@ -146,16 +148,16 @@ namespace {
if (Type == QUIET_CHECKS) if (Type == QUIET_CHECKS)
{ {
b1 &= pos.attacks_from<PAWN>(ksq, Them); b1 &= pos.attacks_from<PAWN>(ci->ksq, Them);
b2 &= pos.attacks_from<PAWN>(ksq, Them); b2 &= pos.attacks_from<PAWN>(ci->ksq, Them);
// Add pawn pushes which give discovered check. This is possible only // 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 // if the pawn is not on the same file as the enemy king, because we
// don't generate captures. Note that a possible discovery check // don't generate captures. Note that a possible discovery check
// promotion has been already generated among captures. // promotion has been already generated among captures.
if (pawnsNotOn7 & target) // Target is dc bitboard if (pawnsNotOn7 & ci->dcCandidates)
{ {
dc1 = move_pawns<UP>(pawnsNotOn7 & target) & emptySquares & ~file_bb(ksq); dc1 = move_pawns<UP>(pawnsNotOn7 & ci->dcCandidates) & emptySquares & ~file_bb(ci->ksq);
dc2 = move_pawns<UP>(dc1 & TRank3BB) & emptySquares; dc2 = move_pawns<UP>(dc1 & TRank3BB) & emptySquares;
b1 |= dc1; b1 |= dc1;
@ -176,9 +178,9 @@ namespace {
if (Type == EVASIONS) if (Type == EVASIONS)
emptySquares &= target; emptySquares &= target;
mlist = generate_promotions<Type, RIGHT>(mlist, pawnsOn7, enemies, ksq); mlist = generate_promotions<Type, RIGHT>(mlist, pawnsOn7, enemies, ci);
mlist = generate_promotions<Type, LEFT>(mlist, pawnsOn7, enemies, ksq); mlist = generate_promotions<Type, LEFT>(mlist, pawnsOn7, enemies, ci);
mlist = generate_promotions<Type, UP>(mlist, pawnsOn7, emptySquares, ksq); mlist = generate_promotions<Type, UP>(mlist, pawnsOn7, emptySquares, ci);
} }
// Standard and en-passant captures // Standard and en-passant captures
@ -213,9 +215,9 @@ namespace {
} }
template<PieceType Pt, bool OnlyChecks> FORCE_INLINE template<PieceType Pt, bool Checks> FORCE_INLINE
MoveStack* generate_moves(const Position& pos, MoveStack* mlist, Color us, MoveStack* generate_moves(const Position& pos, MoveStack* mlist, Color us,
Bitboard target, const CheckInfo* ci = NULL) { Bitboard target, const CheckInfo* ci) {
assert(Pt != KING && Pt != PAWN); assert(Pt != KING && Pt != PAWN);
@ -223,7 +225,7 @@ namespace {
for (Square from = *pl; from != SQ_NONE; from = *++pl) for (Square from = *pl; from != SQ_NONE; from = *++pl)
{ {
if (OnlyChecks) if (Checks)
{ {
if ( (Pt == BISHOP || Pt == ROOK || Pt == QUEEN) if ( (Pt == BISHOP || Pt == ROOK || Pt == QUEEN)
&& !(PseudoAttacks[Pt][from] & target & ci->checkSq[Pt])) && !(PseudoAttacks[Pt][from] & target & ci->checkSq[Pt]))
@ -235,7 +237,7 @@ namespace {
Bitboard b = pos.attacks_from<Pt>(from) & target; Bitboard b = pos.attacks_from<Pt>(from) & target;
if (OnlyChecks) if (Checks)
b &= ci->checkSq[Pt]; b &= ci->checkSq[Pt];
SERIALIZE(b); SERIALIZE(b);
@ -244,15 +246,41 @@ namespace {
return mlist; return mlist;
} }
template<> FORCE_INLINE
MoveStack* generate_moves<KING, false>(const Position& pos, MoveStack* mlist, Color us, FORCE_INLINE MoveStack* generate_king_moves(const Position& pos, MoveStack* mlist,
Bitboard target, const CheckInfo*) { Color us, Bitboard target) {
Square from = pos.king_square(us); Square from = pos.king_square(us);
Bitboard b = pos.attacks_from<KING>(from) & target; Bitboard b = pos.attacks_from<KING>(from) & target;
SERIALIZE(b); SERIALIZE(b);
return mlist; return mlist;
} }
template<GenType Type> FORCE_INLINE
MoveStack* generate_all_moves(const Position& pos, MoveStack* mlist, Color us,
Bitboard target, const CheckInfo* ci = NULL) {
mlist = (us == WHITE ? generate_pawn_moves<WHITE, Type>(pos, mlist, target, ci)
: generate_pawn_moves<BLACK, Type>(pos, mlist, target, ci));
mlist = generate_moves<KNIGHT, Type == QUIET_CHECKS>(pos, mlist, us, target, ci);
mlist = generate_moves<BISHOP, Type == QUIET_CHECKS>(pos, mlist, us, target, ci);
mlist = generate_moves<ROOK, Type == QUIET_CHECKS>(pos, mlist, us, target, ci);
mlist = generate_moves<QUEEN, Type == QUIET_CHECKS>(pos, mlist, us, target, ci);
if (Type != QUIET_CHECKS && Type != EVASIONS)
mlist = generate_king_moves(pos, mlist, us, target);
if (Type != CAPTURES && Type != EVASIONS && pos.can_castle(us))
{
mlist = generate_castle<KING_SIDE, Type == QUIET_CHECKS>(pos, mlist, us);
mlist = generate_castle<QUEEN_SIDE, Type == QUIET_CHECKS>(pos, mlist, us);
}
return mlist;
}
} // namespace } // namespace
@ -283,28 +311,13 @@ MoveStack* generate(const Position& pos, MoveStack* mlist) {
else if (Type == NON_EVASIONS) else if (Type == NON_EVASIONS)
target = ~pos.pieces(us); target = ~pos.pieces(us);
mlist = (us == WHITE ? generate_pawn_moves<WHITE, Type>(pos, mlist, target) return generate_all_moves<Type>(pos, mlist, us, target);
: generate_pawn_moves<BLACK, Type>(pos, mlist, target));
mlist = generate_moves<KNIGHT, false>(pos, mlist, us, target);
mlist = generate_moves<BISHOP, false>(pos, mlist, us, target);
mlist = generate_moves<ROOK, false>(pos, mlist, us, target);
mlist = generate_moves<QUEEN, false>(pos, mlist, us, target);
mlist = generate_moves<KING, false>(pos, mlist, us, target);
if (Type != CAPTURES && pos.can_castle(us))
{
mlist = generate_castle<KING_SIDE, false>(pos, mlist, us);
mlist = generate_castle<QUEEN_SIDE, false>(pos, mlist, us);
}
return mlist;
} }
// Explicit template instantiations // Explicit template instantiations
template MoveStack* generate<CAPTURES>(const Position& pos, MoveStack* mlist); template MoveStack* generate<CAPTURES>(const Position&, MoveStack*);
template MoveStack* generate<QUIETS>(const Position& pos, MoveStack* mlist); template MoveStack* generate<QUIETS>(const Position&, MoveStack*);
template MoveStack* generate<NON_EVASIONS>(const Position& pos, MoveStack* mlist); template MoveStack* generate<NON_EVASIONS>(const Position&, MoveStack*);
/// generate<QUIET_CHECKS> generates all pseudo-legal non-captures and knight /// generate<QUIET_CHECKS> generates all pseudo-legal non-captures and knight
@ -316,7 +329,6 @@ MoveStack* generate<QUIET_CHECKS>(const Position& pos, MoveStack* mlist) {
Color us = pos.side_to_move(); Color us = pos.side_to_move();
CheckInfo ci(pos); CheckInfo ci(pos);
Bitboard empty = ~pos.pieces();
Bitboard dc = ci.dcCandidates; Bitboard dc = ci.dcCandidates;
while (dc) while (dc)
@ -335,21 +347,7 @@ MoveStack* generate<QUIET_CHECKS>(const Position& pos, MoveStack* mlist) {
SERIALIZE(b); SERIALIZE(b);
} }
mlist = (us == WHITE ? generate_pawn_moves<WHITE, QUIET_CHECKS>(pos, mlist, ci.dcCandidates, ci.ksq) return generate_all_moves<QUIET_CHECKS>(pos, mlist, us, ~pos.pieces(), &ci);
: generate_pawn_moves<BLACK, QUIET_CHECKS>(pos, mlist, ci.dcCandidates, ci.ksq));
mlist = generate_moves<KNIGHT, true>(pos, mlist, us, empty, &ci);
mlist = generate_moves<BISHOP, true>(pos, mlist, us, empty, &ci);
mlist = generate_moves<ROOK, true>(pos, mlist, us, empty, &ci);
mlist = generate_moves<QUEEN, true>(pos, mlist, us, empty, &ci);
if (pos.can_castle(us))
{
mlist = generate_castle<KING_SIDE, true>(pos, mlist, us);
mlist = generate_castle<QUEEN_SIDE, true>(pos, mlist, us);
}
return mlist;
} }
@ -360,19 +358,17 @@ MoveStack* generate<EVASIONS>(const Position& pos, MoveStack* mlist) {
assert(pos.in_check()); assert(pos.in_check());
Bitboard b, target;
Square from, checksq; Square from, checksq;
int checkersCnt = 0; int checkersCnt = 0;
Color us = pos.side_to_move(); Color us = pos.side_to_move();
Square ksq = pos.king_square(us); Square ksq = pos.king_square(us);
Bitboard sliderAttacks = 0; Bitboard sliderAttacks = 0;
Bitboard checkers = pos.checkers(); Bitboard b = pos.checkers();
assert(checkers); assert(pos.checkers());
// Find squares attacked by slider checkers, we will remove them from the king // Find squares attacked by slider checkers, we will remove them from the king
// evasions so to skip known illegal moves avoiding useless legality check later. // evasions so to skip known illegal moves avoiding useless legality check later.
b = checkers;
do do
{ {
checkersCnt++; checkersCnt++;
@ -407,20 +403,13 @@ MoveStack* generate<EVASIONS>(const Position& pos, MoveStack* mlist) {
from = ksq; from = ksq;
SERIALIZE(b); SERIALIZE(b);
// Generate evasions for other pieces only if not under a double check
if (checkersCnt > 1) if (checkersCnt > 1)
return mlist; return mlist; // Double check, only a king move can save the day
// Blocking evasions or captures of the checking piece // Generate blocking evasions or captures of the checking piece
target = between_bb(checksq, ksq) | checkers; Bitboard target = between_bb(checksq, ksq) | pos.checkers();
mlist = (us == WHITE ? generate_pawn_moves<WHITE, EVASIONS>(pos, mlist, target) return generate_all_moves<EVASIONS>(pos, mlist, us, target);
: generate_pawn_moves<BLACK, EVASIONS>(pos, mlist, target));
mlist = generate_moves<KNIGHT, false>(pos, mlist, us, target);
mlist = generate_moves<BISHOP, false>(pos, mlist, us, target);
mlist = generate_moves<ROOK, false>(pos, mlist, us, target);
return generate_moves<QUEEN, false>(pos, mlist, us, target);
} }