// hardcoded list name 'mlist' and from square 'from'.
#define SERIALIZE_MOVES(b) while (b) (*mlist++).move = make_move(from, pop_1st_bit(&b))
+// Version used for pawns, where the 'from' square is given as a delta from the 'to' square
+#define SERIALIZE_MOVES_D(b, d) while (b) { to = pop_1st_bit(&b); (*mlist++).move = make_move(to + (d), to); }
+
////
//// Local definitions
////
/// generate_captures generates() all pseudo-legal captures and queen
/// promotions. The return value is the number of moves generated.
-int generate_captures(const Position& pos, MoveStack* mlist) {
+MoveStack* generate_captures(const Position& pos, MoveStack* mlist) {
assert(pos.is_ok());
assert(!pos.is_check());
Color us = pos.side_to_move();
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);
mlist = generate_piece_moves<PAWN, CAPTURE>(pos, mlist, us);
- mlist = generate_piece_moves<KING>(pos, mlist, us, target);
- return int(mlist - mlist_start);
+ return generate_piece_moves<KING>(pos, mlist, us, target);
}
/// generate_noncaptures() generates all pseudo-legal non-captures and
/// underpromotions. The return value is the number of moves generated.
-int generate_noncaptures(const Position& pos, MoveStack* mlist) {
+MoveStack* generate_noncaptures(const Position& pos, MoveStack* mlist) {
assert(pos.is_ok());
assert(!pos.is_check());
Color us = pos.side_to_move();
Bitboard target = pos.empty_squares();
- MoveStack* mlist_start = mlist;
mlist = generate_piece_moves<PAWN, NON_CAPTURE>(pos, mlist, us);
mlist = generate_piece_moves<KNIGHT>(pos, mlist, us, target);
mlist = generate_piece_moves<QUEEN>(pos, mlist, us, target);
mlist = generate_piece_moves<KING>(pos, mlist, us, target);
mlist = generate_castle_moves<KING_SIDE>(pos, mlist);
- mlist = generate_castle_moves<QUEEN_SIDE>(pos, mlist);
- return int(mlist - mlist_start);
+ return generate_castle_moves<QUEEN_SIDE>(pos, mlist);
}
/// generate_non_capture_checks() generates all pseudo-legal non-capturing,
/// non-promoting checks. It returns the number of generated moves.
-int generate_non_capture_checks(const Position& pos, MoveStack* mlist, Bitboard dc) {
+MoveStack* generate_non_capture_checks(const Position& pos, MoveStack* mlist, Bitboard dc) {
assert(pos.is_ok());
assert(!pos.is_check());
Color us = pos.side_to_move();
Square ksq = pos.king_square(opposite_color(us));
- MoveStack* mlist_start = mlist;
assert(pos.piece_on(ksq) == piece_of_color_and_type(opposite_color(us), KING));
&& castling_is_check(pos, KING_SIDE))
mlist = generate_castle_moves<KING_SIDE>(pos, mlist);
- return int(mlist - mlist_start);
+ return mlist;
}
/// in check. Unlike the other move generation functions, this one generates
/// only legal moves. It returns the number of generated moves.
-int generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned) {
+MoveStack* generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned) {
assert(pos.is_ok());
assert(pos.is_check());
Color us = pos.side_to_move();
Color them = opposite_color(us);
Square ksq = pos.king_square(us);
- MoveStack* mlist_start = mlist;
assert(pos.piece_on(ksq) == piece_of_color_and_type(us, KING));
}
}
}
- return int(mlist - mlist_start);
+ return mlist;
}
/// very hard to write an efficient legal move generator, but for the moment
/// we don't need it.
-int generate_legal_moves(const Position& pos, MoveStack* mlist) {
+MoveStack* generate_legal_moves(const Position& pos, MoveStack* mlist) {
assert(pos.is_ok());
return generate_evasions(pos, mlist, pinned);
// Generate pseudo-legal moves
- int n = generate_captures(pos, mlist);
- n += generate_noncaptures(pos, mlist + n);
+ MoveStack* last = generate_captures(pos, mlist);
+ last = generate_noncaptures(pos, last);
// Remove illegal moves from the list
- for (int i = 0; i < n; i++)
- if (!pos.pl_move_is_legal(mlist[i].move, pinned))
- mlist[i--].move = mlist[--n].move;
-
- return n;
+ for (MoveStack* cur = mlist; cur != last; cur++)
+ if (!pos.pl_move_is_legal(cur->move, pinned))
+ {
+ cur->move = (--last)->move;
+ cur--;
+ }
+ return last;
}
}
+/// Another version of move_is_legal(), which takes only a position and a move
+/// as input. This function does not require that the side to move is not in
+/// check. It is not optimized for speed, and is only used for verifying move
+/// legality when building a PV from the transposition table.
+
+bool move_is_legal(const Position& pos, const Move m) {
+
+ Bitboard pinned = pos.pinned_pieces(pos.side_to_move());
+ if (!pos.is_check())
+ return move_is_legal(pos, m, pinned);
+ else
+ {
+ Position p(pos);
+ MoveStack mlist[64];
+ MoveStack* last = generate_evasions(p, mlist, pinned);
+ for (MoveStack* cur = mlist; cur != last; cur++)
+ if (cur->move == m)
+ return true;
+
+ return false;
+ }
+}
+
+
namespace {
template<PieceType Piece>
}
// Capturing non-promotions
- while (b1)
- {
- to = pop_1st_bit(&b1);
- (*mlist++).move = make_move(to - TTDELTA_NE, to);
- }
+ SERIALIZE_MOVES_D(b1, -TTDELTA_NE);
return mlist;
}
// Single pawn pushes
b2 = b1 = move_pawns<Us, DELTA_N>(pawns) & emptySquares & ~TRank8BB;
- while (b2)
- {
- to = pop_1st_bit(&b2);
- (*mlist++).move = make_move(to - TDELTA_N, to);
- }
+ SERIALIZE_MOVES_D(b2, -TDELTA_N);
// Double pawn pushes
b2 = move_pawns<Us, DELTA_N>(b1 & TRank3BB) & emptySquares;
- while (b2)
- {
- to = pop_1st_bit(&b2);
- (*mlist++).move = make_move(to - TDELTA_N - TDELTA_N, to);
- }
+ SERIALIZE_MOVES_D(b2, -TDELTA_N -TDELTA_N);
return mlist;
}
const SquareDelta TDELTA_N = (Us == WHITE ? DELTA_N : DELTA_S);
const SquareDelta TDELTA_S = (Us == WHITE ? DELTA_S : DELTA_N);
+ Square to;
Bitboard b1, b2, b3;
Bitboard pawns = pos.pawns(Us);
// Discovered checks, single pawn pushes, no promotions
b2 = b3 = move_pawns<Us, DELTA_N>(b1 & dc) & empty & ~TRank8BB;
- while (b3)
- {
- Square to = pop_1st_bit(&b3);
- (*mlist++).move = make_move(to - TDELTA_N, to);
- }
+ SERIALIZE_MOVES_D(b3, -TDELTA_N);
// Discovered checks, double pawn pushes
b3 = move_pawns<Us, DELTA_N>(b2 & TRank3BB) & empty;
- while (b3)
- {
- Square to = pop_1st_bit(&b3);
- (*mlist++).move = make_move(to - TDELTA_N - TDELTA_N, to);
- }
+ SERIALIZE_MOVES_D(b3, -TDELTA_N -TDELTA_N);
}
// Direct checks. These are possible only for pawns on neighboring files
Bitboard empty = pos.empty_squares();
b2 = move_pawns<Us, DELTA_N>(b1) & empty;
b3 = b2 & pos.pawn_attacks(Them, ksq);
- while (b3)
- {
- Square to = pop_1st_bit(&b3);
- (*mlist++).move = make_move(to - TDELTA_N, to);
- }
+ SERIALIZE_MOVES_D(b3, -TDELTA_N);
// Direct checks, double pawn pushes
b3 = move_pawns<Us, DELTA_N>(b2 & TRank3BB) & empty & pos.pawn_attacks(Them, ksq);
- while (b3)
- {
- Square to = pop_1st_bit(&b3);
- (*mlist++).move = make_move(to - TDELTA_N - TDELTA_N, to);
- }
+ SERIALIZE_MOVES_D(b3, -TDELTA_N -TDELTA_N);
return mlist;
}
MoveStack* generate_piece_checks(const Position& pos, MoveStack* mlist, Color us,
Bitboard dc, Square ksq) {
- Bitboard target = pos.pieces_of_color_and_type(us, Piece);
+ Bitboard target = pos.pieces_of_color(us) & pos.pieces_of_type(Piece);
// Discovered checks
Bitboard b = target & dc;