generateMoves method
Implementation
List<Move> generateMoves([Map? options]) {
addMove(List<Piece?> board, List<Move> moves, from, to, flags) {
/* if pawn promotion */
if (board[from]!.type == PAWN &&
(rank(to) == RANK_8 || rank(to) == RANK_1)) {
List pieces = [QUEEN, ROOK, BISHOP, KNIGHT];
for (var i = 0, len = pieces.length; i < len; i++) {
moves.add(buildMove(board, from, to, flags, pieces[i]));
}
} else {
moves.add(buildMove(board, from, to, flags));
}
}
List<Move> moves = [];
Color us = turn;
Color them = swapColor(us);
ColorMap<int> secondRank = ColorMap(0);
secondRank[BLACK] = RANK_7;
secondRank[WHITE] = RANK_2;
var firstSq = SQUARES_A8;
var lastSq = SQUARES_H1;
bool singleSquare = false;
/* do we want legal moves? */
var legal = (options != null && options.containsKey('legal'))
? options['legal']
: true;
/* are we generating moves for a single square? */
if (options != null && options.containsKey('square')) {
if (SQUARES.containsKey(options['square'])) {
firstSq = lastSq = SQUARES[options['square']];
singleSquare = true;
} else {
/* invalid square */
return [];
}
}
for (int i = firstSq; i <= lastSq; i++) {
/* did we run off the end of the board */
if ((i & 0x88) != 0) {
i += 7;
continue;
}
Piece? piece = board[i];
if (piece == null || piece.color != us) {
continue;
}
if (piece.type == PAWN) {
/* single square, non-capturing */
int square = i + PAWN_OFFSETS[us]![0];
if (board[square] == null) {
addMove(board, moves, i, square, BITS_NORMAL);
/* double square */
int square2 = i + PAWN_OFFSETS[us]![1];
if (secondRank[us] == rank(i) && board[square2] == null) {
addMove(board, moves, i, square2, BITS_BIG_PAWN);
}
}
/* pawn captures */
for (int j = 2; j < 4; j++) {
int square = i + PAWN_OFFSETS[us]![j];
if ((square & 0x88) != 0) continue;
if (board[square] != null) {
if (board[square]!.color == them) {
addMove(board, moves, i, square, BITS_CAPTURE);
} else if (square == epSquare) {
addMove(board, moves, i, epSquare, BITS_EP_CAPTURE);
}
} else if (square == epSquare) {
addMove(board, moves, i, epSquare, BITS_EP_CAPTURE);
}
}
} else {
for (int j = 0, len = PIECE_OFFSETS[piece.type]!.length; j < len; j++) {
int offset = PIECE_OFFSETS[piece.type]![j];
int square = i;
while (true) {
square += offset;
if ((square & 0x88) != 0) break;
if (board[square] == null) {
addMove(board, moves, i, square, BITS_NORMAL);
} else {
if (board[square]!.color == us) {
break;
}
addMove(board, moves, i, square, BITS_CAPTURE);
break;
}
/* break, if knight or king */
if (piece.type == KNIGHT || piece.type == KING) break;
}
}
}
}
// check for castling if: a) we're generating all moves, or b) we're doing
// single square move generation on the king's square
if ((!singleSquare) || lastSq == kings[us]) {
/* king-side castling */
if ((castling[us] & BITS_KSIDE_CASTLE) != 0) {
var castlingFrom = kings[us];
var castlingTo = castlingFrom + 2;
if (board[castlingFrom + 1] == null &&
board[castlingTo] == null &&
!attacked(them, kings[us]) &&
!attacked(them, castlingFrom + 1) &&
!attacked(them, castlingTo)) {
addMove(board, moves, kings[us], castlingTo, BITS_KSIDE_CASTLE);
}
}
/* queen-side castling */
if ((castling[us] & BITS_QSIDE_CASTLE) != 0) {
var castlingFrom = kings[us];
var castlingTo = castlingFrom - 2;
if (board[castlingFrom - 1] == null &&
board[castlingFrom - 2] == null &&
board[castlingFrom - 3] == null &&
!attacked(them, kings[us]) &&
!attacked(them, castlingFrom - 1) &&
!attacked(them, castlingTo)) {
addMove(board, moves, kings[us], castlingTo, BITS_QSIDE_CASTLE);
}
}
}
/* return all pseudo-legal moves (this includes moves that allow the king
* to be captured)
*/
if (!legal) {
return moves;
}
/* filter out illegal moves */
List<Move> legalMoves = [];
for (int i = 0, len = moves.length; i < len; i++) {
makeMove(moves[i]);
if (!kingAttacked(us)) {
legalMoves.add(moves[i]);
}
undoMove();
}
return legalMoves;
}