static void note_quiet_moves(list_t * list, const board_t * board, bool in_pv, int ThreadId) { int size; int i, move; int move_piece; ASSERT(list_is_ok(list)); ASSERT(board!=NULL); size = LIST_SIZE(list); if (size >= 2) { for (i = 0; i < size; i++) { move = LIST_MOVE(list,i); list->value[i] = quiet_move_value(move,board,ThreadId); if (TryQuietKingAttacks && in_pv) { move_piece = MOVE_PIECE(move,board); if (!(PIECE_IS_PAWN(move_piece) || PIECE_IS_KING(move_piece))) { if (narrow_piece_attack_king(board,move_piece,MOVE_TO(move),KING_POS(board,COLOUR_OPP(board->turn)))) { if (see_move(move,board) >= 0) { // if (1 == NumberThreadsInternal) print_board(board); list->value[i] += 16; } } } } } } }
void filter_legal(list_t * list, const board_t * board) { int pos; int i, move, value; ASSERT(list_is_ok(list)); ASSERT(board_is_ok(board)); pos = 0; for (i = 0; i < list_size(list); i++) { ASSERT(pos>=0&&pos<=i); move = list_move(list,i); value = list_value(list,i); if (pseudo_is_legal(move,board)) { list->move[pos] = move; list->value[pos] = value; pos++; } } ASSERT(pos>=0&&pos<=list_size(list)); list->size = pos; }
void list_filter(list_t * list, board_t * board, move_test_t test, bool keep) { int pos; int i, move, value; ASSERT(list!=NULL); ASSERT(board!=NULL); ASSERT(test!=NULL); ASSERT(keep==true||keep==false); pos = 0; for (i = 0; i < LIST_SIZE(list); i++) { ASSERT(pos>=0&&pos<=i); move = LIST_MOVE(list,i); value = LIST_VALUE(list,i); if ((*test)(move,board) == keep) { list->move[pos] = move; list->value[pos] = value; pos++; } } ASSERT(pos>=0&&pos<=LIST_SIZE(list)); list->size = pos; // debug ASSERT(list_is_ok(list)); }
void gen_pseudo_evasions(list_t * list, const board_t * board, const attack_t * attack) { ASSERT(list!=NULL); ASSERT(board!=NULL); ASSERT(attack!=NULL); gen_evasions(list,board,attack,false,false); // debug ASSERT(list_is_ok(list)); }
void list_note(list_t * list) { int i, move; ASSERT(list_is_ok(list)); for (i = 0; i < list->size; i++) { move = list->move[i]; ASSERT(move_is_ok(move)); list->value[i] = -move_order(move); } }
void list_add(list_t * list, int move, int value) { ASSERT(list_is_ok(list)); ASSERT(move_is_ok(move)); ASSERT(value>=-32767&&value<=+32767); ASSERT(list->size<ListSize-1); list->move[list->size] = move; list->value[list->size] = value; list->size++; }
bool list_contain(const list_t * list, int move) { int i; ASSERT(list_is_ok(list)); ASSERT(move_is_ok(move)); for (i = 0; i < list->size; i++) { if (list->move[i] == move) return true; } return false; }
void list_copy(list_t * dst, const list_t * src) { int i; ASSERT(dst!=NULL); ASSERT(list_is_ok(src)); dst->size = src->size; for (i = 0; i < src->size; i++) { dst->move[i] = src->move[i]; dst->value[i] = src->value[i]; } }
void gen_captures(list_t * list, const board_t * board) { ASSERT(list!=NULL); ASSERT(board!=NULL); LIST_CLEAR(list); add_captures(list,board); add_en_passant_captures(list,board); // debug ASSERT(list_is_ok(list)); }
void list_remove(list_t * list, int pos) { int i; ASSERT(list_is_ok(list)); ASSERT(pos>=0&&pos<list->size); for (i = pos; i < list->size-1; i++) { list->move[i] = list->move[i+1]; list->value[i] = list->value[i+1]; } list->size--; }
void list_remove(list_t * list, int index) { int i; ASSERT(list_is_ok(list)); ASSERT(index>=0&&index<list->size); for (i = index; i < list->size-1; i++) { list->move[i] = list->move[i+1]; list->value[i] = list->value[i+1]; } list->size--; }
bool list_equal(list_t * list_1, list_t * list_2) { list_t copy_1[1], copy_2[1]; int i; ASSERT(list_is_ok(list_1)); ASSERT(list_is_ok(list_2)); if (list_1->size != list_2->size) return false; list_copy(copy_1,list_1); list_note(copy_1); list_sort(copy_1); list_copy(copy_2,list_2); list_note(copy_2); list_sort(copy_2); for (i = 0; i < copy_1->size; i++) { if (copy_1->move[i] != copy_2->move[i]) return false; } return true; }
void gen_quiet_moves(list_t * list, const board_t * board) { ASSERT(list!=NULL); ASSERT(board!=NULL); ASSERT(!board_is_check(board)); LIST_CLEAR(list); add_quiet_moves(list,board); add_castle_moves(list,board); // debug ASSERT(list_is_ok(list)); }
static void note_mvv_lva(list_t * list, const board_t * board) { int size; int i, move; ASSERT(list_is_ok(list)); ASSERT(board!=NULL); size = LIST_SIZE(list); if (size >= 2) { for (i = 0; i < size; i++) { move = LIST_MOVE(list,i); list->value[i] = mvv_lva(move,board); } } }
static void note_moves_simple(list_t * list, const board_t * board, int trans_killer) { int size; int i, move; ASSERT(list_is_ok(list)); ASSERT(board!=NULL); ASSERT(trans_killer==MoveNone||move_is_ok(trans_killer)); size = LIST_SIZE(list); if (size >= 2) { for (i = 0; i < size; i++) { move = LIST_MOVE(list,i); list->value[i] = move_value_simple(move,board,trans_killer); } } }
void note_moves(list_t * list, const board_t * board, int height, int trans_killer, int ThreadId) { int size; int i, move; ASSERT(list_is_ok(list)); ASSERT(board!=NULL); ASSERT(height_is_ok(height)); ASSERT(trans_killer==MoveNone||move_is_ok(trans_killer)); size = LIST_SIZE(list); if (size >= 2) { for (i = 0; i < size; i++) { move = LIST_MOVE(list,i); list->value[i] = move_value(move,board,height,trans_killer,ThreadId); } } }
void list_disp(const list_t * list, const board_t * board) { int i, move, value; char string[256]; ASSERT(list_is_ok(list)); ASSERT(board_is_ok(board)); for (i = 0; i < list->size; i++) { move = list->move[i]; value = list->value[i]; if (!move_to_can(move,board,string,256)) ASSERT(false); my_log("POLYGLOT %-5s %04X %+4d\n",string,move,value); } my_log("POLYGLOT\n"); }
void gen_legal_moves(list_t * list, board_t * board) { attack_t attack[1]; ASSERT(list!=NULL); ASSERT(board!=NULL); attack_set(attack,board); if (ATTACK_IN_CHECK(attack)) { gen_legal_evasions(list,board,attack); } else { gen_moves(list,board); list_filter(list,board,&pseudo_is_legal,true); } // debug ASSERT(list_is_ok(list)); }
void list_sort(list_t * list) { int i, j; int best_index, best_move, best_value; ASSERT(list_is_ok(list)); for (i = 0; i < list->size-1; i++) { best_index = i; best_value = list->value[i]; for (j = i+1; j < list->size; j++) { if (list->value[j] > best_value) { best_index = j; best_value = list->value[j]; } } if (best_index != i) { best_move = list->move[best_index]; ASSERT(best_value==list->value[best_index]); for (j = best_index; j > i; j--) { list->move[j] = list->move[j-1]; list->value[j] = list->value[j-1]; } list->move[i] = best_move; list->value[i] = best_value; } } if (DEBUG) { for (i = 0; i < list->size-1; i++) { ASSERT(list->value[i]>=list->value[i+1]); } } }
void list_sort(list_t * list) { int size; int i, j; int move, value; ASSERT(list_is_ok(list)); // init size = list->size; list->value[size] = -32768; // HACK: sentinel // insert sort (stable) for (i = size-2; i >= 0; i--) { move = list->move[i]; value = list->value[i]; for (j = i; value < list->value[j+1]; j++) { list->move[j] = list->move[j+1]; list->value[j] = list->value[j+1]; } ASSERT(j<size); list->move[j] = move; list->value[j] = value; } // debug if (DEBUG) { for (i = 0; i < size-1; i++) { ASSERT(list->value[i]>=list->value[i+1]); } } }
int search_full_root(list_t * list, board_t * board, int a, int b, int depth, int search_type, int ThreadId) { int value; ASSERT(list_is_ok(list)); ASSERT(board_is_ok(board)); ASSERT(depth_is_ok(depth)); ASSERT(search_type==SearchNormal||search_type==SearchShort); ASSERT(list==SearchRoot[ThreadId]->list); ASSERT(!LIST_IS_EMPTY(list)); ASSERT(board==SearchCurrent[ThreadId]->board); ASSERT(board_is_legal(board)); ASSERT(depth>=1); value = full_root(list,board,a,b,depth,0,search_type, ThreadId); ASSERT(value_is_ok(value)); ASSERT(LIST_VALUE(list,0)==value); return value; }
void list_move_to_front(list_t * list, int index) { int i; int move, value; ASSERT(list_is_ok(list)); ASSERT(index>=0&&index<list->size); if (index != 0) { move = list->move[index]; value = list->value[index]; for (i = index; i > 0; i--) { list->move[i] = list->move[i-1]; list->value[i] = list->value[i-1]; } list->move[0] = move; list->value[0] = value; } }
int search_full_root(list_t * list, board_t * board, int depth, int search_type) { int value, a, b; ASSERT(list_is_ok(list)); ASSERT(board_is_ok(board)); ASSERT(depth_is_ok(depth)); ASSERT(search_type==SearchNormal||search_type==SearchShort); ASSERT(list==SearchRoot->list); ASSERT(!LIST_IS_EMPTY(list)); ASSERT(board==SearchCurrent->board); ASSERT(board_is_legal(board)); ASSERT(depth>=1); if (SearchBest[SearchCurrent->multipv].value == 0){ a = -ValueInf; b = +ValueInf; } else{ a = SearchBest[SearchCurrent->multipv].value - 40; b = SearchBest[SearchCurrent->multipv].value + 40; } if (SearchInput->multipv > 0){ a = -ValueInf; b = +ValueInf; } value = full_root(list,board,a,b,depth,0,search_type); ASSERT(value_is_ok(value)); ASSERT(LIST_VALUE(list,0)==value); return value; }
void search_full_init(list_t * list, board_t * board) { const char * string; int trans_move, trans_min_depth, trans_max_depth, trans_min_value, trans_max_value; ASSERT(list_is_ok(list)); ASSERT(board_is_ok(board)); // null-move options string = option_get_string("NullMove Pruning"); if (false) { } else if (my_string_equal(string,"Always")) { UseNull = true; UseNullEval = false; } else if (my_string_equal(string,"Fail High")) { UseNull = true; UseNullEval = true; } else if (my_string_equal(string,"Never")) { UseNull = false; UseNullEval = false; } else { ASSERT(false); UseNull = true; UseNullEval = true; } NullReduction = option_get_int("NullMove Reduction"); string = option_get_string("Verification Search"); if (false) { } else if (my_string_equal(string,"Always")) { UseVer = true; UseVerEndgame = false; } else if (my_string_equal(string,"Endgame")) { UseVer = true; UseVerEndgame = true; } else if (my_string_equal(string,"Never")) { UseVer = false; UseVerEndgame = false; } else { ASSERT(false); UseVer = true; UseVerEndgame = true; } VerReduction = option_get_int("Verification Reduction"); // history-pruning options UseHistory = option_get_bool("History Pruning"); HistoryValue = (option_get_int("History Threshold") * 16384 + 50) / 100; UseExtendedHistory = option_get_bool("Toga Extended History Pruning"); HistoryBound = (option_get_int("Toga History Threshold") * 16384 + 50) / 100; // futility-pruning options UseFutility = option_get_bool("Futility Pruning"); FutilityMargin1 = option_get_int("Futility Margin"); FutilityMargin2 = option_get_int("Extended Futility Margin"); // delta-pruning options UseDelta = option_get_bool("Delta Pruning"); DeltaMargin = option_get_int("Delta Margin"); // quiescence-search options CheckNb = option_get_int("Quiescence Check Plies"); CheckDepth = 1 - CheckNb; // standard sort list_note(list); list_sort(list); // basic sort trans_move = MoveNone; if (UseTrans) trans_retrieve(Trans,board->key,&trans_move,&trans_min_depth,&trans_max_depth,&trans_min_value,&trans_max_value); note_moves(list,board,0,trans_move); list_sort(list); }
static int full_root(list_t * list, board_t * board, int alpha, int beta, int depth, int height, int search_type) { int old_alpha; int value, best_value[MultiPVMax]; int i, move, j; int new_depth; undo_t undo[1]; mv_t new_pv[HeightMax]; bool found; ASSERT(list_is_ok(list)); ASSERT(board_is_ok(board)); ASSERT(range_is_ok(alpha,beta)); ASSERT(depth_is_ok(depth)); ASSERT(height_is_ok(height)); ASSERT(search_type==SearchNormal||search_type==SearchShort); ASSERT(list==SearchRoot->list); ASSERT(!LIST_IS_EMPTY(list)); ASSERT(board==SearchCurrent->board); ASSERT(board_is_legal(board)); ASSERT(depth>=1); // init SearchStack[height].best_move = MoveNone; SearchStack[height].move = MoveNone; SearchStack[height].threat_move = MoveNone; SearchStack[height].reduced = false; SearchCurrent->node_nb++; SearchInfo->check_nb--; if (SearchCurrent->multipv == 0) for (i = 0; i < LIST_SIZE(list); i++) list->value[i] = ValueNone; old_alpha = alpha; best_value[SearchCurrent->multipv] = ValueNone; // move loop for (i = 0; i < LIST_SIZE(list); i++) { move = LIST_MOVE(list,i); if (SearchCurrent->multipv > 0){ found = false; for (j = 0; j < SearchCurrent->multipv; j++){ if (SearchBest[j].pv[0] == move){ found = true; break; } } if (found == true) continue; } SearchStack[height].move = move; SearchRoot->depth = depth; SearchRoot->move = move; SearchRoot->move_pos = i; SearchRoot->move_nb = LIST_SIZE(list); search_update_root(); new_depth = full_new_depth(depth,move,board,board_is_check(board)&&LIST_SIZE(list)==1,false,true, height); move_do(board,move,undo); if (search_type == SearchShort || best_value[SearchCurrent->multipv] == ValueNone) { // first move value = -full_search(board,-beta,-alpha,new_depth,height+1,new_pv,NodePV); if (value <= alpha){ // research old_alpha = -ValueInf; value = -full_search(board,-beta,ValueInf,new_depth,height+1,new_pv,NodePV); } else if (value >= beta){ // research value = -full_search(board,-ValueInf,-alpha,new_depth,height+1,new_pv,NodePV); } } else { // other moves value = -full_search(board,-alpha-1,-alpha,new_depth,height+1,new_pv,NodeCut); if (value > alpha) { // && value < beta SearchRoot->change = true; SearchRoot->easy = false; SearchRoot->flag = false; search_update_root(); value = -full_search(board,-beta,-alpha,new_depth,height+1,new_pv,NodePV); } } move_undo(board,move,undo); if (value <= alpha) { // upper bound list->value[i] = old_alpha; } else if (value >= beta) { // lower bound list->value[i] = beta; } else { // alpha < value < beta => exact value list->value[i] = value; } if (value > best_value[SearchCurrent->multipv] && (best_value[SearchCurrent->multipv] == ValueNone || value > alpha)) { SearchBest[SearchCurrent->multipv].move = move; SearchStack[height].best_move = move; SearchBest[SearchCurrent->multipv].value = value; if (value <= alpha) { // upper bound SearchBest[SearchCurrent->multipv].flags = SearchUpper; } else if (value >= beta) { // lower bound SearchBest[SearchCurrent->multipv].flags = SearchLower; } else { // alpha < value < beta => exact value SearchBest[SearchCurrent->multipv].flags = SearchExact; } SearchBest[SearchCurrent->multipv].depth = depth; pv_cat(SearchBest[SearchCurrent->multipv].pv,new_pv,move); search_update_best(); } if (value > best_value[SearchCurrent->multipv]) { best_value[SearchCurrent->multipv] = value; if (value > alpha) { if (search_type == SearchNormal) alpha = value; if (value >= beta) break; } } } ASSERT(value_is_ok(best_value)); list_sort(list); ASSERT(SearchBest->move==LIST_MOVE(list,0)); ASSERT(SearchBest->value==best_value); if (UseTrans && best_value[SearchCurrent->multipv] > old_alpha && best_value[SearchCurrent->multipv] < beta) { pv_fill(SearchBest[SearchCurrent->multipv].pv,board); } return best_value[SearchCurrent->multipv]; }
bool list_is_empty(const list_t * list) { ASSERT(list_is_ok(list)); return list->size == 0; }
int list_size(const list_t * list) { ASSERT(list_is_ok(list)); return list->size; }
void search_full_init(list_t * list, board_t * board, int ThreadId) { const char * string; int trans_move, trans_depth, trans_flags, trans_value; int i, j; entry_t * found_entry; ASSERT(list_is_ok(list)); ASSERT(board_is_ok(board)); // null-move options string = option_get_string("NullMove Pruning"); if (false) { } else if (my_string_equal(string,"Always")) { UseNull = true; UseNullEval = false; } else if (my_string_equal(string,"Fail High")) { UseNull = true; UseNullEval = true; } else if (my_string_equal(string,"Never")) { UseNull = false; UseNullEval = false; } else { ASSERT(false); UseNull = true; UseNullEval = true; } NullReduction = option_get_int("NullMove Reduction"); string = option_get_string("Verification Search"); if (false) { } else if (my_string_equal(string,"Always")) { UseVer = true; UseVerEndgame = false; } else if (my_string_equal(string,"Endgame")) { UseVer = true; UseVerEndgame = true; } else if (my_string_equal(string,"Never")) { UseVer = false; UseVerEndgame = false; } else { ASSERT(false); UseVer = true; UseVerEndgame = true; } VerReduction = option_get_int("Verification Reduction"); // history-pruning options UseHistory = option_get_bool("History Pruning"); HistoryValue = (option_get_int("History Threshold") * 16384 + 50) / 100; // Stockfish Late Move Reductions // about 20 elo better than previous Toga History Reductions for (i = 0; i < 64; i++){ for (j = 0; j < 64; j++){ if (i == 0 || j == 0){ quietPvMoveReduction[i][j] = quietMoveReduction[i][j] = 0; } else{ double pvReduction = log((double) (i)) * log((double) (j)) / 3.0; double nonPvReduction = (1.0 + log((double) (i))) * log((double) (j)) / 2.5; // JD quietPvMoveReduction[i][j] = (int) (pvReduction >= 1.0 ? floor(pvReduction) : 0); quietMoveReduction[i][j] = (int) (nonPvReduction >= 1.0 ? floor(nonPvReduction) : 0); } } } // futility-pruning options UseFutility = option_get_bool("Futility Pruning"); FutilityMargin1 = option_get_int("Futility Margin"); FutilityMargin2 = option_get_int("Extended Futility Margin"); // delta-pruning options UseDelta = option_get_bool("Delta Pruning"); DeltaMargin = option_get_int("Delta Margin"); // quiescence-search options SearchCurrent[ThreadId]->CheckNb = option_get_int("Quiescence Check Plies"); SearchCurrent[ThreadId]->CheckDepth = 1 - SearchCurrent[ThreadId]->CheckNb; // standard sort list_note(list); list_sort(list); // misc SearchCurrent[ThreadId]->last_move = MoveNone; // basic sort trans_move = MoveNone; if (UseTrans) trans_retrieve(Trans,&found_entry,board->key,&trans_move,&trans_depth,&trans_flags,&trans_value); note_moves(list,board,0,trans_move,ThreadId); list_sort(list); }