bool pseudo_is_legal(int move, board_t * board) { int me, opp; int from, to; int piece; bool legal; int king; undo_t undo[1]; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); // init me = board->turn; opp = COLOUR_OPP(me); from = MOVE_FROM(move); to = MOVE_TO(move); piece = board->square[from]; ASSERT(COLOUR_IS(piece,me)); // slow test for en-passant captures if (MOVE_IS_EN_PASSANT(move)) { move_do(board,move,undo); legal = !IS_IN_CHECK(board,me); move_undo(board,move,undo); return legal; } // king moves (including castle) if (PIECE_IS_KING(piece)) { legal = !is_attacked(board,to,opp); if (DEBUG) { ASSERT(board->square[from]==piece); board->square[from] = Empty; ASSERT(legal==!is_attacked(board,to,opp)); board->square[from] = piece; } return legal; } // pins if (is_pinned(board,from,me)) { king = KING_POS(board,me); return DELTA_INC_LINE(king-to) == DELTA_INC_LINE(king-from); // does not discover the line } return true; }
static void alists_hidden(alists_t * alists, const board_t * board, int from, int to) { int inc; int sq, piece; ASSERT(alists!=NULL); ASSERT(board!=NULL); ASSERT(SQUARE_IS_OK(from)); ASSERT(SQUARE_IS_OK(to)); inc = DELTA_INC_LINE(to-from); if (inc != IncNone) { // line sq = from; do sq -= inc; while ((piece=board->square[sq]) == Empty); if (SLIDER_ATTACK(piece,inc)) { ASSERT(piece_is_ok(piece)); ASSERT(PIECE_IS_SLIDER(piece)); alist_add(alists->alist[PIECE_COLOUR(piece)],sq,board); } } }
bool is_pinned(const board_t * board, int square, int colour) { int from, to; int inc; int sq, piece; ASSERT(board!=NULL); ASSERT(SQUARE_IS_OK(square)); ASSERT(COLOUR_IS_OK(colour)); from = square; to = KING_POS(board,colour); inc = DELTA_INC_LINE(to-from); if (inc == IncNone) return false; // not a line sq = from; do sq += inc; while (board->square[sq] == Empty); if (sq != to) return false; // blocker sq = from; do sq -= inc; while ((piece=board->square[sq]) == Empty); return COLOUR_IS(piece,COLOUR_OPP(colour)) && SLIDER_ATTACK(piece,inc); }
bool move_is_check(int move, board_t * board) { undo_t undo[1]; bool check; int me, opp, king; int from, to, piece; ASSERT(move_is_ok(move)); ASSERT(board!=NULL); // slow test for complex moves if (MOVE_IS_SPECIAL(move)) { move_do(board,move,undo); check = IS_IN_CHECK(board,board->turn); move_undo(board,move,undo); return check; } // init me = board->turn; opp = COLOUR_OPP(me); king = KING_POS(board,opp); from = MOVE_FROM(move); to = MOVE_TO(move); piece = board->square[from]; ASSERT(COLOUR_IS(piece,me)); // direct check if (PIECE_ATTACK(board,piece,to,king)) return true; // indirect check if (is_pinned(board,from,opp) && DELTA_INC_LINE(king-to) != DELTA_INC_LINE(king-from)) { return true; } return false; }
static void find_pins(int list[], const board_t * board) { int me, opp; int king; const sq_t * ptr; int from; int piece; int delta; int inc; int sq; int capture; int pin; ASSERT(list!=NULL); ASSERT(board!=NULL); // init me = board->turn; opp = COLOUR_OPP(me); king = KING_POS(board,opp); for (ptr = &board->piece[me][1]; (from=*ptr) != SquareNone; ptr++) { // HACK: no king piece = board->square[from]; delta = king - from; ASSERT(delta_is_ok(delta)); if (PSEUDO_ATTACK(piece,delta)) { ASSERT(PIECE_IS_SLIDER(piece)); inc = DELTA_INC_LINE(delta); ASSERT(inc!=IncNone); ASSERT(SLIDER_ATTACK(piece,inc)); sq = from; do sq += inc; while ((capture=board->square[sq]) == Empty); ASSERT(sq!=king); if (COLOUR_IS(capture,me)) { pin = sq; do sq += inc; while (board->square[sq] == Empty); if (sq == king) *list++ = pin; } } } *list = SquareNone; }
static void add_quiet_checks(list_t * list, const board_t * board) { int me, opp; int king; const sq_t * ptr, * ptr_2; int from, to, sq; int piece; const inc_t * inc_ptr; int inc; int pawn; int rank; int pin[8+1]; ASSERT(list!=NULL); ASSERT(board!=NULL); // init me = board->turn; opp = COLOUR_OPP(me); king = KING_POS(board,opp); find_pins(pin,board); // indirect checks for (ptr = pin; (from=*ptr) != SquareNone; ptr++) { piece = board->square[from]; ASSERT(is_pinned(board,from,opp)); if (PIECE_IS_PAWN(piece)) { inc = PAWN_MOVE_INC(me); rank = PAWN_RANK(from,me); if (rank != Rank7) { // promotes are generated with captures to = from + inc; if (board->square[to] == Empty) { if (DELTA_INC_LINE(to-king) != DELTA_INC_LINE(from-king)) { ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE(from,to)); if (rank == Rank2) { to = from + (2*inc); if (board->square[to] == Empty) { ASSERT(DELTA_INC_LINE(to-king)!=DELTA_INC_LINE(from-king)); ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE(from,to)); } } } } } } else if (PIECE_IS_SLIDER(piece)) { for (inc_ptr = PIECE_INC(piece); (inc=*inc_ptr) != IncNone; inc_ptr++) { for (to = from+inc; board->square[to] == Empty; to += inc) { ASSERT(DELTA_INC_LINE(to-king)!=DELTA_INC_LINE(from-king)); LIST_ADD(list,MOVE_MAKE(from,to)); } } } else { for (inc_ptr = PIECE_INC(piece); (inc=*inc_ptr) != IncNone; inc_ptr++) { to = from + inc; if (board->square[to] == Empty) { if (DELTA_INC_LINE(to-king) != DELTA_INC_LINE(from-king)) { LIST_ADD(list,MOVE_MAKE(from,to)); } } } } } // piece direct checks for (ptr = &board->piece[me][1]; (from=*ptr) != SquareNone; ptr++) { // HACK: no king for (ptr_2 = pin; (sq=*ptr_2) != SquareNone; ptr_2++) { if (sq == from) goto next_piece; } ASSERT(!is_pinned(board,from,opp)); 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; board->square[to] == Empty; to += inc) { if (PIECE_ATTACK(board,piece,to,king)) { LIST_ADD(list,MOVE_MAKE(from,to)); } } } } else { for (; (inc=*inc_ptr) != IncNone; inc_ptr++) { to = from + inc; if (board->square[to] == Empty) { if (PSEUDO_ATTACK(piece,king-to)) { LIST_ADD(list,MOVE_MAKE(from,to)); } } } } next_piece: ; } // pawn direct checks inc = PAWN_MOVE_INC(me); pawn = PAWN_MAKE(me); to = king - (inc-1); ASSERT(PSEUDO_ATTACK(pawn,king-to)); from = to - inc; if (board->square[from] == pawn) { if (board->square[to] == Empty) { ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE(from,to)); } } else { from = to - (2*inc); if (board->square[from] == pawn) { if (PAWN_RANK(from,me) == Rank2 && board->square[to] == Empty && board->square[from+inc] == Empty) { ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE(from,to)); } } } to = king - (inc+1); ASSERT(PSEUDO_ATTACK(pawn,king-to)); from = to - inc; if (board->square[from] == pawn) { if (board->square[to] == Empty) { ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE(from,to)); } } else { from = to - (2*inc); if (board->square[from] == pawn) { if (PAWN_RANK(from,me) == Rank2 && board->square[to] == Empty && board->square[from+inc] == Empty) { ASSERT(!SQUARE_IS_PROMOTE(to)); LIST_ADD(list,MOVE_MAKE(from,to)); } } } }
void attack_set(attack_t * attack, const board_t * board) { int me, opp; const sq_t * ptr; int from, to; int inc; int pawn; int delta, piece; int sq; ASSERT(attack!=NULL); ASSERT(board!=NULL); // init attack->dn = 0; me = board->turn; opp = COLOUR_OPP(me); to = KING_POS(board,me); // pawn attacks inc = PAWN_MOVE_INC(opp); pawn = PAWN_MAKE(opp); from = to - (inc-1); if (board->square[from] == pawn) { attack->ds[attack->dn] = from; attack->di[attack->dn] = IncNone; attack->dn++; } from = to - (inc+1); if (board->square[from] == pawn) { attack->ds[attack->dn] = from; attack->di[attack->dn] = IncNone; attack->dn++; } // piece attacks for (ptr = &board->piece[opp][1]; (from=*ptr) != SquareNone; ptr++) { // HACK: no king piece = board->square[from]; delta = to - from; ASSERT(delta_is_ok(delta)); if (PSEUDO_ATTACK(piece,delta)) { inc = IncNone; if (PIECE_IS_SLIDER(piece)) { // check for blockers inc = DELTA_INC_LINE(delta); ASSERT(inc!=IncNone); sq = from; do sq += inc; while (board->square[sq] == Empty); if (sq != to) continue; // blocker => next attacker } attack->ds[attack->dn] = from; attack->di[attack->dn] = -inc; // HACK attack->dn++; } } attack->ds[attack->dn] = SquareNone; attack->di[attack->dn] = IncNone; // debug ASSERT(attack_is_ok(attack)); }