mirror of
https://github.com/sockspls/badfish
synced 2025-04-30 16:53:09 +00:00
Rearrange pawn moves generation
This patch greatly cleanups generation of pawn moves but we change the order in which moves are generated so there is a change in functionality, but not in perft. The only real functionality change is that now when type == CHECK we generate knight underpromotion captures only if give check and not always as before. Perft is 2% faster and fully verified. Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This commit is contained in:
parent
6f70e762a9
commit
d08a8d76f7
1 changed files with 56 additions and 68 deletions
124
src/movegen.cpp
124
src/movegen.cpp
|
@ -455,35 +455,27 @@ namespace {
|
||||||
template<MoveType Type, SquareDelta Delta>
|
template<MoveType Type, SquareDelta Delta>
|
||||||
inline MoveStack* generate_pawn_captures(MoveStack* mlist, Bitboard pawns, Bitboard target) {
|
inline MoveStack* generate_pawn_captures(MoveStack* mlist, Bitboard pawns, Bitboard target) {
|
||||||
|
|
||||||
// Calculate our parametrized parameters at compile time
|
|
||||||
const Bitboard TRank8BB = (Delta == DELTA_NE || Delta == DELTA_NW ? Rank8BB : Rank1BB);
|
|
||||||
const Bitboard TFileABB = (Delta == DELTA_NE || Delta == DELTA_SE ? FileABB : FileHBB);
|
const Bitboard TFileABB = (Delta == DELTA_NE || Delta == DELTA_SE ? FileABB : FileHBB);
|
||||||
|
|
||||||
Bitboard b;
|
Bitboard b;
|
||||||
Square to;
|
Square to;
|
||||||
|
|
||||||
// Captures in the a1-h8 (a8-h1 for black) diagonal or in the h1-a8 (h8-a1 for black)
|
// Captures in the a1-h8 (a8-h1 for black) diagonal or in the h1-a8 (h8-a1 for black)
|
||||||
if (Type == CAPTURE || Type == EVASION)
|
b = move_pawns<Delta>(pawns) & target & ~TFileABB;
|
||||||
{
|
SERIALIZE_MOVES_D(b, -Delta);
|
||||||
b = move_pawns<Delta>(pawns) & target & ~TFileABB & ~TRank8BB;
|
|
||||||
SERIALIZE_MOVES_D(b, -Delta);
|
|
||||||
}
|
|
||||||
return mlist;
|
return mlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Color Us, MoveType Type, SquareDelta Delta>
|
template<Color Us, MoveType Type, SquareDelta Delta>
|
||||||
inline MoveStack* generate_promotions(const Position& pos, MoveStack* mlist, Bitboard pawns, Bitboard target) {
|
inline MoveStack* generate_promotions(const Position& pos, MoveStack* mlist, Bitboard pawnsOn7, Bitboard target) {
|
||||||
|
|
||||||
// Calculate our parametrized parameters at compile time
|
|
||||||
const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
|
|
||||||
const Bitboard TFileABB = (Delta == DELTA_NE || Delta == DELTA_SE ? FileABB : FileHBB);
|
const Bitboard TFileABB = (Delta == DELTA_NE || Delta == DELTA_SE ? FileABB : FileHBB);
|
||||||
const bool IsPush = (Delta == DELTA_N || Delta == DELTA_S);
|
|
||||||
|
|
||||||
Bitboard b;
|
Bitboard b;
|
||||||
Square to;
|
Square to;
|
||||||
|
|
||||||
// Promotions and under-promotions
|
// Promotions and under-promotions, both captures and non-captures
|
||||||
b = move_pawns<Delta>(pawns) & target & TRank8BB;
|
b = move_pawns<Delta>(pawnsOn7) & target;
|
||||||
|
|
||||||
if (Delta != DELTA_N && Delta != DELTA_S)
|
if (Delta != DELTA_N && Delta != DELTA_S)
|
||||||
b &= ~TFileABB;
|
b &= ~TFileABB;
|
||||||
|
@ -502,16 +494,12 @@ namespace {
|
||||||
(*mlist++).move = make_promotion_move(to - Delta, to, KNIGHT);
|
(*mlist++).move = make_promotion_move(to - Delta, to, KNIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the only possible under promotion that can give a check
|
|
||||||
// not already included in the queen-promotion. It is not sure that
|
|
||||||
// the promoted knight will give check, but it doesn't worth to verify.
|
|
||||||
if (Type == CHECK && !IsPush)
|
|
||||||
(*mlist++).move = make_promotion_move(to - Delta, to, KNIGHT);
|
|
||||||
|
|
||||||
// This is the only possible under promotion that can give a check
|
// This is the only possible under promotion that can give a check
|
||||||
// not already included in the queen-promotion.
|
// not already included in the queen-promotion.
|
||||||
if (Type == CHECK && IsPush && bit_is_set(pos.attacks_from<KNIGHT>(to), pos.king_square(opposite_color(Us))))
|
if ( Type == CHECK
|
||||||
|
&& bit_is_set(pos.attacks_from<KNIGHT>(to), pos.king_square(opposite_color(Us))))
|
||||||
(*mlist++).move = make_promotion_move(to - Delta, to, KNIGHT);
|
(*mlist++).move = make_promotion_move(to - Delta, to, KNIGHT);
|
||||||
|
else (void)pos; // Silence a warning under MSVC
|
||||||
}
|
}
|
||||||
return mlist;
|
return mlist;
|
||||||
}
|
}
|
||||||
|
@ -519,72 +507,72 @@ namespace {
|
||||||
template<Color Us, MoveType Type>
|
template<Color Us, MoveType Type>
|
||||||
MoveStack* generate_pawn_moves(const Position& pos, MoveStack* mlist, Bitboard target, Square ksq) {
|
MoveStack* generate_pawn_moves(const Position& pos, MoveStack* mlist, Bitboard target, Square ksq) {
|
||||||
|
|
||||||
// Calculate our parametrized parameters at compile time
|
// Calculate our parametrized parameters at compile time, named
|
||||||
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
// according to the point of view of white side.
|
||||||
const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
|
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
||||||
const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
|
const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
|
||||||
const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
|
const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
|
||||||
const SquareDelta TDELTA_N = (Us == WHITE ? DELTA_N : DELTA_S);
|
const SquareDelta TDELTA_N = (Us == WHITE ? DELTA_N : DELTA_S);
|
||||||
const SquareDelta TDELTA_NE = (Us == WHITE ? DELTA_NE : DELTA_SE);
|
const SquareDelta TDELTA_NE = (Us == WHITE ? DELTA_NE : DELTA_SE);
|
||||||
const SquareDelta TDELTA_NW = (Us == WHITE ? DELTA_NW : DELTA_SW);
|
const SquareDelta TDELTA_NW = (Us == WHITE ? DELTA_NW : DELTA_SW);
|
||||||
|
|
||||||
Square to;
|
Square to;
|
||||||
Bitboard b1, b2, enemyPieces, emptySquares;
|
Bitboard b1, b2, dc1, dc2, pawnPushes, emptySquares;
|
||||||
Bitboard pawns = pos.pieces(PAWN, Us);
|
Bitboard pawns = pos.pieces(PAWN, Us);
|
||||||
|
Bitboard pawnsOn7 = pawns & TRank7BB;
|
||||||
|
Bitboard enemyPieces = (Type == CAPTURE ? target : pos.pieces_of_color(Them));
|
||||||
|
|
||||||
// Standard captures and capturing promotions and underpromotions
|
// Pre-calculate pawn pushes before changing emptySquares definition
|
||||||
if (Type == CAPTURE || Type == EVASION || (pawns & TRank7BB))
|
|
||||||
{
|
|
||||||
enemyPieces = (Type == CAPTURE ? target : pos.pieces_of_color(opposite_color(Us)));
|
|
||||||
|
|
||||||
if (Type == EVASION)
|
|
||||||
enemyPieces &= target; // Capture only the checker piece
|
|
||||||
|
|
||||||
mlist = generate_promotions<Us, Type, TDELTA_NE>(pos, mlist, pawns, enemyPieces);
|
|
||||||
mlist = generate_pawn_captures<Type, TDELTA_NE>(mlist, pawns, enemyPieces);
|
|
||||||
mlist = generate_promotions<Us, Type, TDELTA_NW>(pos, mlist, pawns, enemyPieces);
|
|
||||||
mlist = generate_pawn_captures<Type, TDELTA_NW>(mlist, pawns, enemyPieces);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Non-capturing promotions and underpromotions
|
|
||||||
if (pawns & TRank7BB)
|
|
||||||
{
|
|
||||||
b1 = pos.empty_squares();
|
|
||||||
|
|
||||||
if (Type == EVASION)
|
|
||||||
b1 &= target; // Only blocking promotion pushes
|
|
||||||
|
|
||||||
mlist = generate_promotions<Us, Type, TDELTA_N>(pos, mlist, pawns, b1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Standard pawn pushes and double pushes
|
|
||||||
if (Type != CAPTURE)
|
if (Type != CAPTURE)
|
||||||
{
|
{
|
||||||
emptySquares = (Type == NON_CAPTURE ? target : pos.empty_squares());
|
emptySquares = (Type == NON_CAPTURE ? target : pos.empty_squares());
|
||||||
|
pawnPushes = move_pawns<TDELTA_N>(pawns & ~TRank7BB) & emptySquares;
|
||||||
|
}
|
||||||
|
|
||||||
// Single and double pawn pushes
|
if (Type == EVASION)
|
||||||
b1 = move_pawns<TDELTA_N>(pawns) & emptySquares & ~TRank8BB;
|
{
|
||||||
b2 = move_pawns<TDELTA_N>(b1 & TRank3BB) & emptySquares;
|
emptySquares &= target; // Only blocking squares
|
||||||
|
enemyPieces &= target; // Capture only the checker piece
|
||||||
|
}
|
||||||
|
|
||||||
// Filter out unwanted pushes according to the move type
|
// Promotions and underpromotions
|
||||||
if (Type == EVASION)
|
if (pawnsOn7)
|
||||||
|
{
|
||||||
|
if (Type == CAPTURE)
|
||||||
|
emptySquares = pos.empty_squares();
|
||||||
|
|
||||||
|
pawns &= ~TRank7BB;
|
||||||
|
mlist = generate_promotions<Us, Type, TDELTA_NE>(pos, mlist, pawnsOn7, enemyPieces);
|
||||||
|
mlist = generate_promotions<Us, Type, TDELTA_NW>(pos, mlist, pawnsOn7, enemyPieces);
|
||||||
|
mlist = generate_promotions<Us, Type, TDELTA_N >(pos, mlist, pawnsOn7, emptySquares);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Standard captures
|
||||||
|
if (Type == CAPTURE || Type == EVASION)
|
||||||
|
{
|
||||||
|
mlist = generate_pawn_captures<Type, TDELTA_NE>(mlist, pawns, enemyPieces);
|
||||||
|
mlist = generate_pawn_captures<Type, TDELTA_NW>(mlist, pawns, enemyPieces);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Single and double pawn pushes
|
||||||
|
if (Type != CAPTURE)
|
||||||
|
{
|
||||||
|
b1 = pawnPushes & emptySquares;
|
||||||
|
b2 = move_pawns<TDELTA_N>(pawnPushes & TRank3BB) & emptySquares;
|
||||||
|
|
||||||
|
if (Type == CHECK)
|
||||||
{
|
{
|
||||||
b1 &= target;
|
// Condider only pawn moves which give direct checks
|
||||||
b2 &= target;
|
|
||||||
}
|
|
||||||
else if (Type == CHECK)
|
|
||||||
{
|
|
||||||
// Pawn moves which give direct cheks
|
|
||||||
b1 &= pos.attacks_from<PAWN>(ksq, Them);
|
b1 &= pos.attacks_from<PAWN>(ksq, Them);
|
||||||
b2 &= pos.attacks_from<PAWN>(ksq, Them);
|
b2 &= pos.attacks_from<PAWN>(ksq, Them);
|
||||||
|
|
||||||
// Pawn moves which gives discovered check. This is possible only if
|
// Add pawn moves which gives discovered check. This is possible only
|
||||||
// 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.
|
// don't generate captures.
|
||||||
if (pawns & target) // For CHECK type target is dc bitboard
|
if (pawns & target) // For CHECK type target is dc bitboard
|
||||||
{
|
{
|
||||||
Bitboard dc1 = move_pawns<TDELTA_N>(pawns & target & ~file_bb(ksq)) & emptySquares & ~TRank8BB;
|
dc1 = move_pawns<TDELTA_N>(pawns & target & ~file_bb(ksq)) & emptySquares;
|
||||||
Bitboard dc2 = move_pawns<TDELTA_N>(dc1 & TRank3BB) & emptySquares;
|
dc2 = move_pawns<TDELTA_N>(dc1 & TRank3BB) & emptySquares;
|
||||||
|
|
||||||
b1 |= dc1;
|
b1 |= dc1;
|
||||||
b2 |= dc2;
|
b2 |= dc2;
|
||||||
|
|
Loading…
Add table
Reference in a new issue