/* 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; }
void game_make_move_str(char *move_str, int ui_update) { board_t new_board = *history->last->board; move_t *engine_move; DBG_LOG("Parsing move string '%s'", move_str); engine_move = san_to_move(&new_board, move_str); if (!engine_move) engine_move = fullalg_to_move(&new_board, move_str); if (engine_move) { game_make_move(engine_move, ui_update); free(engine_move); } else DBG_ERROR("Failed to parse move string '%s'", move_str); }
/* Read a PGN file (a collection of one or more games in PGN format) and store the positions and their win/loss ratios in an AVL tree (**tree). The AVL tree can later be written in an opening book file (book.bin). Returns the number of new positions added to the tree, or -1 on error. */ int pgn_to_tree(const char *filename, AvlNode **tree) { PgnResult result; int prev_progress; int npos = 0; long file_len; FILE *fp; Board board; ASSERT(1, filename != NULL); if ((fp = fopen(filename, "r")) == NULL) { my_perror("Can't open PGN file %s", filename); return -1; } if (settings.book_type != BOOK_MEM) { settings.book_type = BOOK_MEM; printf("Changed book mode to \"book in memory\"\n"); } if (*tree == NULL && file_exists(settings.book_file)) { printf("Loading opening book to memory...\n"); book_to_tree(settings.book_file, tree); } else if (*tree == NULL) printf("Creating a new opening book...\n"); /* Find out how big the file is. */ fseek(fp, 0, SEEK_END); file_len = ftell(fp); rewind(fp); printf("Reading PGN file %s...\n", filename); prev_progress = 0; progressbar(50, 0); while ((result = get_pgn_result(fp)) != RESULT_ERROR) { int depth; int progress; int len; char san_move[MAX_BUF]; /* Games with an unknown result are ignored. */ ASSERT(1, result != RESULT_ERROR); if (result == NO_RESULT || result == DRAWN_GAME) continue; depth = 0; fen_to_board(&board, START_FEN); while ((len = read_move(san_move, MAX_BUF, fp)) >= 0) { int points = 0; U32 move; /* break out of the loop when a new game begins */ if (depth > 0 && san_move[0] == '[') break; if (len < 2) continue; move = san_to_move(&board, san_move); if (move == NULLMOVE) { #if DEBUG_LEVEL > 0 update_log("Illegal move in %s: %s, line: %d\n", filename, san_move, get_line_num(fp)); #endif /* DEBUG_LEVEL > 0 */ break; } if ((result == WHITE_WINS && board.color == WHITE) || (result == BLACK_WINS && board.color == BLACK)) points = 2; make_move(&board, move); if (save_book_pos(board.posp->key, points, tree)) npos++; if (++depth >= MAX_BOOK_PLIES) break; } progress = (ftell(fp) * 50) / file_len; if (progress > prev_progress) { progressbar(50, progress); prev_progress = progress; } } progressbar(50, 50); my_close(fp, filename); printf("\n"); return npos; }
int main(int argc, char **argv) { cl_options_t cl_options = {0}; dbg_init(); DBG_LOG("Version %s", g_version); ui = &ui_sdlgl; printf("DreamChess %s\n", g_version); parse_options(argc, argv, &ui, &cl_options); config_init(); set_cl_options(&cl_options); if (!ui) { DBG_ERROR("Failed to find a user interface driver"); exit(1); } ui->init(); init_resolution(); while (1) { board_t board; int pgn_slot; option_t *option; if (!(config = ui->config(&pgn_slot))) break; ch_userdir(); option = config_get_option("first_engine"); #ifdef __APPLE__ char temp1[200]; char temp2[200]; if (!strcmp(option->string, "dreamer") || !strcmp(option->string, "Dreamer")) { CFBundleRef mainBundle = CFBundleGetMainBundle(); CFURLRef bundledir = CFBundleCopyBundleURL(mainBundle); CFStringRef stringref = CFURLCopyFileSystemPath(bundledir, kCFURLPOSIXPathStyle); CFStringGetCString(stringref, temp1, 200, kCFStringEncodingMacRoman); snprintf(temp2, sizeof(temp2), "%s/contents/MacOS/dreamer", temp1); game_set_engine_error(comm_init(temp2)); } else game_set_engine_error(comm_init(option->string)); #else game_set_engine_error(comm_init(option->string)); #endif comm_send("xboard\n"); comm_send("new\n"); comm_send("random\n"); comm_send("sd %i\n", config->cpu_level); comm_send("depth %i\n", config->cpu_level); if (config->difficulty == 0) comm_send("noquiesce\n"); if (config->player[WHITE] == PLAYER_UI && config->player[BLACK] == PLAYER_UI) comm_send("force\n"); if (config->player[WHITE] == PLAYER_ENGINE) comm_send("go\n"); in_game = 1; board_setup(&board); history = history_init(&board); move_list_init(&san_list); move_list_init(&fan_list); move_list_init(&fullalg_list); if (pgn_slot >= 0) if (game_load(pgn_slot)) { DBG_ERROR("Failed to load savegame in slot %i", pgn_slot); exit(1); } ui->update(history->view->board, NULL); while (in_game) { char *s; if ((s = comm_poll())) { DBG_LOG("Message from engine: '%s'", s); if (!history->result) { if ((!strncmp(s, "move ", 4) || strstr(s, "... ")) && config->player[history->last->board->turn] == PLAYER_ENGINE) { char *move_str = strrchr(s, ' ') + 1; board_t new_board = *history->last->board; move_t *engine_move; DBG_LOG("Parsing move string '%s'", move_str); engine_move = san_to_move(&new_board, move_str); if (!engine_move) engine_move = fullalg_to_move(&new_board, move_str); if (engine_move) { audio_play_sound(AUDIO_MOVE); do_move(engine_move, 1); free(engine_move); } else DBG_ERROR("Failed to parse move string '%s'", move_str); } else if (strstr(s, "llegal move")) game_undo(); /* Ignore result message if we've already determined a result ourselves. */ else { char *start = strchr(s, '{'); char *end = strchr(s, '}'); if (start && end && end > start) { char *comment = malloc(end - start); history->result = malloc(sizeof(result_t)); strncpy(comment, start + 1, end - start - 1); comment[end - start - 1] = '\0'; history->result->reason = comment; if (strstr(s, "1-0")) { history->result->code = RESULT_WHITE_WINS; ui->show_result(history->result); } else if (strstr(s, "1/2-1/2")) { history->result->code = RESULT_DRAW; ui->show_result(history->result); } else if (strstr(s, "0-1")) { history->result->code = RESULT_BLACK_WINS; ui->show_result(history->result); } else { free(history->result->reason); free(history->result); history->result = NULL; } } } } free(s); } ui->poll(); } comm_send("quit\n"); comm_exit(); history_exit(history); move_list_exit(&san_list); move_list_exit(&fan_list); move_list_exit(&fullalg_list); } ui->exit(); dbg_exit(); return 0; }