static bool simple_stalemate(const board_t * board) { int me, opp; int king; int opp_flag; int from, to; int capture; const inc_t * inc_ptr; int inc; ASSERT(board!=NULL); ASSERT(board_is_legal(board)); ASSERT(!board_is_check(board)); // lone king? me = board->turn; if (board->piece_size[me] != 1 || board->pawn_size[me] != 0) return false; // no // king in a corner? king = KING_POS(board,me); if (king != A1 && king != H1 && king != A8 && king != H8) return false; // no // init opp = COLOUR_OPP(me); opp_flag = COLOUR_FLAG(opp); // king can move? from = king; for (inc_ptr = KingInc; (inc=*inc_ptr) != IncNone; inc_ptr++) { to = from + inc; capture = board->square[to]; if (capture == Empty || FLAG_IS(capture,opp_flag)) { if (!is_attacked(board,to,opp)) return false; // legal king move } } // no legal move ASSERT(board_is_stalemate((board_t*)board)); return true; }
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)); } } } } }
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)); } } } } }
static bool gen_evasions(list_t * list, const board_t * board, const attack_t * attack, bool legal, bool stop) { int me, opp; int opp_flag; int king; const inc_t * inc_ptr; int inc; int to; int piece; ASSERT(list!=NULL); ASSERT(board!=NULL); ASSERT(attack!=NULL); ASSERT(legal==true||legal==false); ASSERT(stop==true||stop==false); ASSERT(board_is_check(board)); ASSERT(ATTACK_IN_CHECK(attack)); // init LIST_CLEAR(list); me = board->turn; opp = COLOUR_OPP(me); opp_flag = COLOUR_FLAG(opp); king = KING_POS(board,me); for (inc_ptr = KingInc; (inc=*inc_ptr) != IncNone; inc_ptr++) { if (inc != -attack->di[0] && inc != -attack->di[1]) { // avoid escaping along a check line to = king + inc; piece = board->square[to]; if (piece == Empty || FLAG_IS(piece,opp_flag)) { if (!legal || !is_attacked(board,to,opp)) { if (stop) return true; LIST_ADD(list,MOVE_MAKE(king,to)); } } } } if (attack->dn >= 2) return false; // double check, we are done // single check ASSERT(attack->dn==1); // capture the checking piece if (add_pawn_captures(list,board,attack->ds[0],legal,stop) && stop) return true; if (add_piece_moves(list,board,attack->ds[0],legal,stop) && stop) return true; // interpose a piece inc = attack->di[0]; if (inc != IncNone) { // line for (to = king+inc; to != attack->ds[0]; to += inc) { ASSERT(SQUARE_IS_OK(to)); ASSERT(board->square[to]==Empty); if (add_pawn_moves(list,board,to,legal,stop) && stop) return true; if (add_piece_moves(list,board,to,legal,stop) && stop) return true; } } return false; }
void move_do(board_t * board, int move, undo_t * undo) { int me, opp; int from, to; int piece, pos, capture; int old_flags, new_flags; int delta; int sq; int pawn, rook; ASSERT(board!=NULL); ASSERT(move_is_ok(move)); ASSERT(undo!=NULL); ASSERT(board_is_legal(board)); // initialise undo undo->capture = false; undo->turn = board->turn; undo->flags = board->flags; undo->ep_square = board->ep_square; undo->ply_nb = board->ply_nb; undo->cap_sq = board->cap_sq; undo->opening = board->opening; undo->endgame = board->endgame; undo->key = board->key; undo->pawn_key = board->pawn_key; undo->material_key = board->material_key; // 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)); // update key stack ASSERT(board->sp<StackSize); board->stack[board->sp++] = board->key; // update turn board->turn = opp; board->key ^= RANDOM_64(RandomTurn); // update castling rights old_flags = board->flags; new_flags = old_flags & CastleMask[from] & CastleMask[to]; board->flags = new_flags; board->key ^= Castle64[new_flags^old_flags]; // HACK // update en-passant square if ((sq=board->ep_square) != SquareNone) { board->key ^= RANDOM_64(RandomEnPassant+SQUARE_FILE(sq)-FileA); board->ep_square = SquareNone; } if (PIECE_IS_PAWN(piece)) { delta = to - from; if (delta == +32 || delta == -32) { pawn = PAWN_MAKE(opp); if (board->square[to-1] == pawn || board->square[to+1] == pawn) { board->ep_square = (from + to) / 2; board->key ^= RANDOM_64(RandomEnPassant+SQUARE_FILE(to)-FileA); } } } // update move number (captures are handled later) board->ply_nb++; if (PIECE_IS_PAWN(piece)) board->ply_nb = 0; // conversion // update last square board->cap_sq = SquareNone; // remove the captured piece sq = to; if (MOVE_IS_EN_PASSANT(move)) sq = SQUARE_EP_DUAL(sq); if ((capture=board->square[sq]) != Empty) { ASSERT(COLOUR_IS(capture,opp)); ASSERT(!PIECE_IS_KING(capture)); undo->capture = true; undo->capture_square = sq; undo->capture_piece = capture; undo->capture_pos = board->pos[sq]; square_clear(board,sq,capture,true); board->ply_nb = 0; // conversion board->cap_sq = to; } // move the piece if (MOVE_IS_PROMOTE(move)) { // promote undo->pawn_pos = board->pos[from]; square_clear(board,from,piece,true); piece = move_promote(move); // insert the promote piece in MV order for (pos = board->piece_size[me]; pos > 0 && piece > board->square[board->piece[me][pos-1]]; pos--) // HACK ; square_set(board,to,piece,pos,true); board->cap_sq = to; } else { // normal move square_move(board,from,to,piece,true); } // move the rook in case of castling if (MOVE_IS_CASTLE(move)) { rook = Rook64 | COLOUR_FLAG(me); // HACK if (to == G1) { square_move(board,H1,F1,rook,true); } else if (to == C1) { square_move(board,A1,D1,rook,true); } else if (to == G8) { square_move(board,H8,F8,rook,true); } else if (to == C8) { square_move(board,A8,D8,rook,true); } else { ASSERT(false); } } // debug ASSERT(board_is_ok(board)); }
void move_undo(board_t * board, int move, const undo_t * undo) { int me; int from, to; int piece, pos; int rook; ASSERT(board!=NULL); ASSERT(move_is_ok(move)); ASSERT(undo!=NULL); // init me = undo->turn; from = MOVE_FROM(move); to = MOVE_TO(move); piece = board->square[to]; ASSERT(COLOUR_IS(piece,me)); // castle if (MOVE_IS_CASTLE(move)) { rook = Rook64 | COLOUR_FLAG(me); // HACK if (to == G1) { square_move(board,F1,H1,rook,false); } else if (to == C1) { square_move(board,D1,A1,rook,false); } else if (to == G8) { square_move(board,F8,H8,rook,false); } else if (to == C8) { square_move(board,D8,A8,rook,false); } else { ASSERT(false); } } // move the piece backward if (MOVE_IS_PROMOTE(move)) { // promote ASSERT(piece==move_promote(move)); square_clear(board,to,piece,false); piece = PAWN_MAKE(me); pos = undo->pawn_pos; square_set(board,from,piece,pos,false); } else { // normal move square_move(board,to,from,piece,false); } // put the captured piece back if (undo->capture) { square_set(board,undo->capture_square,undo->capture_piece,undo->capture_pos,false); } // update board info board->turn = undo->turn; board->flags = undo->flags; board->ep_square = undo->ep_square; board->ply_nb = undo->ply_nb; board->cap_sq = undo->cap_sq; board->opening = undo->opening; board->endgame = undo->endgame; board->key = undo->key; board->pawn_key = undo->pawn_key; board->material_key = undo->material_key; // update key stack ASSERT(board->sp>0); board->sp--; // debug ASSERT(board_is_ok(board)); ASSERT(board_is_legal(board)); }