/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- gen_legal_moves
- gen_moves
- gen_captures
- gen_quiet_moves
- add_moves
- add_captures
- add_quiet_moves
- add_promotes
- add_en_passant_captures
- add_castle_moves
- add_pawn_move
- add_promote
// move_gen.cpp
// includes
#include "attack.h"
#include "board.h"
#include "colour.h"
#include "list.h"
#include "move.h"
#include "move_evasion.h"
#include "move_gen.h"
#include "move_legal.h"
#include "piece.h"
#include "util.h"
// prototypes
static void add_moves (list_t * list, const board_t * board);
static void add_captures (list_t * list, const board_t * board);
static void add_quiet_moves (list_t * list, const board_t * board);
static void add_promotes (list_t * list, const board_t * board);
static void add_en_passant_captures (list_t * list, const board_t * board);
static void add_castle_moves (list_t * list, const board_t * board);
// functions
// gen_legal_moves()
void gen_legal_moves(list_t * list, board_t * board) {
attack_t attack[1];
ASSERT(list!=NULL);
ASSERT(board!=NULL);
attack_set(attack,board);
if (ATTACK_IN_CHECK(attack)) {
gen_legal_evasions(list,board,attack);
} else {
gen_moves(list,board);
list_filter(list,board,&pseudo_is_legal,true);
}
// debug
ASSERT(list_is_ok(list));
}
// gen_moves()
void gen_moves(list_t * list, const board_t * board) {
ASSERT(list!=NULL);
ASSERT(board!=NULL);
ASSERT(!board_is_check(board));
LIST_CLEAR(list);
add_moves(list,board);
add_en_passant_captures(list,board);
add_castle_moves(list,board);
// debug
ASSERT(list_is_ok(list));
}
// gen_captures()
void gen_captures(list_t * list, const board_t * board) {
ASSERT(list!=NULL);
ASSERT(board!=NULL);
LIST_CLEAR(list);
add_captures(list,board);
add_en_passant_captures(list,board);
// debug
ASSERT(list_is_ok(list));
}
// gen_quiet_moves()
void gen_quiet_moves(list_t * list, const board_t * board) {
ASSERT(list!=NULL);
ASSERT(board!=NULL);
ASSERT(!board_is_check(board));
LIST_CLEAR(list);
add_quiet_moves(list,board);
add_castle_moves(list,board);
// debug
ASSERT(list_is_ok(list));
}
// add_moves()
static void add_moves(list_t * list, const board_t * board) {
int me, opp;
int opp_flag;
const sq_t * ptr;
int from, to;
int piece, capture;
const inc_t * inc_ptr;
int inc;
ASSERT(list!=NULL);
ASSERT(board!=NULL);
me = board->turn;
opp = COLOUR_OPP(me);
opp_flag = COLOUR_FLAG(opp);
// piece moves
for (ptr = &board->piece[me][0]; (from=*ptr) != SquareNone; ptr++) {
piece = board->square[from];
inc_ptr = PIECE_INC(piece);
if (PIECE_IS_SLIDER(piece)) {
for (; (inc=*inc_ptr) != IncNone; inc_ptr++) {
for (to = from+inc; (capture=board->square[to]) == Empty; to += inc) {
LIST_ADD(list,MOVE_MAKE(from,to));
}
if (FLAG_IS(capture,opp_flag)) {
LIST_ADD(list,MOVE_MAKE(from,to));
}
}
} else {
for (; (inc=*inc_ptr) != IncNone; inc_ptr++) {
to = from + inc;
capture = board->square[to];
if (capture == Empty || FLAG_IS(capture,opp_flag)) {
LIST_ADD(list,MOVE_MAKE(from,to));
}
}
}
}
// pawn moves
inc = PAWN_MOVE_INC(me);
for (ptr = &board->pawn[me][0]; (from=*ptr) != SquareNone; ptr++) {
to = from + (inc-1);
if (FLAG_IS(board->square[to],opp_flag)) {
add_pawn_move(list,from,to);
}
to = from + (inc+1);
if (FLAG_IS(board->square[to],opp_flag)) {
add_pawn_move(list,from,to);
}
to = from + inc;
if (board->square[to] == Empty) {
add_pawn_move(list,from,to);
if (PAWN_RANK(from,me) == Rank2) {
to = from + (2*inc);
if (board->square[to] == Empty) {
ASSERT(!SQUARE_IS_PROMOTE(to));
LIST_ADD(list,MOVE_MAKE(from,to));
}
}
}
}
}
// add_captures()
static void add_captures(list_t * list, const board_t * board) {
int me, opp;
int opp_flag;
const sq_t * ptr;
int from, to;
int piece, capture;
ASSERT(list!=NULL);
ASSERT(board!=NULL);
me = board->turn;
opp = COLOUR_OPP(me);
opp_flag = COLOUR_FLAG(opp);
// piece captures
for (ptr = &board->piece[me][0]; (from=*ptr) != SquareNone; ptr++) {
piece = board->square[from];
switch (PIECE_TYPE(piece)) {
case Knight64:
to = from - 33;
if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
to = from - 31;
if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
to = from - 18;
if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
to = from - 14;
if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
to = from + 14;
if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
to = from + 18;
if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
to = from + 31;
if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
to = from + 33;
if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
break;
case Bishop64:
for (to = from-17; (capture=board->square[to]) == Empty; to -= 17)
;
if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
for (to = from-15; (capture=board->square[to]) == Empty; to -= 15)
;
if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
for (to = from+15; (capture=board->square[to]) == Empty; to += 15)
;
if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
for (to = from+17; (capture=board->square[to]) == Empty; to += 17)
;
if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
break;
case Rook64:
for (to = from-16; (capture=board->square[to]) == Empty; to -= 16)
;
if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
for (to = from-1; (capture=board->square[to]) == Empty; to -= 1)
;
if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
for (to = from+1; (capture=board->square[to]) == Empty; to += 1)
;
if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
for (to = from+16; (capture=board->square[to]) == Empty; to += 16)
;
if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
break;
case Queen64:
for (to = from-17; (capture=board->square[to]) == Empty; to -= 17)
;
if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
for (to = from-16; (capture=board->square[to]) == Empty; to -= 16)
;
if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
for (to = from-15; (capture=board->square[to]) == Empty; to -= 15)
;
if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
for (to = from-1; (capture=board->square[to]) == Empty; to -= 1)
;
if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
for (to = from+1; (capture=board->square[to]) == Empty; to += 1)
;
if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
for (to = from+15; (capture=board->square[to]) == Empty; to += 15)
;
if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
for (to = from+16; (capture=board->square[to]) == Empty; to += 16)
;
if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
for (to = from+17; (capture=board->square[to]) == Empty; to += 17)
;
if (FLAG_IS(capture,opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
break;
case King64:
to = from - 17;
if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
to = from - 16;
if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
to = from - 15;
if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
to = from - 1;
if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
to = from + 1;
if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
to = from + 15;
if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
to = from + 16;
if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
to = from + 17;
if (FLAG_IS(board->square[to],opp_flag)) LIST_ADD(list,MOVE_MAKE(from,to));
break;
default:
ASSERT(false);
break;
}
}
// pawn captures
if (COLOUR_IS_WHITE(me)) {
for (ptr = &board->pawn[me][0]; (from=*ptr) != SquareNone; ptr++) {
to = from + 15;
if (FLAG_IS(board->square[to],opp_flag)) add_pawn_move(list,from,to);
to = from + 17;
if (FLAG_IS(board->square[to],opp_flag)) add_pawn_move(list,from,to);
// promote
if (SQUARE_RANK(from) == Rank7) {
to = from + 16;
if (board->square[to] == Empty) {
add_promote(list,MOVE_MAKE(from,to));
}
}
}
} else { // black
for (ptr = &board->pawn[me][0]; (from=*ptr) != SquareNone; ptr++) {
to = from - 17;
if (FLAG_IS(board->square[to],opp_flag)) add_pawn_move(list,from,to);
to = from - 15;
if (FLAG_IS(board->square[to],opp_flag)) add_pawn_move(list,from,to);
// promote
if (SQUARE_RANK(from) == Rank2) {
to = from - 16;
if (board->square[to] == Empty) {
add_promote(list,MOVE_MAKE(from,to));
}
}
}
}
}
// add_quiet_moves()
static void add_quiet_moves(list_t * list, const board_t * board) {
int me;
const sq_t * ptr;
int from, to;
int piece;
ASSERT(list!=NULL);
ASSERT(board!=NULL);
me = board->turn;
// piece moves
for (ptr = &board->piece[me][0]; (from=*ptr) != SquareNone; ptr++) {
piece = board->square[from];
switch (PIECE_TYPE(piece)) {
case Knight64:
to = from - 33;
if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to));
to = from - 31;
if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to));
to = from - 18;
if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to));
to = from - 14;
if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to));
to = from + 14;
if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to));
to = from + 18;
if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to));
to = from + 31;
if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to));
to = from + 33;
if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to));
break;
case Bishop64:
for (to = from-17; board->square[to] == Empty; to -= 17) {
LIST_ADD(list,MOVE_MAKE(from,to));
}
for (to = from-15; board->square[to] == Empty; to -= 15) {
LIST_ADD(list,MOVE_MAKE(from,to));
}
for (to = from+15; board->square[to] == Empty; to += 15) {
LIST_ADD(list,MOVE_MAKE(from,to));
}
for (to = from+17; board->square[to] == Empty; to += 17) {
LIST_ADD(list,MOVE_MAKE(from,to));
}
break;
case Rook64:
for (to = from-16; board->square[to] == Empty; to -= 16) {
LIST_ADD(list,MOVE_MAKE(from,to));
}
for (to = from-1; board->square[to] == Empty; to -= 1) {
LIST_ADD(list,MOVE_MAKE(from,to));
}
for (to = from+1; board->square[to] == Empty; to += 1) {
LIST_ADD(list,MOVE_MAKE(from,to));
}
for (to = from+16; board->square[to] == Empty; to += 16) {
LIST_ADD(list,MOVE_MAKE(from,to));
}
break;
case Queen64:
for (to = from-17; board->square[to] == Empty; to -= 17) {
LIST_ADD(list,MOVE_MAKE(from,to));
}
for (to = from-16; board->square[to] == Empty; to -= 16) {
LIST_ADD(list,MOVE_MAKE(from,to));
}
for (to = from-15; board->square[to] == Empty; to -= 15) {
LIST_ADD(list,MOVE_MAKE(from,to));
}
for (to = from-1; board->square[to] == Empty; to -= 1) {
LIST_ADD(list,MOVE_MAKE(from,to));
}
for (to = from+1; board->square[to] == Empty; to += 1) {
LIST_ADD(list,MOVE_MAKE(from,to));
}
for (to = from+15; board->square[to] == Empty; to += 15) {
LIST_ADD(list,MOVE_MAKE(from,to));
}
for (to = from+16; board->square[to] == Empty; to += 16) {
LIST_ADD(list,MOVE_MAKE(from,to));
}
for (to = from+17; board->square[to] == Empty; to += 17) {
LIST_ADD(list,MOVE_MAKE(from,to));
}
break;
case King64:
to = from - 17;
if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to));
to = from - 16;
if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to));
to = from - 15;
if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to));
to = from - 1;
if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to));
to = from + 1;
if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to));
to = from + 15;
if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to));
to = from + 16;
if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to));
to = from + 17;
if (board->square[to] == Empty) LIST_ADD(list,MOVE_MAKE(from,to));
break;
default:
ASSERT(false);
break;
}
}
// pawn moves
if (COLOUR_IS_WHITE(me)) {
for (ptr = &board->pawn[me][0]; (from=*ptr) != SquareNone; ptr++) {
// non promotes
if (SQUARE_RANK(from) != Rank7) {
to = from + 16;
if (board->square[to] == Empty) {
ASSERT(!SQUARE_IS_PROMOTE(to));
LIST_ADD(list,MOVE_MAKE(from,to));
if (SQUARE_RANK(from) == Rank2) {
to = from + 32;
if (board->square[to] == Empty) {
ASSERT(!SQUARE_IS_PROMOTE(to));
LIST_ADD(list,MOVE_MAKE(from,to));
}
}
}
}
}
} else { // black
for (ptr = &board->pawn[me][0]; (from=*ptr) != SquareNone; ptr++) {
// non promotes
if (SQUARE_RANK(from) != Rank2) {
to = from - 16;
if (board->square[to] == Empty) {
ASSERT(!SQUARE_IS_PROMOTE(to));
LIST_ADD(list,MOVE_MAKE(from,to));
if (SQUARE_RANK(from) == Rank7) {
to = from - 32;
if (board->square[to] == Empty) {
ASSERT(!SQUARE_IS_PROMOTE(to));
LIST_ADD(list,MOVE_MAKE(from,to));
}
}
}
}
}
}
}
// add_promotes()
static void add_promotes(list_t * list, const board_t * board) {
int me;
int inc;
const sq_t * ptr;
int from, to;
ASSERT(list!=NULL);
ASSERT(board!=NULL);
me = board->turn;
inc = PAWN_MOVE_INC(me);
for (ptr = &board->pawn[me][0]; (from=*ptr) != SquareNone; ptr++) {
if (PAWN_RANK(from,me) == Rank7) {
to = from + inc;
if (board->square[to] == Empty) {
add_promote(list,MOVE_MAKE(from,to));
}
}
}
}
// add_en_passant_captures()
static void add_en_passant_captures(list_t * list, const board_t * board) {
int from, to;
int me;
int inc;
int pawn;
ASSERT(list!=NULL);
ASSERT(board!=NULL);
to = board->ep_square;
if (to != SquareNone) {
me = board->turn;
inc = PAWN_MOVE_INC(me);
pawn = PAWN_MAKE(me);
from = to - (inc-1);
if (board->square[from] == pawn) {
ASSERT(!SQUARE_IS_PROMOTE(to));
LIST_ADD(list,MOVE_MAKE_FLAGS(from,to,MoveEnPassant));
}
from = to - (inc+1);
if (board->square[from] == pawn) {
ASSERT(!SQUARE_IS_PROMOTE(to));
LIST_ADD(list,MOVE_MAKE_FLAGS(from,to,MoveEnPassant));
}
}
}
// add_castle_moves()
static void add_castle_moves(list_t * list, const board_t * board) {
ASSERT(list!=NULL);
ASSERT(board!=NULL);
ASSERT(!board_is_check(board));
if (COLOUR_IS_WHITE(board->turn)) {
if ((board->flags & FlagsWhiteKingCastle) != 0
&& board->square[F1] == Empty
&& board->square[G1] == Empty
&& !is_attacked(board,F1,Black)) {
LIST_ADD(list,MOVE_MAKE_FLAGS(E1,G1,MoveCastle));
}
if ((board->flags & FlagsWhiteQueenCastle) != 0
&& board->square[D1] == Empty
&& board->square[C1] == Empty
&& board->square[B1] == Empty
&& !is_attacked(board,D1,Black)) {
LIST_ADD(list,MOVE_MAKE_FLAGS(E1,C1,MoveCastle));
}
} else { // black
if ((board->flags & FlagsBlackKingCastle) != 0
&& board->square[F8] == Empty
&& board->square[G8] == Empty
&& !is_attacked(board,F8,White)) {
LIST_ADD(list,MOVE_MAKE_FLAGS(E8,G8,MoveCastle));
}
if ((board->flags & FlagsBlackQueenCastle) != 0
&& board->square[D8] == Empty
&& board->square[C8] == Empty
&& board->square[B8] == Empty
&& !is_attacked(board,D8,White)) {
LIST_ADD(list,MOVE_MAKE_FLAGS(E8,C8,MoveCastle));
}
}
}
// add_pawn_move()
void add_pawn_move(list_t * list, int from, int to) {
int move;
ASSERT(list!=NULL);
ASSERT(SQUARE_IS_OK(from));
ASSERT(SQUARE_IS_OK(to));
move = MOVE_MAKE(from,to);
if (SQUARE_IS_PROMOTE(to)) {
LIST_ADD(list,move|MovePromoteQueen);
LIST_ADD(list,move|MovePromoteKnight);
LIST_ADD(list,move|MovePromoteRook);
LIST_ADD(list,move|MovePromoteBishop);
} else {
LIST_ADD(list,move);
}
}
// add_promote()
void add_promote(list_t * list, int move) {
ASSERT(list!=NULL);
ASSERT(move_is_ok(move));
ASSERT((move&~07777)==0); // HACK
ASSERT(SQUARE_IS_PROMOTE(MOVE_TO(move)));
LIST_ADD(list,move|MovePromoteQueen);
LIST_ADD(list,move|MovePromoteKnight);
LIST_ADD(list,move|MovePromoteRook);
LIST_ADD(list,move|MovePromoteBishop);
}
// end of move_gen.cpp