void do_log (const ExactSolution *const result, const GameTreeStack *const stack, const LogEnv *const log_env) { const NodeInfo* const c = stack->active_node; LogDataH log_data = { .sub_run_id = game_tree_log_def_sub_run_id, .call_id = result->node_count, .hash = c->hash, .parent_hash = (c - 1)->hash, .blacks = c->gpx.blacks, .whites = c->gpx.whites, .player = c->gpx.player, .json_doc = NULL, .json_doc_len = 0, .call_level = c - stack->nodes }; game_tree_log_write_h(log_env, &log_data); } /** * @cond */ /* * Internal functions. */ /** * @brief Verifies the filename. * * @param [in] filename the logging file name */ static void game_tree_log_filename_check (const gchar *const filename) { const gchar * const dirname = g_path_get_dirname(filename); if (!g_file_test(filename, G_FILE_TEST_EXISTS)) { game_tree_log_dirname_recursive_check(dirname); } else { if (g_file_test(filename, G_FILE_TEST_IS_REGULAR)) { printf("Logging regular file \"%s\" does exist, overwriting it.\n", filename); } else { printf("Logging file \"%s\" does exist, but it is a directory! Exiting with status -101.\n", filename); exit(-101); } } } /** * @brief Utility function used by game_tree_log_filename_check. * It recursively checks the subdirs in the filename path and creates them if are missing. * * @param [in] filename the directory path to be checked */ static void game_tree_log_dirname_recursive_check (const gchar * const filename) { const gchar * const dirname = g_path_get_dirname(filename); if (!g_file_test(filename, G_FILE_TEST_EXISTS)) { game_tree_log_dirname_recursive_check(dirname); g_mkdir(filename, 0755); } else { if (g_file_test(filename, G_FILE_TEST_IS_REGULAR)) { printf("The given \"%s\" path contains an existing file! Exiting with status -102.\n", filename); exit(-102); } } }
/* * Main recursive search function. */ static SearchNode * game_position_solve_impl (ExactSolution *const result, const GamePosition *const gp, const int achievable, const int cutoff, PVCell ***pve_parent_line_p) { result->node_count++; SearchNode *node = NULL; SearchNode *node2 = NULL; PVCell **pve_line = NULL; if (log_env->log_is_on) { call_count++; gp_hash_stack_fill_point++; LogDataH log_data; log_data.sub_run_id = 0; log_data.call_id = call_count; log_data.hash = game_position_hash(gp); gp_hash_stack[gp_hash_stack_fill_point] = log_data.hash; log_data.parent_hash = gp_hash_stack[gp_hash_stack_fill_point - 1]; log_data.blacks = (gp->board)->blacks; log_data.whites = (gp->board)->whites; log_data.player = gp->player; gchar *json_doc = game_tree_log_data_h_json_doc(gp_hash_stack_fill_point, gp); log_data.json_doc = json_doc; log_data.json_doc_len = strlen(json_doc); game_tree_log_write_h(log_env, &log_data); g_free(json_doc); } const SquareSet moves = game_position_legal_moves(gp); if (0ULL == moves) { pve_line = pve_line_create(pve); GamePosition *flipped_players = game_position_pass(gp); if (game_position_has_any_legal_move(flipped_players)) { node = search_node_negated(game_position_solve_impl(result, flipped_players, -cutoff, -achievable, &pve_line)); } else { result->leaf_count++; node = search_node_new(pass_move, game_position_final_value(gp)); } pve_line_add_move(pve, pve_line, pass_move, flipped_players); pve_line_delete(pve, *pve_parent_line_p); *pve_parent_line_p = pve_line; game_position_free(flipped_players); } else { MoveList move_list; bool branch_is_active = false; move_list_init(&move_list); sort_moves_by_mobility_count(&move_list, gp); for (MoveListElement *element = move_list.head.succ; element != &move_list.tail; element = element->succ) { const Square move = element->sq; if (!node) node = search_node_new(move, (pv_full_recording) ? achievable - 1 : achievable); GamePosition *gp2 = game_position_make_move(gp, move); pve_line = pve_line_create(pve); node2 = search_node_negated(game_position_solve_impl(result, gp2, -cutoff, -node->value, &pve_line)); if (node2->value > node->value || (!branch_is_active && node2->value == node->value)) { branch_is_active = true; search_node_free(node); node = node2; node->move = move; node2 = NULL; pve_line_add_move(pve, pve_line, move, gp2); game_position_free(gp2); pve_line_delete(pve, *pve_parent_line_p); *pve_parent_line_p = pve_line; if (node->value > cutoff) goto out; if (!pv_full_recording && node->value == cutoff) goto out; } else { if (pv_full_recording && node2->value == node->value) { pve_line_add_move(pve, pve_line, move, gp2); pve_line_add_variant(pve, *pve_parent_line_p, pve_line); } else { pve_line_delete(pve, pve_line); } search_node_free(node2); game_position_free(gp2); } } } out: if (log_env->log_is_on) { gp_hash_stack_fill_point--; } return node; }