static int in_check(board_t *board, int turn) { int i; for (i = 0; i < 64; i++) if (board->square[i] == KING + turn) break; if (i == 64) { DBG_ERROR("board is missing a king"); exit(1); } return square_attacked(board, i, OPPONENT(turn)); }
/* Checks whether a move is valid, except for whether this puts own king in check. */ static int move_is_semi_valid(board_t *board, move_t *move) { /* Bounds check. */ if ((move->source > 63) || (move->source < 0)) return 0; if ((move->destination > 63) || (move->destination < 0)) return 0; /* Test for moving to same square. */ if (move->source == move->destination) return 0; /* Test for empty source square. */ if (board->square[move->source] == NONE) return 0; /* Test for moving opponent's piece. */ if (COLOUR(board->square[move->source]) != board->turn) return 0; /* Check that a promotion piece is specified for promotion moves. */ if ((PIECE(board->square[move->source]) == PAWN) && ((move->destination < 8) || (move->destination >= 56))) { switch (PIECE(move->promotion_piece)) { case KNIGHT: case ROOK: case BISHOP: case QUEEN: break; default: return 0; } if (COLOUR(move->promotion_piece) != board->turn) return 0; } else if (move->promotion_piece != NONE) /* Promotion piece specified for non-promotion move. */ return 0; switch (PIECE(board->square[move->source])) { case KNIGHT: if ((HOR != 1) && (HOR != 2)) return 0; if ((HOR == 1) && (VERT != 2)) return 0; if ((HOR == 2) && (VERT != 1)) return 0; if (board->square[move->destination] == NONE) break; if (COLOUR(board->square[move->destination]) == COLOUR(board->square[move->source])) return 0; break; case BISHOP: if (HOR != VERT) return 0; if (!ray_ok(board, move)) return 0; break; case ROOK: if ((HOR != 0) && (VERT != 0)) return 0; if (!ray_ok(board, move)) return 0; break; case QUEEN: if ((HOR != 0) && (VERT != 0) && (HOR != VERT)) return 0; if (!ray_ok(board, move)) return 0; break; case PAWN: /* Catch moves in wrong direction. */ if ((move->destination > move->source) && (COLOUR(board->square[move->source]) == BLACK)) return 0; if ((move->destination < move->source) && (COLOUR(board->square[move->source]) == WHITE)) return 0; if (HOR > 1) return 0; if (HOR == 0) { /* Regular or double push. */ if (VERT > 2) return 0; if (VERT == 2) if (!(((move->source >= 8) && (move->source <= 15)) || ((move->source >= 48) && (move->source <= 55)))) return 0; /* Use ray checking code with added requirement that destination square is empty. */ if (!ray_ok(board, move) || (board->square[move->destination] != NONE)) return 0; } else { if (VERT != 1) return 0; if (!ray_ok(board, move)) return 0; /* En-passant move. */ if (board->square[move->destination] == NONE) { if ((COLOUR(board->square[move->source]) == WHITE) && !((move->source >= 32) && (move->source < 40))) return 0; if ((COLOUR(board->square[move->source]) == BLACK) && !((move->source >= 24) && (move->source < 32))) return 0; if (board->square[move->destination + (COLOUR(board->square[move->source]) == WHITE ? -8 : 8)] != PAWN + OPPONENT(COLOUR(board->square[move->source]))) return 0; } } break; case KING: if (HOR > 2) return 0; else if (HOR == 2) { int white = COLOUR(board->square[move->source]) == WHITE; int i, step = (move->destination > move->source ? 1 : -1); int rook = (step == 1 ? (white ? 7 : 63) : (white ? 0 : 56)); /* Castling. */ if (VERT != 0) return 0; if (move->source != (white ? 4 : 60)) return 0; if (board->square[rook] != ROOK + COLOUR(board->square[move->source])) return 0; i = move->source + step; while (i != rook) { if (board->square[i] != NONE) return 0; i += step; } /* Check whether any of the squares the king moves over is under ** attack. Note that destination square is checked later. */ if (square_attacked(board, move->source, (white ? BLACK : WHITE))) return 0; if (square_attacked(board, move->source + step, (white ? BLACK : WHITE))) return 0; } else { if (VERT > 1) return 0; if (!ray_ok(board, move)) return 0; } } return 1; }
int qsearch(s_search_info *info, s_stack *stack, s_board *board, int alpha, int beta) { assert(info != NULL); assert(stack != NULL); assert(board != NULL); assert(alpha < beta); int stand_pat = evaluate(board); if(stack->ply > info->seldepth) { info->seldepth = stack->ply-1; } if(stand_pat >= beta) { return beta; } #ifdef DELTA_PRUNING const int safety = 900; // The value of a queen if(stand_pat < alpha - safety && !is_endgame(board)) { return alpha; } #endif if(stand_pat > alpha) { alpha = stand_pat; } if(stack->ply >= MAX_DEPTH) { return stand_pat; } // Set old permissions s_irreversible permissions; store_irreversible(&permissions, board); s_move moves[MAX_MOVES]; int num_moves = find_moves_captures(board, moves, board->turn); #ifdef SORT_MOVES moves_sort_see(board, moves, num_moves); #endif for(int m = 0; m < num_moves; ++m) { int val = see_capture(board, moves[m]); if(val < -50) { break; } move_make(board, &moves[m]); if(square_attacked(board, board->pieces[KINGS]&board->colour[!board->turn], board->turn)) { // Restore old permissions restore_irreversible(&permissions, board); move_undo(board, &moves[m]); continue; } info->nodes++; int score = -qsearch(info, stack+1, board, -beta, -alpha); // Restore old permissions restore_irreversible(&permissions, board); move_undo(board, &moves[m]); if(score >= beta) { #ifndef NDEBUG info->num_cutoffs[m]++; #endif return beta; } if(score > alpha) { alpha = score; } } return alpha; }