1
0
Fork 0
mirror of https://github.com/sockspls/badfish synced 2025-04-29 16:23: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:
Marco Costalba 2010-11-16 09:42:12 +01:00
parent 6f70e762a9
commit d08a8d76f7

View file

@ -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;