void bench(void) { Chess chess; SearchData sd; S64 timer; int npos = 0; int nfen = (int)(sizeof(bench_fen) / sizeof(char*)); double avg_bfactor; double t_elapsed; double hhit_rate; U64 nnodes_all; /* num. of all nodes (main + qs) */ int nps; /* nodes (all types) per second */ int i; init_chess(&chess); init_search_data(&sd); chess.max_depth = 8; chess.increment = 60000; printf("Running benchmark at search depth %d...\n", chess.max_depth); timer = get_ms(); progressbar(nfen, 0); for (i = 0; i < nfen; i++) { const char *fen = bench_fen[i]; if (strlen(fen) <= 1) continue; if (!fen_to_board(&chess.board, fen)) { id_search(&chess, NULLMOVE); if (chess.sd.cmd_type != CMDT_CONTINUE) { printf("Benchmark cancelled by user\n"); return; } sd.nnodes += chess.sd.nnodes; sd.nqs_nodes += chess.sd.nqs_nodes; sd.nhash_probes += chess.sd.nhash_probes; sd.nhash_hits += chess.sd.nhash_hits; sd.bfactor += chess.sd.bfactor; npos++; progressbar(nfen, npos); } else printf("\nInvalid FEN string: %s\n", fen); } timer = get_ms() - timer; t_elapsed = timer / 1000.0; avg_bfactor = sd.bfactor / npos; hhit_rate = (sd.nhash_hits * 100.0) / sd.nhash_probes; nnodes_all = sd.nnodes + sd.nqs_nodes; nps = (double)nnodes_all / ((double)timer / 1000.0); printf("\n\nBenchmark finished in %.2f seconds.\n", t_elapsed); printf("Main nodes searched: %" PRIu64 "\n", sd.nnodes); printf("Quiescence nodes searched: %" PRIu64 "\n", sd.nqs_nodes); printf("Total nodes per second: %d\n", nps); printf("Average branching factor: %.2f\n", avg_bfactor); printf("Hash table hit rate: %.2f%%\n", hhit_rate); }
/* Choose the best move (by searching or using the book), and make it. */ static void cpu_move(Chess *chess) { bool book_used = false; char san_move[MAX_BUF]; char str_move[MAX_BUF]; U32 move = NULLMOVE; int score = 0; S64 timer; Board *board; ASSERT(1, chess != NULL); board = &chess->board; timer = get_ms(); chess->sd.cmd_type = CMDT_CONTINUE; if (settings.book_type != BOOK_OFF) move = get_book_move(board, chess->show_pv, chess->book); if (move != NULLMOVE) { book_used = true; chess->in_book = true; } else { score = id_search(chess, NULLMOVE); if (chess->sd.cmd_type == CMDT_CANCEL) { chess->cpu_color = COLOR_NONE; return; } move = chess->sd.move; chess->in_book = false; } timer = get_ms() - timer; ASSERT(1, move != NULLMOVE); move_to_str(move, str_move); if (SIGN(board->color)*score < VAL_RESIGN) { if (board->color == WHITE) printf("0-1 {White resigns}\n"); else printf("1-0 {Black resigns}\n"); chess->game_over = true; return; } printf("move %s\n", str_move); if (chess->debug && chess->sd.nnodes > 0) { print_search_data(&chess->sd, (int)timer); printf("Score: %d\n", score); } move_to_san(san_move, board, move); update_game_log(board, san_move, score, book_used); update_game(chess, move); }
PRIVATE struct id_rec *expand_getid() { struct id_rec *id; char *s = expand_getstr2(SQ_ID); if (s) { id = id_search(s); mem_free(s); } else id = NULL; return id; }
/* Run a test position (eg. WAC, ECM, WCSAC). Format of pos: <FEN> <"bm" or "am"> <move>; <position id>; - "bm" means <move> is the best move, "am" means <move> should be avoided - the move is in SAN notation - position id can be omitted - example: R7/P4k2/8/8/8/8/r7/6K1 w - - bm Rg8; id "WAC.018"; The time limit must be defined in <chess> before running the test. Returns -1 on error 0 for unsolved test 1 for solved test 2 for cancelled test */ int test_pos(Chess *chess, const char *pos) { char tmp_pos[MAX_BUF]; char *pos_item = NULL; char *svptr = NULL; U32 move; bool find_best; strlcpy(tmp_pos, pos, MAX_BUF); /* See if we're looking for the best move or avoiding a move. By doing that we'll also get to the end of the FEN string. */ if ((pos_item = strstr(tmp_pos, " bm ")) != NULL) find_best = true; else if ((pos_item = strstr(tmp_pos, " am ")) != NULL) { find_best = false; my_error("'Avoid move' positions not currently allowed"); return -1; } else return -1; *pos_item = 0; /* end of FEN string */ pos_item += 4; /* best move or move to avoid */ if (fen_to_board(&chess->board, tmp_pos)) return -1; /* Get the move string. */ if ((pos_item = strtok_r(pos_item, ";", &svptr)) == NULL) return -1; /* Some positions have a series of moves (a pv) as the solution. We only care about the first one, so make sure to pick just one. */ svptr = strchr(pos_item, ' '); if (svptr != NULL) *svptr = '\0'; move = san_to_move(&chess->board, pos_item); if (move == NULLMOVE) { printf("Illegal test solution: %s\n", pos_item); return -1; } id_search(chess, move); if (chess->sd.cmd_type != CMDT_CONTINUE) return 2; if (chess->sd.move == move) return 1; return 0; }
PUBLIC int lex_id(int sym) { register int i; strupr(yytext); for (i = 0; lexemetab[i].sym; i++) if (strcmp(yytext, lexemetab[i].txt) == 0) { yylval.inum = lexemetab[i].func; return lexemetab[i].sym; } yylval.id = id_search(yytext); return sym; }
/* Analyze mode for any supported chess protocol. */ void analyze_mode(Chess *chess) { CmdType *cmd_type; ASSERT(1, chess != NULL); cmd_type = &chess->sd.cmd_type; chess->cpu_color = COLOR_NONE; *cmd_type = CMDT_CONTINUE; while (chess->analyze) { if (!chess->game_over && *cmd_type != CMDT_CANCEL) { id_search(chess, NULLMOVE); /* If the maximum search depth is reached, there's no reason to search again until something changes. */ if (*cmd_type == CMDT_CONTINUE) *cmd_type = CMDT_CANCEL; } else { read_input(chess); *cmd_type = CMDT_CONTINUE; } } }