/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
- Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
+ Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "movegen.h"
+
#include <cassert>
+#include <initializer_list>
-#include "movegen.h"
+#include "bitboard.h"
#include "position.h"
namespace Stockfish {
namespace {
- template<GenType Type, Direction D>
- ExtMove* make_promotions(ExtMove* moveList, Square to) {
+ template<GenType Type, Direction D, bool Enemy>
+ ExtMove* make_promotions(ExtMove* moveList, [[maybe_unused]] Square to) {
- if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
+ if constexpr (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
+ {
*moveList++ = make<PROMOTION>(to - D, to, QUEEN);
+ if constexpr (Enemy && Type == CAPTURES)
+ {
+ *moveList++ = make<PROMOTION>(to - D, to, ROOK);
+ *moveList++ = make<PROMOTION>(to - D, to, BISHOP);
+ *moveList++ = make<PROMOTION>(to - D, to, KNIGHT);
+ }
+ }
- if (Type == QUIETS || Type == EVASIONS || Type == NON_EVASIONS)
+ if constexpr ((Type == QUIETS && !Enemy) || Type == EVASIONS || Type == NON_EVASIONS)
{
*moveList++ = make<PROMOTION>(to - D, to, ROOK);
*moveList++ = make<PROMOTION>(to - D, to, BISHOP);
Bitboard pawnsNotOn7 = pos.pieces(Us, PAWN) & ~TRank7BB;
// Single and double pawn pushes, no promotions
- if (Type != CAPTURES)
+ if constexpr (Type != CAPTURES)
{
Bitboard b1 = shift<Up>(pawnsNotOn7) & emptySquares;
Bitboard b2 = shift<Up>(b1 & TRank3BB) & emptySquares;
- if (Type == EVASIONS) // Consider only blocking squares
+ if constexpr (Type == EVASIONS) // Consider only blocking squares
{
b1 &= target;
b2 &= target;
}
- if (Type == QUIET_CHECKS)
+ if constexpr (Type == QUIET_CHECKS)
{
// To make a quiet check, you either make a direct check by pushing a pawn
// or push a blocker pawn that is not on the same file as the enemy king.
Bitboard b2 = shift<UpLeft >(pawnsOn7) & enemies;
Bitboard b3 = shift<Up >(pawnsOn7) & emptySquares;
- if (Type == EVASIONS)
+ if constexpr (Type == EVASIONS)
b3 &= target;
while (b1)
- moveList = make_promotions<Type, UpRight>(moveList, pop_lsb(b1));
+ moveList = make_promotions<Type, UpRight, true>(moveList, pop_lsb(b1));
while (b2)
- moveList = make_promotions<Type, UpLeft >(moveList, pop_lsb(b2));
+ moveList = make_promotions<Type, UpLeft, true>(moveList, pop_lsb(b2));
while (b3)
- moveList = make_promotions<Type, Up >(moveList, pop_lsb(b3));
+ moveList = make_promotions<Type, Up, false>(moveList, pop_lsb(b3));
}
// Standard and en passant captures
- if (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
+ if constexpr (Type == CAPTURES || Type == EVASIONS || Type == NON_EVASIONS)
{
Bitboard b1 = shift<UpRight>(pawnsNotOn7) & enemies;
Bitboard b2 = shift<UpLeft >(pawnsNotOn7) & enemies;
/// <CAPTURES> Generates all pseudo-legal captures plus queen promotions
/// <QUIETS> Generates all pseudo-legal non-captures and underpromotions
-/// <EVASIONS> Generates all pseudo-legal check evasions when the side to move is in check
-/// <QUIET_CHECKS> Generates all pseudo-legal non-captures giving check, except castling and promotions
+/// <EVASIONS> Generates all pseudo-legal check evasions
/// <NON_EVASIONS> Generates all pseudo-legal captures and non-captures
+/// <QUIET_CHECKS> Generates all pseudo-legal non-captures giving check,
+/// except castling and promotions
///
/// Returns a pointer to the end of the move list.
ExtMove* generate(const Position& pos, ExtMove* moveList) {
static_assert(Type != LEGAL, "Unsupported type in generate()");
- assert((Type == EVASIONS) == (bool)pos.checkers());
+ assert((Type == EVASIONS) == bool(pos.checkers()));
Color us = pos.side_to_move();
moveList = pos.checkers() ? generate<EVASIONS >(pos, moveList)
: generate<NON_EVASIONS>(pos, moveList);
while (cur != moveList)
- if ( ((pinned && pinned & from_sq(*cur)) || from_sq(*cur) == ksq || type_of(*cur) == EN_PASSANT)
+ if ( ((pinned & from_sq(*cur)) || from_sq(*cur) == ksq || type_of(*cur) == EN_PASSANT)
&& !pos.legal(*cur))
*cur = (--moveList)->move;
else