int main (int argc, char *argv[]) { struct sortstate *sortp; char *linep, *tdirbuf; char *tmpdir = "/tmp"; int mem = 128; int par = 1; for (;;) { int option_index = 0; int c; static struct option long_options[] = { {"tmpdir", required_argument, 0, 'd'}, {"mem", required_argument, 0, 'm'}, {"parallel", required_argument, 0, 'p'}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "t:", long_options, &option_index); if (c == -1) break; switch (c) { case 'd': tmpdir = optarg; break; case 'm': mem = atol (optarg); break; case 'p': par = atol (optarg); break; default: printf("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) error (argv[0], "Excess argument"); if (mem < 1 || mem > 2048) error (argv[0], "Invalid --mem value"); if (par < 1 || par > 16) error (argv[0], "Invalid --par value"); tdirbuf = malloc (strlen (tmpdir) + 16); sprintf (tdirbuf, "%s/sort-XXXXXX", tmpdir); linep = (char *)sort_init (&sortp, par, mem *1024 * 1024, stdin, tdirbuf, NULL); while (linep) { fputs (linep, stdout); linep = (char *)sort_nextline (sortp); } return 0; }
void search() { int move; int depth; int i; bool search_ready; for (i = 0; i < MultiPVMax; i++){ save_multipv[SearchCurrent->multipv].mate = 0; save_multipv[SearchCurrent->multipv].depth = 0; save_multipv[SearchCurrent->multipv].max_depth = 0; save_multipv[SearchCurrent->multipv].value = 0; save_multipv[SearchCurrent->multipv].time = 0; save_multipv[SearchCurrent->multipv].node_nb = 0; strcpy(save_multipv[SearchCurrent->multipv].pv_string,""); } SearchInput->multipv = option_get_int("MultiPV")-1; SearchCurrent->multipv = 0; ASSERT(board_is_ok(SearchInput->board)); // opening book if (option_get_bool("OwnBook") && !SearchInput->infinite) { move = book_move(SearchInput->board); if (move != MoveNone) { // play book move SearchBest[SearchCurrent->multipv].move = move; SearchBest[SearchCurrent->multipv].value = 1; SearchBest[SearchCurrent->multipv].flags = SearchExact; SearchBest[SearchCurrent->multipv].depth = 1; SearchBest[SearchCurrent->multipv].pv[0] = move; SearchBest[SearchCurrent->multipv].pv[1] = MoveNone; search_update_best(); return; } } // SearchInput gen_legal_moves(SearchInput->list,SearchInput->board); if (LIST_SIZE(SearchInput->list) < SearchInput->multipv+1){ SearchInput->multipv = LIST_SIZE(SearchInput->list)-1; } if (LIST_SIZE(SearchInput->list) <= 1) { SearchInput->depth_is_limited = true; SearchInput->depth_limit = 4; // was 1 } // SearchInfo if (setjmp(SearchInfo->buf) != 0) { ASSERT(SearchInfo->can_stop); ASSERT(SearchBest->move!=MoveNone); search_update_current(); return; } // SearchRoot list_copy(SearchRoot->list,SearchInput->list); // SearchCurrent board_copy(SearchCurrent->board,SearchInput->board); my_timer_reset(SearchCurrent->timer); my_timer_start(SearchCurrent->timer); // init trans_inc_date(Trans); sort_init(); search_full_init(SearchRoot->list,SearchCurrent->board); // analyze game for evaluation if (SearchCurrent->board->piece_size[White] < 3 && SearchCurrent->board->piece_size[Black] < 3){ trans_endgame = true; } else{ trans_endgame = false; } // iterative deepening search_ready = false; for (depth = 1; depth < DepthMax; depth++) { for (SearchCurrent->multipv = 0; SearchCurrent->multipv <= SearchInput->multipv; SearchCurrent->multipv++){ if (DispDepthStart && SearchCurrent->multipv == 0) send("info depth %d",depth); SearchCurrent->max_extensions = depth * 10; SearchRoot->bad_1 = false; SearchRoot->change = false; board_copy(SearchCurrent->board,SearchInput->board); if (UseShortSearch && depth <= ShortSearchDepth) { search_full_root(SearchRoot->list,SearchCurrent->board,depth,SearchShort); } else { search_full_root(SearchRoot->list,SearchCurrent->board,depth,SearchNormal); } search_update_current(); if (DispDepthEnd && SearchCurrent->multipv == SearchInput->multipv) { send("info depth %d seldepth %d time %.0f nodes " S64_FORMAT " nps %.0f",depth,SearchCurrent->max_depth,SearchCurrent->time*1000.0,SearchCurrent->node_nb,SearchCurrent->speed); } // update search info if (depth >= 1) SearchInfo->can_stop = true; if (depth == 1 && LIST_SIZE(SearchRoot->list) >= 2 && LIST_VALUE(SearchRoot->list,0) >= LIST_VALUE(SearchRoot->list,1) + EasyThreshold) { SearchRoot->easy = true; } if (depth > 1) { SearchRoot->bad_2 = SearchRoot->bad_1; SearchRoot->bad_1 = false; ASSERT(SearchRoot->bad_2==(SearchBest->value<=SearchRoot->last_value-BadThreshold)); } SearchRoot->last_value = SearchBest[SearchCurrent->multipv].value; // stop search? if (SearchInput->depth_is_limited && SearchCurrent->multipv >= SearchInput->multipv && depth >= SearchInput->depth_limit) { SearchRoot->flag = true; } if (SearchInput->time_is_limited && SearchCurrent->time * 2 >= SearchInput->time_limit_1 && !SearchRoot->bad_2) { SearchRoot->flag = true; } if (SearchInput->time_is_limited && SearchCurrent->time >= SearchInput->time_limit_1 * EasyRatio && SearchRoot->easy) { ASSERT(!SearchRoot->bad_2); ASSERT(!SearchRoot->change); SearchRoot->flag = true; } if (SearchInput->time_is_limited && SearchCurrent->time >= SearchInput->time_limit_1 * EarlyRatio && !SearchRoot->bad_2 && !SearchRoot->change) { SearchRoot->flag = true; } if (SearchInfo->can_stop && (SearchInfo->stop || (SearchRoot->flag && !SearchInput->infinite))) { search_ready = true; break; } } if (search_ready) break; } }
void lslinit_process (void) /*@globals undef g_symtab; @*/ /*@modifies g_symtab, internalState, fileSystem; @*/ { /* ** Open init file provided by user, or use the default LCL init file */ cstring larchpath = context_getLarchPath (); inputStream initstream = inputStream_undefined; setCodePoint (); if (inputStream_isUndefined (s_initFile)) { s_initFile = inputStream_create (cstring_makeLiteral (INITFILENAME), cstring_makeLiteralTemp (LCLINIT_SUFFIX), FALSE); if (!inputStream_getPath (larchpath, s_initFile)) { lldiagmsg (message ("Continuing without LCL init file: %s", inputStream_fileName (s_initFile))); } else { if (!inputStream_open (s_initFile)) { lldiagmsg (message ("Continuing without LCL init file: %s", inputStream_fileName (s_initFile))); } } } else { if (!inputStream_open (s_initFile)) { lldiagmsg (message ("Continuing without LCL init file: %s", inputStream_fileName (s_initFile))); } } /* Initialize checker */ lsymbol_initMod (); LCLSynTableInit (); setCodePoint (); LCLSynTableReset (); LCLTokenTableInit (); setCodePoint (); LCLScanLineInit (); setCodePoint (); LCLScanLineReset (); setCodePoint (); LCLScanInit (); setCodePoint (); /* need this to initialize LCL checker */ llassert (inputStream_isDefined (s_initFile)); if (inputStream_isOpen (s_initFile)) { setCodePoint (); LCLScanReset (s_initFile); lclinit_initMod (); lclinit_reset (); setCodePoint (); lclinit_process (); lclinit_cleanup (); setCodePoint (); check (inputStream_close (s_initFile)); } /* Initialize LSL init files, for parsing LSL signatures from LSL */ initstream = inputStream_create (cstring_makeLiteral ("lslinit.lsi"), cstring_makeLiteralTemp (".lsi"), FALSE); if (!inputStream_getPath (larchpath, initstream)) { lldiagmsg (message ("Continuing without LSL init file: %s", inputStream_fileName (initstream))); } else { if (!inputStream_open (initstream)) { lldiagmsg (message ("Continuing without LSL init file: %s", inputStream_fileName (initstream))); } } setCodePoint (); lsynTableInit (); lsynTableReset (); setCodePoint (); ltokenTableInit (); setCodePoint (); lscanLineInit (); lscanLineReset (); LSLScanInit (); if (inputStream_isOpen (initstream)) { setCodePoint (); LSLScanReset (initstream); lslinit_initProcessInitFile (); lslinit_processInitFile (); check (inputStream_close (initstream)); } inputStream_free (initstream); if (lclHadError ()) { lclplainerror (cstring_makeLiteral ("LSL init file error. Attempting to continue.")); } setCodePoint (); g_symtab = symtable_new (); /* ** sort_init must come after symtab has been initialized */ sort_init (); abstract_init (); setCodePoint (); /* ** Equivalent to importing old spec_csupport.lcl ** define immutable LCL type "bool" and bool constants TRUE and FALSE ** and initialized them to be equal to LSL's "true" and "false". ** ** Reads in CTrait.syms (derived from CTrait.lsl) on LARCH_PATH. */ LCLBuiltins (); LCLReportEolTokens (FALSE); }
int main(int argc, char **argv) { INIT_GLB_VARS(); SET_PROCESS_ROLE(PROCESS_ROLE_MASTER); SET_CHILD_PROCESS(PROCESS_ROLE_MASTER, getpid()); /* 此处注册清理函数, 以便主进程由于某些原因退出时, kill掉 * 启动的所有子进程. 但man atexit可知, 通过fork的子进程会 * 继承atexit的注册链, 而exec后将抛弃此注册链. * <NOTE> 此处不考虑fork子进程也执行此函数带来的影响 */ (void)atexit(kill_child_all); if (log_init() == RET_ERR) { SDNS_LOG_ERR("LOG init failed"); exit(EXIT_FAILURE); } if (zone_init() == RET_ERR) { SDNS_LOG_ERR("ZONE init failed"); exit(EXIT_FAILURE); } if (get_options(argc, argv) == RET_ERR) { SDNS_LOG_ERR("parse cmdline failed"); usage_help(); exit(EXIT_FAILURE); } if (IS_PROCESS_ROLE(PROCESS_ROLE_SIGNALLER)) { process_option_signal(); exit(EXIT_SUCCESS); } if (IS_PROCESS_ROLE(PROCESS_ROLE_HELPER)) { usage_help(); exit(EXIT_SUCCESS); } if (start_monitor() == RET_ERR) { exit(EXIT_FAILURE); } if (parse_conf() == RET_ERR) { exit(EXIT_FAILURE); } if (IS_PROCESS_ROLE(PROCESS_ROLE_TESTER)) { SDNS_LOG_DEBUG("配置文件测试OK"); print_parse_res(); exit(EXIT_SUCCESS); } if (pkt_engine_init() == RET_ERR) { SDNS_LOG_ERR("engine init failed"); exit(EXIT_FAILURE); } if (set_required_signal() == RET_ERR || block_required_signal() == RET_ERR) { SDNS_LOG_ERR("signal init failed"); exit(EXIT_FAILURE); } if (sort_init() == RET_ERR) { SDNS_LOG_ERR("sort init failed"); exit(EXIT_FAILURE); } start_worker(); if (start_pkt_engine() == RET_ERR) { SDNS_LOG_ERR("start engine failed"); exit(EXIT_FAILURE); } for(;;) { (void)wait_required_signal(); (void)process_signals(); } exit(EXIT_SUCCESS); }
static int full_no_null(board_t * board, int alpha, int beta, int depth, int height, mv_t pv[], int node_type, int trans_move, int * best_move) { int value, best_value; int move; int new_depth; attack_t attack[1]; sort_t sort[1]; undo_t undo[1]; mv_t new_pv[HeightMax]; ASSERT(board!=NULL); ASSERT(range_is_ok(alpha,beta)); ASSERT(depth_is_ok(depth)); ASSERT(height_is_ok(height)); ASSERT(pv!=NULL); ASSERT(node_type==NodePV||node_type==NodeCut||node_type==NodeAll); ASSERT(trans_move==MoveNone||move_is_ok(trans_move)); ASSERT(best_move!=NULL); ASSERT(board_is_legal(board)); ASSERT(!board_is_check(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--; PV_CLEAR(pv); if (height > SearchCurrent->max_depth) SearchCurrent->max_depth = height; if (SearchInfo->check_nb <= 0) { SearchInfo->check_nb += SearchInfo->check_inc; search_check(); } attack_set(attack,board); ASSERT(!ATTACK_IN_CHECK(attack)); *best_move = MoveNone; best_value = ValueNone; // move loop sort_init(sort,board,attack,depth,height,trans_move); while ((move=sort_next(sort)) != MoveNone) { SearchStack[height].move = move; new_depth = full_new_depth(depth,move,board,false,false,false,height); move_do(board,move,undo); value = -full_search(board,-beta,-alpha,new_depth,height+1,new_pv,NODE_OPP(node_type)); move_undo(board,move,undo); if (value > best_value) { best_value = value; pv_cat(pv,new_pv,move); if (value > alpha) { alpha = value; *best_move = move; SearchStack[height].best_move = move; if (value >= beta) goto cut; } } } // ALL node if (best_value == ValueNone) { // no legal move => stalemate ASSERT(board_is_stalemate(board)); best_value = ValueDraw; } cut: ASSERT(value_is_ok(best_value)); return best_value; }
static int full_search(board_t * board, int alpha, int beta, int depth, int height, mv_t pv[], int node_type) { bool in_check; bool single_reply; bool mate_threat; int trans_move, trans_depth, trans_min_depth, trans_max_depth, trans_min_value, trans_max_value; int min_value, max_value; int old_alpha; int value, best_value; int move, best_move; int new_depth; int played_nb; int i; int opt_value; bool reduced; int mb; attack_t attack[1]; sort_t sort[1]; undo_t undo[1]; mv_t new_pv[HeightMax]; mv_t played[256]; int FutilityMargin; ASSERT(board!=NULL); ASSERT(range_is_ok(alpha,beta)); ASSERT(depth_is_ok(depth)); ASSERT(height_is_ok(height)); ASSERT(pv!=NULL); ASSERT(node_type==NodePV||node_type==NodeCut||node_type==NodeAll); ASSERT(board_is_legal(board)); // horizon? if (depth <= 0){ if (node_type == NodePV) CheckDepth = 1 - CheckNb - 1; else CheckDepth = 1 - CheckNb; return full_quiescence(board,alpha,beta,0,height,pv); } // init SearchStack[height].best_move = MoveNone; SearchStack[height].move = MoveNone; SearchStack[height].threat_move = MoveNone; SearchStack[height].reduced = false; mate_threat = false; SearchCurrent->node_nb++; SearchInfo->check_nb--; PV_CLEAR(pv); if (height > SearchCurrent->max_depth) SearchCurrent->max_depth = height; if (SearchInfo->check_nb <= 0) { SearchInfo->check_nb += SearchInfo->check_inc; search_check(); } // draw? if (board_is_repetition(board) || recog_draw(board)) return ValueDraw; // mate-distance pruning if (UseDistancePruning) { // lower bound value = VALUE_MATE(height+2); // does not work if the current position is mate if (value > alpha && board_is_mate(board)) value = VALUE_MATE(height); if (value > alpha) { alpha = value; if (value >= beta) return value; } // upper bound value = -VALUE_MATE(height+1); if (value < beta) { beta = value; if (value <= alpha) return value; } } // transposition table trans_move = MoveNone; if (UseTrans && depth >= TransDepth) { if (trans_retrieve(Trans,board->key,&trans_move,&trans_min_depth,&trans_max_depth,&trans_min_value,&trans_max_value)) { // trans_move is now updated if (node_type != NodePV) { if (UseMateValues) { if (trans_min_value > +ValueEvalInf && trans_min_depth < depth) { trans_min_depth = depth; } if (trans_max_value < -ValueEvalInf && trans_max_depth < depth) { trans_max_depth = depth; } } min_value = -ValueInf; if (DEPTH_MATCH(trans_min_depth,depth)) { min_value = value_from_trans(trans_min_value,height); if (min_value >= beta) return min_value; } max_value = +ValueInf; if (DEPTH_MATCH(trans_max_depth,depth)) { max_value = value_from_trans(trans_max_value,height); if (max_value <= alpha) return max_value; } if (min_value == max_value) return min_value; // exact match } } } // height limit if (height >= HeightMax-1) return eval(board, alpha, beta); // more init old_alpha = alpha; best_value = ValueNone; best_move = MoveNone; played_nb = 0; attack_set(attack,board); in_check = ATTACK_IN_CHECK(attack); // null-move pruning if (UseNull && depth >= NullDepth && node_type != NodePV) { if (!in_check && !value_is_mate(beta) && do_null(board) && (!UseNullEval || depth <= NullReduction+1 || eval(board,alpha, beta) >= beta)) { // null-move search new_depth = depth - NullReduction - 1; //new_depth = depth - R_adpt(board->piece_size[board->turn]+board->pawn_size[board->turn],depth,NullReduction) - 1; move_do_null(board,undo); value = -full_search(board,-beta,-beta+1,new_depth,height+1,new_pv,NODE_OPP(node_type)); move_undo_null(board,undo); // verification search if (UseVer && depth > VerReduction) { if (value >= beta && (!UseVerEndgame || do_ver(board))) { new_depth = depth - VerReduction; ASSERT(new_depth>0); value = full_no_null(board,alpha,beta,new_depth,height,new_pv,NodeCut,trans_move,&move); if (value >= beta) { ASSERT(move==new_pv[0]); played[played_nb++] = move; best_move = move; SearchStack[height].move = move; SearchStack[height].best_move = move; best_value = value; pv_copy(pv,new_pv); goto cut; } } } // pruning if (value >= beta) { if (value > +ValueEvalInf) value = +ValueEvalInf; // do not return unproven mates ASSERT(!value_is_mate(value)); // pv_cat(pv,new_pv,MoveNull); best_move = MoveNone; best_value = value; goto cut; } SearchStack[height].threat_move = SearchStack[height+1].best_move; /* if (SearchStack[height-1].reduced){ // Idea by Tord Romstad if (MOVE_FROM(SearchStack[height+1].best_move) == MOVE_TO(SearchStack[height-1].move)) return alpha-1; */ /* if(((MOVE_TO(SearchStack[height - 2].threat_move) == MOVE_FROM(SearchStack[height - 2].move)) && (MOVE_TO(SearchStack[height].threat_move) == MOVE_TO(SearchStack[height - 2].move))) || ((MOVE_TO(SearchStack[height - 2].threat_move) != MOVE_FROM(SearchStack[height - 2].move)) && (MOVE_TO(SearchStack[height].threat_move) == MOVE_TO(SearchStack[height - 2].threat_move)))) return alpha-1; */ // } } } // mate threat /* mate_threat = false; if (value <= VALUE_MATE(height+2)){ mate_threat = true; } */ // Internal Iterative Deepening if (UseIID && depth >= IIDDepth && node_type == NodePV && trans_move == MoveNone) { // new_depth = depth - IIDReduction; new_depth = MIN(depth - IIDReduction,depth/2); ASSERT(new_depth>0); value = full_search(board,alpha,beta,new_depth,height,new_pv,node_type); if (value <= alpha) value = full_search(board,-ValueInf,beta,new_depth,height,new_pv,node_type); trans_move = new_pv[0]; } // move generation sort_init(sort,board,attack,depth,height,trans_move); single_reply = false; if (in_check && LIST_SIZE(sort->list) == 1) single_reply = true; // HACK // move loop opt_value = +ValueInf; while ((move=sort_next(sort)) != MoveNone) { SearchStack[height].move = move; // history_tried(move,board); // extensions new_depth = full_new_depth(depth,move,board,single_reply,mate_threat,node_type==NodePV, height); // futility pruning if (UseFutility && depth <= 2 && node_type != NodePV) { if (!in_check && new_depth < depth && !move_is_tactical(move,board) && !move_is_dangerous(move,board)) { ASSERT(!move_is_check(move,board)); // optimistic evaluation if (opt_value == +ValueInf) { if (depth==2){ FutilityMargin = FutilityMargin2; } else{ FutilityMargin = FutilityMargin1; } opt_value = eval(board,alpha,beta) + FutilityMargin; ASSERT(opt_value<+ValueInf); } value = opt_value; // pruning if (value <= alpha) { if (value > best_value) { best_value = value; PV_CLEAR(pv); } continue; } } } // history pruning /* reduced = false; if (UseHistory && depth >= HistoryDepth && node_type != NodePV) { if (!in_check && played_nb >= HistoryMoveNb && new_depth < depth) { ASSERT(best_value!=ValueNone); ASSERT(played_nb>0); ASSERT(sort->pos>0&&move==LIST_MOVE(sort->list,sort->pos-1)); if (history_reduction(move,board) == true) { ASSERT(value>=0&&value<16384); ASSERT(move!=trans_move); ASSERT(!move_is_tactical(move,board)); ASSERT(!move_is_check(move,board)); new_depth--; reduced = true; } } } */ // history pruning reduced = false; value = sort->value; // history score if (!in_check && depth < SearchCurrent->max_extensions / 2 && node_type != NodePV && new_depth < depth && value < HistoryValue / depth) continue; if (UseHistory && depth >= HistoryDepth && node_type != NodePV) { if (!in_check && played_nb >= HistoryMoveNb && new_depth < depth) { ASSERT(best_value!=ValueNone); ASSERT(played_nb>0); ASSERT(sort->pos>0&&move==LIST_MOVE(sort->list,sort->pos-1)); value = sort->value; // history score if (value < HistoryValue) { ASSERT(value>=0&&value<16384); ASSERT(move!=trans_move); ASSERT(!move_is_tactical(move,board)); ASSERT(!move_is_check(move,board)); new_depth--; reduced = true; if (UseExtendedHistory && value < HistoryValue / 2 && depth >= 8){ new_depth--; } } } } SearchStack[height].reduced = reduced; // recursive search move_do(board,move,undo); if (node_type != NodePV || best_value == ValueNone) { // first move value = -full_search(board,-beta,-alpha,new_depth,height+1,new_pv,NODE_OPP(node_type)); } else { // other moves value = -full_search(board,-alpha-1,-alpha,new_depth,height+1,new_pv,NodeCut); if (value > alpha) { // && value < beta value = -full_search(board,-beta,-alpha,new_depth,height+1,new_pv,NodePV); } } // history-pruning re-search if (HistoryReSearch && reduced && value > alpha /* was >= beta */) { ASSERT(node_type!=NodePV); //history_very_bad(move,board); SearchStack[height].reduced = false; new_depth++; ASSERT(new_depth==depth-1); value = -full_search(board,-beta,-alpha,new_depth,height+1,new_pv,NODE_OPP(node_type)); } move_undo(board,move,undo); played[played_nb++] = move; if (value > best_value) { best_value = value; pv_cat(pv,new_pv,move); if (value > alpha) { alpha = value; best_move = move; SearchStack[height].best_move = move; if (value >= beta){ // history_success(move,board); goto cut; } } } if (node_type == NodeCut) node_type = NodeAll; } // ALL node if (best_value == ValueNone) { // no legal move if (in_check) { ASSERT(board_is_mate(board)); return VALUE_MATE(height); } else { ASSERT(board_is_stalemate(board)); return ValueDraw; } } cut: ASSERT(value_is_ok(best_value)); // move ordering if (best_move != MoveNone) { good_move(best_move,board,depth,height); if (best_value >= beta && !move_is_tactical(best_move,board)) { ASSERT(played_nb>0&&played[played_nb-1]==best_move); for (i = 0; i < played_nb-1; i++) { move = played[i]; ASSERT(move!=best_move); history_bad(move,board); } history_good(best_move,board); } } // transposition table if (UseTrans && depth >= TransDepth) { trans_move = best_move; trans_depth = depth; trans_min_value = (best_value > old_alpha) ? value_to_trans(best_value,height) : -ValueInf; trans_max_value = (best_value < beta) ? value_to_trans(best_value,height) : +ValueInf; trans_store(Trans,board->key,trans_move,trans_depth,trans_min_value,trans_max_value); } return best_value; }
static int full_search(board_t * board, int alpha, int beta, int depth, int height, mv_t pv[], int node_type, bool extended, int ThreadId) { bool in_check; bool single_reply; bool good_cap; int trans_move, trans_depth, trans_flags, trans_value; int old_alpha; int value, best_value; int move, best_move; int new_depth; int played_nb; int i; int opt_value; bool reduced, cap_extended; attack_t attack[1]; sort_t sort[1]; undo_t undo[1]; mv_t new_pv[HeightMax]; mv_t played[256]; int FutilityMargin; int probe_score, probe_depth; int newHistoryValue; int threshold; int reduction; int last_move; int quiet_move_count; entry_t * found_entry; ASSERT(board!=NULL); ASSERT(range_is_ok(alpha,beta)); ASSERT(depth_is_ok(depth)); ASSERT(height_is_ok(height)); ASSERT(pv!=NULL); ASSERT(node_type==NodePV||node_type==NodeCut||node_type==NodeAll); ASSERT(board_is_legal(board)); // horizon? if (depth <= 0){ if (node_type == NodePV) SearchCurrent[ThreadId]->CheckDepth = 1 - SearchCurrent[ThreadId]->CheckNb - 1; else SearchCurrent[ThreadId]->CheckDepth = 1 - SearchCurrent[ThreadId]->CheckNb; return full_quiescence(board,alpha,beta,0,height,pv,ThreadId); } // init SearchCurrent[ThreadId]->node_nb++; SearchInfo[ThreadId]->check_nb--; PV_CLEAR(pv); if (height > SearchCurrent[ThreadId]->max_depth) SearchCurrent[ThreadId]->max_depth = height; if (SearchInfo[ThreadId]->check_nb <= 0) { SearchInfo[ThreadId]->check_nb += SearchInfo[ThreadId]->check_inc; search_check(ThreadId); } // draw? if (board_is_repetition(board)) return ValueDraw; /* Interior node recognizer from scorpio by Daniel Shawul -> dont probe at the leaves as this will slow down search For 4/3 pieces probe there also. -> After captures and pawn moves assume exact score and cutoff tree, because we are making progress. Note this is not done only for speed. -> if we are far from root (depth / 2), assume exact score and cutoff tree */ // if (egbb_is_loaded && board->piece_nb <= 5){ // probe_depth = (2 * SearchCurrent[ThreadId]->act_iteration) / 3; // if ((board->piece_nb <=4 || height <= probe_depth) // && (height >= probe_depth // || board->cap_sq != SquareNone || PIECE_IS_PAWN(board->moving_piece)) // ) { // // if (probe_bitbases(board, probe_score)){ // if (probe_score < 0 && board_is_mate(board)) return VALUE_MATE(height); // probe_score = value_from_trans(probe_score,height); // /* trans_move = MoveNone; // trans_depth = depth; // trans_flags = TransUnknown; // if (probe_score > alpha) trans_flags |= TransLower; // if (probe_score < beta) trans_flags |= TransUpper; // trans_store(Trans,board->key,trans_move,trans_depth,trans_flags,probe_score);*/ // return probe_score; // } // } // } if (recog_draw(board,ThreadId)) return ValueDraw; // mate-distance pruning if (UseDistancePruning) { // lower bound value = VALUE_MATE(height+2); // does not work if the current position is mate if (value > alpha && board_is_mate(board)) value = VALUE_MATE(height); if (value > alpha) { alpha = value; if (value >= beta) return value; } // upper bound value = -VALUE_MATE(height+1); if (value < beta) { beta = value; if (value <= alpha) return value; } } // transposition table trans_move = MoveNone; if (UseTrans && depth >= TransDepth) { if (trans_retrieve(Trans,&found_entry,board->key,&trans_move,&trans_depth,&trans_flags,&trans_value)) { // trans_move is now updated /* if (found_entry->depth != trans_depth){ found_entry->depth = trans_depth; }*/ if (node_type != NodePV /*|| ThreadId > 0*/) { if (UseMateValues) { if (trans_depth < depth) { if (trans_value < -ValueEvalInf && TRANS_IS_UPPER(trans_flags)) { trans_depth = depth; trans_flags = TransUpper; } else if (trans_value > +ValueEvalInf && TRANS_IS_LOWER(trans_flags)) { trans_depth = depth; trans_flags = TransLower; } } if (trans_depth >= depth) { trans_value = value_from_trans(trans_value,height); if ((UseExact && TRANS_IS_EXACT(trans_flags)) || (TRANS_IS_LOWER(trans_flags) && trans_value >= beta) || (TRANS_IS_UPPER(trans_flags) && trans_value <= alpha)) { return trans_value; } /* if (TRANS_IS_EXACT(trans_flags)) return trans_value; if (TRANS_IS_LOWER(trans_flags)) { if (trans_value >= beta) return trans_value; if (trans_value > alpha) alpha = trans_value; } if (TRANS_IS_UPPER(trans_flags)) { if (trans_value <= alpha) return trans_value; if (trans_value < beta) beta = trans_value; } */ } } } } } // height limit if (height >= HeightMax-1) return eval(board, alpha, beta, ThreadId); // more init old_alpha = alpha; best_value = ValueNone; best_move = MoveNone; played_nb = 0; last_move = SearchCurrent[ThreadId]->last_move; attack_set(attack,board); in_check = ATTACK_IN_CHECK(attack); // null-move pruning if (UseNull && depth >= NullDepth && node_type != NodePV && !(trans_move != MoveNone && TRANS_IS_UPPER(trans_flags) && trans_depth >= depth - NullReduction - depth/4 && trans_value < beta)) { // if hash table tells us we are < beta, the null move search probably wastes time // bugfix 25-3-2013 (trans_move condition added) was LOS ~90%, + 10 elo. Probably not nearly that good but it's a bugfix...) if (!in_check && !value_is_mate(beta) && do_null(board) && (!UseNullEval || depth <= NullReduction+1 || eval(board,alpha, beta, ThreadId) >= beta)) { // null-move search // if (depth < 11) new_depth = depth - NullReduction - depth/4; // JD: from Stockfish, 10 elo better // else // new_depth = depth - NullReduction - 2; //new_depth = depth - R_adpt(board->piece_size[board->turn]+board->pawn_size[board->turn],depth,NullReduction) - 1; move_do_null(board,undo); SearchCurrent[ThreadId]->last_move = MoveNone; // refutation table value = -full_search(board,-beta,-beta+1,new_depth,height+1,new_pv,NODE_OPP(node_type),false,ThreadId); move_undo_null(board,undo); // pruning if (value >= beta) { if (value > +ValueEvalInf) value = +ValueEvalInf; // do not return unproven mates ASSERT(!value_is_mate(value)); // pv_cat(pv,new_pv,MoveNull); best_move = MoveNone; best_value = value; goto cut; } } } // Razoring: idea by Tord Romstad (Glaurung), fixed by Jerry Donald if (node_type != NodePV && !in_check && trans_move == MoveNone && depth <= 3){ threshold = beta - RazorMargin - (depth-1)*39; // Values from Protector (Raimund Heid) if (eval(board,threshold-1, threshold, ThreadId) < threshold){ value = full_quiescence(board,threshold-1,threshold,0,height,pv,ThreadId); if (value < threshold) // corrected - was < beta which is too risky at depth > 1 return value; } } // Internal Iterative Deepening if (UseIID && depth >= IIDDepth && node_type == NodePV && trans_move == MoveNone) { new_depth = MIN(depth - IIDReduction,depth/2); ASSERT(new_depth>0); value = full_search(board,alpha,beta,new_depth,height,new_pv,node_type,false,ThreadId); if (value <= alpha) value = full_search(board,-ValueInf,beta,new_depth,height,new_pv,node_type,false,ThreadId); trans_move = new_pv[0]; } // move generation sort_init(sort,board,attack,depth,height,trans_move,last_move,ThreadId); single_reply = false; if (in_check && LIST_SIZE(sort->list) == 1) single_reply = true; // HACK // move loop opt_value = +ValueInf; good_cap = true; quiet_move_count = 0; while ((move=sort_next(sort,ThreadId)) != MoveNone) { // extensions new_depth = full_new_depth(depth,move,board,single_reply,node_type==NodePV, height, extended, &cap_extended, ThreadId); // history pruning value = sort->value; // history score if (!in_check && depth <= 6 && node_type != NodePV && new_depth < depth && value < 2 * HistoryValue / (depth + depth % 2) /*2*/ && played_nb >= 1+depth && !move_is_dangerous(move,board)){ continue; } // futility pruning if (UseFutility && node_type != NodePV && depth <= 5) { if (!in_check && new_depth < depth&& !move_is_tactical(move,board) && !move_is_dangerous(move,board)) { ASSERT(!move_is_check(move,board)); // move count based pruning (added by Jerry Donald: ~+20 elo!) if (quiet_move_count >= MoveCountLimit[depth])continue; quiet_move_count++; // optimistic evaluation (Chris Formula) if (opt_value == +ValueInf) { if (depth>=2){ FutilityMargin = FutilityMargin2 + (depth % 2) * 100; } else{ FutilityMargin = FutilityMargin1; } opt_value = eval(board,alpha-FutilityMargin,alpha,ThreadId) + FutilityMargin; ASSERT(opt_value<+ValueInf); } value = opt_value; // pruning if (value <= alpha) { if (value > best_value) { best_value = value; PV_CLEAR(pv); } continue; } } } // Late Move Reductions // init reduced = false; reduction = 0; // lookup reduction if (UseHistory) { if (!in_check && new_depth < depth && played_nb >= HistoryMoveNb && depth >= HistoryDepth && !move_is_dangerous(move,board)) { if (good_cap && !move_is_tactical(move,board)){ good_cap = false; } if (!good_cap){ reduction = (node_type == NodePV ? quietPvMoveReduction[depth<64 ? depth: 63][played_nb<64? played_nb: 63]: quietMoveReduction[depth<64 ? depth: 63][played_nb<64? played_nb: 63]); // reduced bad captures less if (move_is_tactical(move,board)) reduction = reduction / 2; // bad captures // set reduction flag if (reduction > 0) reduced = true; } } } // recursive search move_do(board,move,undo); SearchCurrent[ThreadId]->last_move = move; if (node_type != NodePV || best_value == ValueNone) { // first move or non-pv value = -full_search(board,-beta,-alpha,new_depth-reduction,height+1,new_pv,NODE_OPP(node_type),cap_extended,ThreadId); // The move was reduced and fails high; so we research with full depth if (reduced && value >= beta){ value = -full_search(board,-beta,-alpha,new_depth,height+1,new_pv,NODE_OPP(node_type),cap_extended,ThreadId); } } else { // other moves (all PV children) value = -full_search(board,-alpha-1,-alpha,new_depth-reduction,height+1,new_pv,NodeCut,cap_extended,ThreadId); // In case of fail high: // If reduced then we try a research with node_type = NodePV if (value > alpha && reduced){ // && value < beta value = -full_search(board,-beta,-alpha,new_depth-reduction,height+1,new_pv,NodePV,cap_extended,ThreadId); // Still fails high! We research to full depth if (reduced && value >= beta){ value = -full_search(board,-beta,-alpha,new_depth,height+1,new_pv,NodePV,cap_extended,ThreadId); } // If not reduced we research as a PV node } else if (value > alpha){ value = -full_search(board,-beta,-alpha,new_depth,height+1,new_pv,NodePV,cap_extended,ThreadId); } } move_undo(board,move,undo); played[played_nb++] = move; if (value > best_value) { best_value = value; pv_cat(pv,new_pv,move); if (value > alpha) { alpha = value; best_move = move; if (value >= beta){ goto cut; } } } if (node_type == NodeCut) node_type = NodeAll; } // ALL node if (best_value == ValueNone) { // no legal move if (in_check) { ASSERT(board_is_mate(board)); return VALUE_MATE(height); } else { ASSERT(board_is_stalemate(board)); return ValueDraw; } } cut: ASSERT(value_is_ok(best_value)); // move ordering if (best_move != MoveNone) { good_move(best_move,board,depth,height,ThreadId); if (best_value >= beta && !move_is_tactical(best_move,board)) { // check is 204b and d, e // refutation table ~5 elo if (last_move != MoveNull && last_move != MoveNone)refutation_update(best_move, last_move, board, ThreadId); ASSERT(played_nb>0&&played[played_nb-1]==best_move); for (i = 0; i < played_nb-1; i++) { move = played[i]; ASSERT(move!=best_move); history_bad(move,board,ThreadId); bad_move(move,board,depth,height,ThreadId); // added JD ~ 5 elo } history_good(best_move,board,ThreadId); } } // transposition table if (UseTrans && depth >= TransDepth) { trans_move = best_move; trans_depth = depth; trans_flags = TransUnknown; if (best_value > old_alpha) trans_flags |= TransLower; if (best_value < beta) trans_flags |= TransUpper; trans_value = value_to_trans(best_value,height); trans_store(Trans,board->key,trans_move,trans_depth,trans_flags,trans_value); } return best_value; }