#include "movegen.h"
+// Simple macro to wrap a very common while loop, no facny, no flexibility,
+// hardcoded list name 'mlist' and from square 'from'.
+#define SERIALIZE_MOVES(b) while (b) (*mlist++).move = make_move(from, pop_1st_bit(&b))
////
//// Local definitions
}
// Template generate_pawn_blocking_evasions() with specializations
- template<Color Us, Bitboard, Bitboard, SquareDelta>
+ template<Color Us, Rank, Bitboard, SquareDelta>
MoveStack* do_generate_pawn_blocking_evasions(const Position& pos, Bitboard not_pinned,
Bitboard blockSquares, MoveStack* mlist);
template<Color>
inline MoveStack* generate_pawn_blocking_evasions(const Position& p, Bitboard np, Bitboard bs, MoveStack* m) {
- return do_generate_pawn_blocking_evasions<WHITE, Rank8BB, Rank3BB, DELTA_N>(p, np, bs, m);
+ return do_generate_pawn_blocking_evasions<WHITE, RANK_8, Rank3BB, DELTA_N>(p, np, bs, m);
}
template<>
inline MoveStack* generate_pawn_blocking_evasions<BLACK>(const Position& p, Bitboard np, Bitboard bs, MoveStack* m) {
- return do_generate_pawn_blocking_evasions<BLACK, Rank1BB, Rank6BB, DELTA_S>(p, np, bs, m);
+ return do_generate_pawn_blocking_evasions<BLACK, RANK_1, Rank6BB, DELTA_S>(p, np, bs, m);
}
// Template generate_pawn_checks() with specializations
Bitboard target = pos.pieces_of_color(opposite_color(us));
MoveStack* mlist_start = mlist;
+ mlist = generate_piece_moves<QUEEN>(pos, mlist, us, target);
+ mlist = generate_piece_moves<ROOK>(pos, mlist, us, target);
+ mlist = generate_piece_moves<BISHOP>(pos, mlist, us, target);
+ mlist = generate_piece_moves<KNIGHT>(pos, mlist, us, target);
+
if (us == WHITE)
mlist = generate_pawn_captures<WHITE>(pos, mlist);
else
mlist = generate_pawn_captures<BLACK>(pos, mlist);
- mlist = generate_piece_moves<KNIGHT>(pos, mlist, us, target);
- mlist = generate_piece_moves<BISHOP>(pos, mlist, us, target);
- mlist = generate_piece_moves<ROOK>(pos, mlist, us, target);
- mlist = generate_piece_moves<QUEEN>(pos, mlist, us, target);
mlist = generate_piece_moves<KING>(pos, mlist, us, target);
return int(mlist - mlist_start);
}
// Pawn moves. Because a blocking evasion can never be a capture, we
// only generate pawn pushes.
if (us == WHITE)
- generate_pawn_blocking_evasions<WHITE>(pos, not_pinned, blockSquares, mlist);
+ mlist = generate_pawn_blocking_evasions<WHITE>(pos, not_pinned, blockSquares, mlist);
else
- generate_pawn_blocking_evasions<BLACK>(pos, not_pinned, blockSquares, mlist);
+ mlist = generate_pawn_blocking_evasions<BLACK>(pos, not_pinned, blockSquares, mlist);
// Pieces moves
b1 = pos.knights(us) & not_pinned;
if (b1)
- generate_piece_blocking_evasions<KNIGHT>(pos, b1, blockSquares, mlist);
+ mlist = generate_piece_blocking_evasions<KNIGHT>(pos, b1, blockSquares, mlist);
b1 = pos.bishops(us) & not_pinned;
if (b1)
- generate_piece_blocking_evasions<BISHOP>(pos, b1, blockSquares, mlist);
+ mlist = generate_piece_blocking_evasions<BISHOP>(pos, b1, blockSquares, mlist);
b1 = pos.rooks(us) & not_pinned;
if (b1)
- generate_piece_blocking_evasions<ROOK>(pos, b1, blockSquares, mlist);
+ mlist = generate_piece_blocking_evasions<ROOK>(pos, b1, blockSquares, mlist);
b1 = pos.queens(us) & not_pinned;
if (b1)
- generate_piece_blocking_evasions<QUEEN>(pos, b1, blockSquares, mlist);
+ mlist = generate_piece_blocking_evasions<QUEEN>(pos, b1, blockSquares, mlist);
}
// Finally, the ugly special case of en passant captures. An en passant
// Remove illegal moves from the list
for (int i = 0; i < n; i++)
- if (!pos.move_is_legal(mlist[i].move, pinned))
+ if (!pos.pl_move_is_legal(mlist[i].move, pinned))
mlist[i--].move = mlist[--n].move;
return n;
}
-/// generate_move_if_legal() takes a position and a (not necessarily
-/// pseudo-legal) move and a pinned pieces bitboard as input, and tests
-/// whether the move is legal. If the move is legal, the move itself is
-/// returned. If not, the function returns MOVE_NONE. This function must
+/// move_is_legal() takes a position and a (not necessarily pseudo-legal)
+/// move and a pinned pieces bitboard as input, and tests whether
+/// the move is legal. If the move is legal, the move itself is
+/// returned. If not, the function returns false. This function must
/// only be used when the side to move is not in check.
-Move generate_move_if_legal(const Position& pos, Move m, Bitboard pinned) {
+bool move_is_legal(const Position& pos, const Move m, Bitboard pinned) {
assert(pos.is_ok());
assert(!pos.is_check());
assert(move_is_ok(m));
+ assert(pinned == pos.pinned_pieces(pos.side_to_move()));
Color us = pos.side_to_move();
Color them = opposite_color(us);
// If the from square is not occupied by a piece belonging to the side to
// move, the move is obviously not legal.
if (color_of_piece(pc) != us)
- return MOVE_NONE;
+ return false;
Square to = move_to(m);
// en passant square.
if ( type_of_piece(pc) != PAWN
|| to != pos.ep_square())
- return MOVE_NONE;
+ return false;
assert(pos.square_is_empty(to));
assert(pos.piece_on(to - pawn_push(us)) == pawn_of_color(them));
- // The move is pseudo-legal. If it is legal, return it.
- return (pos.move_is_legal(m) ? m : MOVE_NONE);
+ // The move is pseudo-legal, check if it is also legal
+ return pos.pl_move_is_legal(m, pinned);
}
// Castling moves
// the right to castle kingside.
if ( type_of_piece(pc) != KING
||!pos.can_castle_kingside(us))
- return MOVE_NONE;
+ return false;
assert(from == pos.king_square(us));
assert(to == pos.initial_kr_square(us));
if (s != from && s != to && !pos.square_is_empty(s))
illegal = true;
- return (!illegal ? m : MOVE_NONE);
+ return !illegal;
}
if (move_is_long_castle(m))
// the right to castle kingside.
if ( type_of_piece(pc) != KING
||!pos.can_castle_queenside(us))
- return MOVE_NONE;
+ return false;
assert(from == pos.king_square(us));
assert(to == pos.initial_qr_square(us));
|| pos.piece_on(to + DELTA_W) == queen_of_color(them)))
illegal = true;
- return (!illegal ? m : MOVE_NONE);
+ return !illegal;
}
// Normal moves
// The destination square cannot be occupied by a friendly piece
if (pos.color_of_piece_on(to) == us)
- return MOVE_NONE;
+ return false;
// Proceed according to the type of the moving piece.
if (type_of_piece(pc) == PAWN)
if ( ( (square_rank(to) == RANK_8 && us == WHITE)
||(square_rank(to) == RANK_1 && us != WHITE))
&& !move_promotion(m))
- return MOVE_NONE;
+ return false;
// Proceed according to the square delta between the source and
// destionation squares.
// Capture. The destination square must be occupied by an enemy
// piece (en passant captures was handled earlier).
if (pos.color_of_piece_on(to) != them)
- return MOVE_NONE;
+ return false;
break;
case DELTA_N:
case DELTA_S:
// Pawn push. The destination square must be empty.
if (!pos.square_is_empty(to))
- return MOVE_NONE;
+ return false;
break;
case DELTA_NN:
if ( square_rank(to) != RANK_4
|| !pos.square_is_empty(to)
|| !pos.square_is_empty(from + DELTA_N))
- return MOVE_NONE;
+ return false;
break;
case DELTA_SS:
if ( square_rank(to) != RANK_5
|| !pos.square_is_empty(to)
|| !pos.square_is_empty(from + DELTA_S))
- return MOVE_NONE;
+ return false;
break;
default:
- return MOVE_NONE;
+ return false;
}
- // The move is pseudo-legal. Return it if it is legal.
- return (pos.move_is_legal(m) ? m : MOVE_NONE);
+ // The move is pseudo-legal, check if it is also legal
+ return pos.pl_move_is_legal(m, pinned);
}
// Luckly we can handle all the other pieces in one go
return ( pos.piece_attacks_square(from, to)
- && pos.move_is_legal(m)
- && !move_promotion(m) ? m : MOVE_NONE);
+ && pos.pl_move_is_legal(m, pinned)
+ && !move_promotion(m));
}
template<PieceType Piece>
MoveStack* generate_piece_moves(const Position& pos, MoveStack* mlist, Color us, Bitboard target) {
- Square from, to;
+ Square from;
Bitboard b;
- for (int i = 0; i < pos.piece_count(us, Piece); i++)
+ for (int i = 0, e = pos.piece_count(us, Piece); i < e; i++)
{
from = pos.piece_list(us, Piece, i);
b = pos.piece_attacks<Piece>(from) & target;
- while (b)
- {
- to = pop_1st_bit(&b);
- (*mlist++).move = make_move(from, to);
- }
+ SERIALIZE_MOVES(b);
}
return mlist;
}
MoveStack* generate_piece_moves<KING>(const Position& pos, MoveStack* mlist, Color us, Bitboard target) {
Bitboard b;
- Square to, from = pos.king_square(us);
+ Square from = pos.king_square(us);
b = pos.piece_attacks<KING>(from) & target;
- while (b)
- {
- to = pop_1st_bit(&b);
- (*mlist++).move = make_move(from, to);
- }
+ SERIALIZE_MOVES(b);
return mlist;
}
{
Square from = pop_1st_bit(&b);
Bitboard bb = pos.piece_attacks<Piece>(from) & blockSquares;
- while (bb)
- {
- Square to = pop_1st_bit(&bb);
- (*mlist++).move = make_move(from, to);
- }
+ SERIALIZE_MOVES(bb);
}
return mlist;
}
template<Color Us, Color Them, Bitboard TRank8BB, SquareDelta TDELTA_NE,
SquareDelta TDELTA_NW, SquareDelta TDELTA_N
>
- MoveStack* do_generate_pawn_captures(const Position& pos, MoveStack* mlist) {
+ MoveStack* do_generate_pawn_captures(const Position& pos, MoveStack* mlist) {
- Square sq;
+ Square to;
Bitboard pawns = pos.pawns(Us);
Bitboard enemyPieces = pos.pieces_of_color(Them);
Bitboard b2 = b1 & TRank8BB;
while (b2)
{
- sq = pop_1st_bit(&b2);
- (*mlist++).move = make_promotion_move(sq - TDELTA_NE, sq, QUEEN);
+ to = pop_1st_bit(&b2);
+ (*mlist++).move = make_promotion_move(to - TDELTA_NE, to, QUEEN);
}
// Capturing non-promotions
b2 = b1 & ~TRank8BB;
while (b2)
{
- sq = pop_1st_bit(&b2);
- (*mlist++).move = make_move(sq - TDELTA_NE, sq);
+ to = pop_1st_bit(&b2);
+ (*mlist++).move = make_move(to - TDELTA_NE, to);
}
// Captures in the h1-a8 (h8-a1 for black) direction
b2 = b1 & TRank8BB;
while (b2)
{
- sq = pop_1st_bit(&b2);
- (*mlist++).move = make_promotion_move(sq - TDELTA_NW, sq, QUEEN);
+ to = pop_1st_bit(&b2);
+ (*mlist++).move = make_promotion_move(to - TDELTA_NW, to, QUEEN);
}
// Capturing non-promotions
b2 = b1 & ~TRank8BB;
while (b2)
{
- sq = pop_1st_bit(&b2);
- (*mlist++).move = make_move(sq - TDELTA_NW, sq);
+ to = pop_1st_bit(&b2);
+ (*mlist++).move = make_move(to - TDELTA_NW, to);
}
// Non-capturing promotions
b1 = (Us == WHITE ? pawns << 8 : pawns >> 8) & pos.empty_squares() & TRank8BB;
while (b1)
{
- sq = pop_1st_bit(&b1);
- (*mlist++).move = make_promotion_move(sq - TDELTA_N, sq, QUEEN);
+ to = pop_1st_bit(&b1);
+ (*mlist++).move = make_promotion_move(to - TDELTA_N, to, QUEEN);
}
// En passant captures
while (b1)
{
- sq = pop_1st_bit(&b1);
- (*mlist++).move = make_ep_move(sq, pos.ep_square());
+ to = pop_1st_bit(&b1);
+ (*mlist++).move = make_ep_move(to, pos.ep_square());
}
}
return mlist;
template<Color Us, Color Them, Bitboard TRank8BB, Bitboard TRank3BB,
SquareDelta TDELTA_NE, SquareDelta TDELTA_NW, SquareDelta TDELTA_N
>
- MoveStack* do_generate_pawn_noncaptures(const Position& pos, MoveStack* mlist) {
+ MoveStack* do_generate_pawn_noncaptures(const Position& pos, MoveStack* mlist) {
Bitboard pawns = pos.pawns(Us);
Bitboard enemyPieces = pos.pieces_of_color(Them);
Bitboard emptySquares = pos.empty_squares();
Bitboard b1, b2;
- Square sq;
+ Square to;
// Underpromotion captures in the a1-h8 (a8-h1 for black) direction
b1 = (Us == WHITE ? pawns << 9 : pawns >> 7) & ~FileABB & enemyPieces & TRank8BB;
while (b1)
{
- sq = pop_1st_bit(&b1);
- (*mlist++).move = make_promotion_move(sq - TDELTA_NE, sq, ROOK);
- (*mlist++).move = make_promotion_move(sq - TDELTA_NE, sq, BISHOP);
- (*mlist++).move = make_promotion_move(sq - TDELTA_NE, sq, KNIGHT);
+ to = pop_1st_bit(&b1);
+ (*mlist++).move = make_promotion_move(to - TDELTA_NE, to, ROOK);
+ (*mlist++).move = make_promotion_move(to - TDELTA_NE, to, BISHOP);
+ (*mlist++).move = make_promotion_move(to - TDELTA_NE, to, KNIGHT);
}
// Underpromotion captures in the h1-a8 (h8-a1 for black) direction
b1 = (Us == WHITE ? pawns << 7 : pawns >> 9) & ~FileHBB & enemyPieces & TRank8BB;
while (b1)
{
- sq = pop_1st_bit(&b1);
- (*mlist++).move = make_promotion_move(sq - TDELTA_NW, sq, ROOK);
- (*mlist++).move = make_promotion_move(sq - TDELTA_NW, sq, BISHOP);
- (*mlist++).move = make_promotion_move(sq - TDELTA_NW, sq, KNIGHT);
+ to = pop_1st_bit(&b1);
+ (*mlist++).move = make_promotion_move(to - TDELTA_NW, to, ROOK);
+ (*mlist++).move = make_promotion_move(to - TDELTA_NW, to, BISHOP);
+ (*mlist++).move = make_promotion_move(to - TDELTA_NW, to, KNIGHT);
}
// Single pawn pushes
b2 = b1 & TRank8BB;
while (b2)
{
- sq = pop_1st_bit(&b2);
- (*mlist++).move = make_promotion_move(sq - TDELTA_N, sq, ROOK);
- (*mlist++).move = make_promotion_move(sq - TDELTA_N, sq, BISHOP);
- (*mlist++).move = make_promotion_move(sq - TDELTA_N, sq, KNIGHT);
+ to = pop_1st_bit(&b2);
+ (*mlist++).move = make_promotion_move(to - TDELTA_N, to, ROOK);
+ (*mlist++).move = make_promotion_move(to - TDELTA_N, to, BISHOP);
+ (*mlist++).move = make_promotion_move(to - TDELTA_N, to, KNIGHT);
}
b2 = b1 & ~TRank8BB;
while (b2)
{
- sq = pop_1st_bit(&b2);
- (*mlist++).move = make_move(sq - TDELTA_N, sq);
+ to = pop_1st_bit(&b2);
+ (*mlist++).move = make_move(to - TDELTA_N, to);
}
// Double pawn pushes
b2 = (Us == WHITE ? (b1 & TRank3BB) << 8 : (b1 & TRank3BB) >> 8) & emptySquares;
while (b2)
{
- sq = pop_1st_bit(&b2);
- (*mlist++).move = make_move(sq - TDELTA_N - TDELTA_N, sq);
+ to = pop_1st_bit(&b2);
+ (*mlist++).move = make_move(to - TDELTA_N - TDELTA_N, to);
}
return mlist;
}
{
Square from = pop_1st_bit(&b);
Bitboard bb = pos.piece_attacks<Piece>(from) & pos.empty_squares();
- while (bb)
- {
- Square to = pop_1st_bit(&bb);
- (*mlist++).move = make_move(from, to);
- }
+ SERIALIZE_MOVES(bb);
}
// Direct checks
b = target & ~dc;
{
Square from = pop_1st_bit(&b);
Bitboard bb = pos.piece_attacks<Piece>(from) & checkSqs;
- while (bb)
- {
- Square to = pop_1st_bit(&bb);
- (*mlist++).move = make_move(from, to);
- }
+ SERIALIZE_MOVES(bb);
}
return mlist;
}
Bitboard b = pos.piece_attacks<KING>(from)
& pos.empty_squares()
& ~QueenPseudoAttacks[ksq];
- while (b)
- {
- Square to = pop_1st_bit(&b);
- (*mlist++).move = make_move(from, to);
- }
+ SERIALIZE_MOVES(b);
}
return mlist;
}
- template<Color Us, Bitboard TRANK_8, Bitboard TRank3BB, SquareDelta TDELTA_N>
+ template<Color Us, Rank TRANK_8, Bitboard TRank3BB, SquareDelta TDELTA_N>
MoveStack* do_generate_pawn_blocking_evasions(const Position& pos, Bitboard not_pinned,
Bitboard blockSquares, MoveStack* mlist) {
+ Square to;
+
// Find non-pinned pawns
Bitboard b1 = pos.pawns(Us) & not_pinned;
Bitboard b2 = (Us == WHITE ? b1 << 8 : b1 >> 8) & blockSquares;
while (b2)
{
- Square to = pop_1st_bit(&b2);
+ to = pop_1st_bit(&b2);
assert(pos.piece_on(to) == EMPTY);
b2 = (Us == WHITE ? b2 << 8 : b2 >> 8) & blockSquares;;
while (b2)
{
- Square to = pop_1st_bit(&b2);
+ to = pop_1st_bit(&b2);
assert(pos.piece_on(to) == EMPTY);
assert(Us != WHITE || square_rank(to) == RANK_4);