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; }
// ------------------------------------------------------------------- // Determine king mobility // - returns a list of all squares where the king may move // ------------------------------------------------------------------- move_list ChessBoard::mobility_king(int from) const { chessmove m; move_list ml; m.promotion=Empty; m.from=from; // Potential destinations relative to king's position static const int relative_destination[] = {-Rank-File, -Rank, -Rank+File, -File, File, Rank-File, Rank, Rank+File}; for (int i=0;i<8;i++) { m.to=from+relative_destination[i]; if (is_dest(m.from,m.to) && abs(which_file(from)-which_file(m.to))<=1 && !causes_check(m)) ml.push_front(m); } // Can king castle kingside? register bool white=is_white(square[from]); if (// 1) Castling flag is set (i.e. king/rook not moved/captured) (white ? w_castle_k : b_castle_k) == true && // 2) King is not castling to escape check (white ? w_check : b_check) == false && // 3) King is not castling through check is_attacked(!white, from+File) == false && // 4) King is not castling into check is_attacked(!white, from+2*File) == false && // 5) Squares between king and rook are empty square[from+File]==Empty && square[from+2*File]==Empty ) { m.to=from+2*File; ml.push_front(m); } // Can king castle queenside? if (// 1) Castling flag is set (i.e. king/rook not moved/captured) (white ? w_castle_q : b_castle_q) == true && // 2) King is not castling to escape check (white ? w_check : b_check) == false && // 3) King is not castling through check is_attacked(!white, from-File) == false && // 4) King is not castling into check is_attacked(!white, from-2*File) == false && // 5) Squares between king and rook are empty square[from-File]==Empty && square[from-2*File]==Empty && square[from-3*File]==Empty) { m.to=from-2*File; ml.push_front(m); } return ml; }
bool is_in_check(const board_t * board, int colour) { ASSERT(board_is_ok(board)); ASSERT(colour_is_ok(colour)); return is_attacked(board,king_pos(board,colour),colour_opp(colour)); }
int check_mate_pawns_b(long64 idx0, ubyte *table, bitboard occ, int *p) { int i; int sq; long64 idx, idx2; for (i = 0; i < numpawns; i++) { if (pw[i]) continue; sq = p[i]; if (bit[sq - 8] & occ) continue; if (sq < 0x10) { if (!is_attacked(p[black_king], white_all, occ ^ bit[sq] ^ bit[sq - 8], p)) return 0; } else { idx = idx0 & ~mask[i]; if (i) idx2 = idx | ((p[i] - 0x08) << shift[i]); else idx2 = idx | piv_idx[p[i] - 0x08]; if (table[idx2] < WDL_ILLEGAL) return 0; if (sq >= 0x30 && !(bit[sq - 0x10] & occ)) { if (i) idx2 = idx | ((p[i] - 0x10) << shift[i]); else idx2 = idx | piv_idx[p[i] - 0x10]; if (table[idx2] < WDL_ILLEGAL) return 0; } } } return 1; }
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)); } } }
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 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; }
// ------------------------------------------------------------------- // Piece movement: // - this function must be passed a *VALID* move (e.g. one that has // been verified by can_move()) // - promotion piece will be automatically cast to correct colour // ------------------------------------------------------------------- game_status ChessBoard::do_move(int from, int to, piece_type promotion) { // Disable castling if rook is captured or moved for (int *sq=&to;sq;sq=sq==&to?&from:(int *)NULL) switch (*sq) { case a1: w_castle_q=false; break; case a8: b_castle_q=false; break; case h1: w_castle_k=false; break; case h8: b_castle_k=false; } // Reset castled flags b_castled=w_castled=false; // Mark en-passant square, if any if (square[from]==w_Pawn && to==from+2*Rank) en_passant=from+Rank; else if (square[from]==b_Pawn && to==from-2*Rank) en_passant=from-Rank; else en_passant=No_square; // Perform actual rearrangement of board pieces bool increment_fifty=true; if (w_castle_k && from==e1 && to==g1) { square[g1]=w_King; // White castles kingside square[f1]=w_Rook; square[e1]=square[h1]=Empty; w_castled=true; } else if (w_castle_q && from==e1 && to==c1) { square[c1]=w_King; // White castles queenside square[d1]=w_Rook; square[e1]=square[a1]=Empty; w_castled=true; } else if (b_castle_k && from==e8 && to==g8) { square[g8]=b_King; // Black castles kingside square[f8]=b_Rook; square[e8]=square[h8]=Empty; b_castled=true; } else if (b_castle_q && from==e8 && to==c8) { square[c8]=b_King; // Black castles queenside square[d8]=b_Rook; square[e8]=square[a8]=Empty; b_castled=true; } else if (square[from]==w_Pawn && square[to]==Empty && to!=from+Rank) { square[to]=w_Pawn; // White captures en-passant square[from]=square[to-Rank]=Empty; increment_fifty=false; } else if (square[from]==b_Pawn && square[to]==Empty && to!=from-Rank) { square[to]=b_Pawn; // Black captures en-passant square[from]=square[to+Rank]=Empty; increment_fifty=false; } else { // Normal move if (square[to]!=Empty || is_pawn(square[from])) increment_fifty=false; promotion=make_colour(promotion, w_turn); square[to]=(promotion!=Empty)?promotion:square[from]; square[from]=Empty; } // Disable castling if king was moved if (square[e1]!=w_King) w_castle_q=w_castle_k=false; if (square[e8]!=b_King) b_castle_q=b_castle_k=false; // Update king position if (square[to]==w_King) w_king_pos=to; else if (square[to]==b_King) b_king_pos=to; // Adjust 50-move rule counter fifty=increment_fifty?fifty+1:0; // Set check flag if (w_turn) { w_check=is_attacked(!w_turn, w_king_pos); b_check=is_attacked(w_turn, b_king_pos); } else { b_check=is_attacked(!w_turn, b_king_pos); w_check=is_attacked(w_turn, w_king_pos); } // Change active player w_turn=!w_turn; // Check for checkmate/stalemate move_list moves; for (int i=a1;i<=h8;i++) { if (is_colour(square[i], w_turn)) { switch (make_neutral(square[i])) { case King: moves=mobility_king(i); break; case Pawn: moves=mobility_pawn(i); break; case Knight: moves=mobility_knight(i); break; case Bishop: moves=mobility_bishop(i); break; case Rook: moves=mobility_rook(i); break; case Queen: moves=mobility_queen(i); break; } if (!moves.empty()) break; } } // Update log of board configurations boardlog.append(*this); // Set game status if (triple_occurrence()) { status=TripleOccurrence; in_progress=false; } else if (moves.empty() && is_in_check(w_turn)) { status=Checkmate; in_progress=false; } else if (moves.empty()) { status=Stalemate; in_progress=false; } else if (fifty>=99) { status=FiftyMoves; in_progress=false; } else if (is_in_check(w_turn)) status=Check; else status=Normal; return status; }