int iod_put(char *key,char *value, int count) { return tt_put(key,value,count,IO_DATA); }
// Unified alpha-beta and quiescence search int abq(board *b, int alpha, int beta, int ply, int centiply_extension, bool allow_extensions, bool side_to_move_in_check) { if (search_terminate_requested) return 0; // Check for search termination int alpha_orig = alpha; // For use in later TT storage // Retrieve the value from the transposition table, if appropriate evaluation stored; tt_get(b, &stored); if (!e_eq(stored, no_eval) && stored.depth >= ply && use_ttable) { if (stored.type == qexact || stored.type == exact) return stored.score; if (stored.type == qlowerbound || stored.type == lowerbound) alpha = max(alpha, stored.score); else if (stored.type == qupperbound || stored.type == upperbound) beta = min(beta, stored.score); if (alpha >= beta) return stored.score; } // Futility pruning: enter quiescence early if the node is futile if (use_futility_pruning && !side_to_move_in_check && ply == 1) { if (relative_evaluation(b) + frontier_futility_margin < alpha) ply = 0; } else if (use_futility_pruning && !side_to_move_in_check && ply == 2) { if (relative_evaluation(b) + prefrontier_futility_margin < alpha) ply = 0; } bool quiescence = (ply <= 0); // Generate all possible moves for the quiscence search or normal search, and compute the // static evaluation if applicable. move *moves = NULL; int num_available_moves = 0; if (quiescence) moves = board_moves(b, &num_available_moves, true); // Generate only captures else moves = board_moves(b, &num_available_moves, false); // Generate all moves if (quiescence && !use_qsearch) { free(moves); return relative_evaluation(b); // If qsearch is turned off } // Abort if the quiescence search is too deep (currently 45 plies) if (ply < -quiesce_ply_cutoff) { sstats.qnode_aborts++; free(moves); return relative_evaluation(b); } int quiescence_stand_pat; // Allow the quiescence search to generate cutoffs if (quiescence) { quiescence_stand_pat = relative_evaluation(b); alpha = max(alpha, quiescence_stand_pat); if (alpha >= beta) { free(moves); return quiescence_stand_pat; } } else if (!e_eq(stored, no_eval) && use_tt_move_hueristic) { assert(is_legal_move(b, stored.best)); // TODO // For non-quiescence search, use the TT entry as a hueristic moves[num_available_moves] = stored.best; num_available_moves++; } // Update search stats if (quiescence) sstats.qnodes_searched++; else sstats.nodes_searched++; // Search hueristic: sort exchanges using MVV-LVA if (quiescence && mvvlva) nlopt_qsort_r(moves, num_available_moves, sizeof(move), b, &capture_move_comparator); // Search extensions bool no_more_extensions = false; // Extend the search if we are in check //coord king_loc = b->black_to_move ? b->black_king : b->white_king; bool currently_in_check = side_to_move_in_check; //in_check(b, king_loc.col, king_loc.row, b->black_to_move); if (check_extend && currently_in_check && ply <= check_extend_threshold && !quiescence && allow_extensions) { // only extend in shallow non-quiescence situations centiply_extension += check_extension_centiply; no_more_extensions = true; } // Process any extensions if (allow_extensions && centiply_extension >= 100) { centiply_extension -= 100; ply += 1; } else if (allow_extensions && centiply_extension <= -100) { centiply_extension += 100; ply -= 1; } if (no_more_extensions) allow_extensions = false; // Only allow one check extension move best_move_yet = no_move; int best_score_yet = NEG_INFINITY; int num_moves_actually_examined = 0; // We might end up in checkmate //for (int iterations = 0; iterations < 2; iterations++) { // ABDADA iterations for (int i = num_available_moves - 1; i >= 0; i--) { // Iterate backwards to match MVV-LVA sort order /*int claimed_node_id = -1; if (i != num_available_moves - 1 && iterations == 1) { // Skip redundant young brothers on the first pass if (!tt_try_to_claim_node(b, &claimed_node_id)) continue; // Skip the node if it is already being searched } else tt_always_claim_node(b, &claimed_node_id);*/ apply(b, moves[i]); bool we_moved_into_check; // Choose the more efficient version if possible // If we were already in check, we need to do the expensive search if (side_to_move_in_check) { coord king_loc = b->black_to_move ? b->white_king : b->black_king; // for side that just moved we_moved_into_check = in_check(b, king_loc.col, king_loc.row, !(b->black_to_move)); } else we_moved_into_check = puts_in_check(b, moves[i], !b->black_to_move); // Never move into check if (we_moved_into_check) { unapply(b, moves[i]); //tt_unclaim_node(claimed_node_id); continue; } bool opponent_in_check = puts_in_check(b, moves[i], b->black_to_move); /*coord opp_king_loc = b->black_to_move ? b->black_king : b->white_king; bool opponent_in_check = in_check(b, opp_king_loc.col, opp_king_loc.row, (b->black_to_move));*/ int score = -abq(b, -beta, -alpha, ply - 1, centiply_extension, allow_extensions, opponent_in_check); num_moves_actually_examined++; unapply(b, moves[i]); if (score > best_score_yet) { best_score_yet = score; best_move_yet = moves[i]; } alpha = max(alpha, best_score_yet); if (alpha >= beta) { //tt_unclaim_node(claimed_node_id); break; } //tt_unclaim_node(claimed_node_id); } //} free(moves); // We are done with the array // We have no available moves (or captures) that don't leave us in check // This means checkmate or stalemate in normal search // It might mean no captures are available in quiescence search if (num_moves_actually_examined == 0) { if (quiescence) return quiescence_stand_pat; // TODO: qsearch doesn't understand stalemate or checkmate // This seems paradoxical, but the +1 is necessary so we pick some move in case of checkmate if (currently_in_check) return NEG_INFINITY + 1; // checkmate else return 0; // stalemate } if (quiescence && best_score_yet < quiescence_stand_pat) return quiescence_stand_pat; // TODO experimental stand pat if (search_terminate_requested) return 0; // Search termination preempts tt_put // Record the selected move in the transposition table evaltype type; if (best_score_yet <= alpha_orig) type = (quiescence) ? qupperbound : upperbound; else if (best_score_yet >= beta) type = (quiescence) ? qlowerbound : lowerbound; else type = (quiescence) ? qexact : exact; evaluation eval = {.best = best_move_yet, .score = best_score_yet, .type = type, .depth = ply}; tt_put(b, eval); return best_score_yet; }
int md_put(char *path,Meta_Data *md) { return tt_put(path,md,sizeof(Meta_Data),META_DATA); }