mirror of
https://github.com/sockspls/badfish
synced 2025-04-29 08:13:08 +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>
|
||||
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);
|
||||
|
||||
Bitboard b;
|
||||
Square to;
|
||||
|
||||
// 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 & ~TRank8BB;
|
||||
SERIALIZE_MOVES_D(b, -Delta);
|
||||
}
|
||||
b = move_pawns<Delta>(pawns) & target & ~TFileABB;
|
||||
SERIALIZE_MOVES_D(b, -Delta);
|
||||
return mlist;
|
||||
}
|
||||
|
||||
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 bool IsPush = (Delta == DELTA_N || Delta == DELTA_S);
|
||||
|
||||
Bitboard b;
|
||||
Square to;
|
||||
|
||||
// Promotions and under-promotions
|
||||
b = move_pawns<Delta>(pawns) & target & TRank8BB;
|
||||
// Promotions and under-promotions, both captures and non-captures
|
||||
b = move_pawns<Delta>(pawnsOn7) & target;
|
||||
|
||||
if (Delta != DELTA_N && Delta != DELTA_S)
|
||||
b &= ~TFileABB;
|
||||
|
@ -502,16 +494,12 @@ namespace {
|
|||
(*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
|
||||
// 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);
|
||||
else (void)pos; // Silence a warning under MSVC
|
||||
}
|
||||
return mlist;
|
||||
}
|
||||
|
@ -519,72 +507,72 @@ namespace {
|
|||
template<Color Us, MoveType Type>
|
||||
MoveStack* generate_pawn_moves(const Position& pos, MoveStack* mlist, Bitboard target, Square ksq) {
|
||||
|
||||
// Calculate our parametrized parameters at compile time
|
||||
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
||||
const Bitboard TRank8BB = (Us == WHITE ? Rank8BB : Rank1BB);
|
||||
const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
|
||||
const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
|
||||
// Calculate our parametrized parameters at compile time, named
|
||||
// according to the point of view of white side.
|
||||
const Color Them = (Us == WHITE ? BLACK : WHITE);
|
||||
const Bitboard TRank7BB = (Us == WHITE ? Rank7BB : Rank2BB);
|
||||
const Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB);
|
||||
const SquareDelta TDELTA_N = (Us == WHITE ? DELTA_N : DELTA_S);
|
||||
const SquareDelta TDELTA_NE = (Us == WHITE ? DELTA_NE : DELTA_SE);
|
||||
const SquareDelta TDELTA_NW = (Us == WHITE ? DELTA_NW : DELTA_SW);
|
||||
|
||||
Square to;
|
||||
Bitboard b1, b2, enemyPieces, emptySquares;
|
||||
Bitboard b1, b2, dc1, dc2, pawnPushes, emptySquares;
|
||||
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
|
||||
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
|
||||
// Pre-calculate pawn pushes before changing emptySquares definition
|
||||
if (Type != CAPTURE)
|
||||
{
|
||||
emptySquares = (Type == NON_CAPTURE ? target : pos.empty_squares());
|
||||
pawnPushes = move_pawns<TDELTA_N>(pawns & ~TRank7BB) & emptySquares;
|
||||
}
|
||||
|
||||
// Single and double pawn pushes
|
||||
b1 = move_pawns<TDELTA_N>(pawns) & emptySquares & ~TRank8BB;
|
||||
b2 = move_pawns<TDELTA_N>(b1 & TRank3BB) & emptySquares;
|
||||
if (Type == EVASION)
|
||||
{
|
||||
emptySquares &= target; // Only blocking squares
|
||||
enemyPieces &= target; // Capture only the checker piece
|
||||
}
|
||||
|
||||
// Filter out unwanted pushes according to the move type
|
||||
if (Type == EVASION)
|
||||
// Promotions and underpromotions
|
||||
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;
|
||||
b2 &= target;
|
||||
}
|
||||
else if (Type == CHECK)
|
||||
{
|
||||
// Pawn moves which give direct cheks
|
||||
// Condider only pawn moves which give direct checks
|
||||
b1 &= pos.attacks_from<PAWN>(ksq, Them);
|
||||
b2 &= pos.attacks_from<PAWN>(ksq, Them);
|
||||
|
||||
// Pawn moves which gives discovered check. This is possible only if
|
||||
// the pawn is not on the same file as the enemy king, because we
|
||||
// don't generate captures.
|
||||
// Add pawn moves which gives discovered check. This is possible only
|
||||
// if the pawn is not on the same file as the enemy king, because we
|
||||
// don't generate captures.
|
||||
if (pawns & target) // For CHECK type target is dc bitboard
|
||||
{
|
||||
Bitboard dc1 = move_pawns<TDELTA_N>(pawns & target & ~file_bb(ksq)) & emptySquares & ~TRank8BB;
|
||||
Bitboard dc2 = move_pawns<TDELTA_N>(dc1 & TRank3BB) & emptySquares;
|
||||
dc1 = move_pawns<TDELTA_N>(pawns & target & ~file_bb(ksq)) & emptySquares;
|
||||
dc2 = move_pawns<TDELTA_N>(dc1 & TRank3BB) & emptySquares;
|
||||
|
||||
b1 |= dc1;
|
||||
b2 |= dc2;
|
||||
|
|
Loading…
Add table
Reference in a new issue