#include "gobang.h" #include #include #include #include #ifdef _WIN32 #include #include #include #endif /** * @brief 从用户获取整数输入 * * @param prompt 提示信息 * @param min 最小值 * @param max 最大值 * @return int 用户输入的整数 */ int get_integer_input(const char *prompt, int min, int max) { int value; int result; char ch; while (1) { printf("%s", prompt); result = scanf("%d", &value); if (result == 1 && value >= min && value <= max) { // 清除输入缓冲区中剩余的字符 while ((ch = getchar()) != '\n' && ch != EOF) ; return value; } else { // 清除无效输入 while ((ch = getchar()) != '\n' && ch != EOF) ; printf("输入无效,请输入一个介于 %d 和 %d 之间的整数。\n", min, max); } } } /** * @brief 处理玩家回合 * * @param current_player * @return true * @return false */ bool handle_player_turn(int current_player) { int x, y; char input[10]; time_t start_time, end_time; if (use_timer) { time(&start_time); } if (current_player == 1) { printf("\n玩家, 请输入落子坐标(行 列,1~%d),或输入R/r悔棋:", BOARD_SIZE); } else { printf("\n玩家%d, 请输入落子坐标(行 列,1~%d),或输入R/r悔棋:", current_player, BOARD_SIZE); } while (1) { if (use_timer) { time(&end_time); if (difftime(end_time, start_time) > time_limit) { if (current_player == 1) { printf("\n玩家超时, 对方获胜!\n"); } else { printf("\n玩家%d超时, 对方获胜!\n", current_player); } return false; // 超时,返回false表示回合失败 } } if (_kbhit()) { scanf("%s", input); break; } Sleep(100); // a small delay to prevent high CPU usage } if (input[0] == 'r' || input[0] == 'R') { int steps_to_undo; printf("请输入要悔棋的步数(AI会同样悔棋): "); steps_to_undo = get_integer_input("", 1, step_count / 2); int effective_steps = (current_player == PLAYER) ? steps_to_undo * 2 : steps_to_undo; if (return_move(effective_steps)) { printf("成功悔棋 %d 步!\n", steps_to_undo); print_board(); } else { printf("无法悔棋!\n"); } return true; // 悔棋操作后,回合算作成功,但不进行落子 } if (sscanf(input, "%d", &x) != 1) { printf("无效输入,请输入数字坐标。"); return true; // 输入无效,但回合继续 } if (scanf("%d", &y) != 1) { printf("无效输入,请输入数字坐标。"); while (getchar() != '\n') ; return true; // 输入无效,但回合继续 } x--; y--; if (!player_move(x, y, current_player)) { printf("坐标无效!请重新输入。\n"); return true; // 坐标无效,但回合继续 } print_board(); if (check_win(x, y, current_player)) { if (current_player == 1) { printf("\n玩家获胜!\n"); } else { printf("\n玩家%d获胜!\n", current_player); } return false; // 游戏结束 } return true; // 成功落子 } /** * @brief 运行AI游戏 * @note 从文件中加载历史记录并进行复盘 * @param AI_DEPTH AI的搜索深度 */ void run_ai_game() { setup_game_options(); // AI对战模式 setup_board_size(); int AI_DEPTH = 3; AI_DEPTH = get_integer_input("请选择AI难度(1~5), 数字越大越强,注意数字越大AI思考时间越长!):", 1, 5); empty_board(); int current_player = determine_first_player(PLAYER, AI); print_board(); while (1) { if (current_player == PLAYER) { int old_step_count = step_count; if (!handle_player_turn(current_player)) { break; // 游戏结束或超时 } if (step_count > old_step_count) { current_player = AI; } } else { printf("\nAI思考中...\n"); time_t start_time, end_time; if (use_timer) { time(&start_time); } ai_move(AI_DEPTH); if (use_timer) { time(&end_time); if (difftime(end_time, start_time) > time_limit) { printf("\nAI超时, 玩家获胜!\n"); break; } } print_board(); Step last_step = steps[step_count - 1]; if (check_win(last_step.x, last_step.y, AI)) { printf("\nAI获胜!\n"); break; } current_player = PLAYER; } if (step_count == BOARD_SIZE * BOARD_SIZE) { printf("\n平局!\n"); break; } } printf("===== 游戏结束 =====\n"); int review_choice; review_choice = get_integer_input("是否要复盘本局比赛? (1-是, 0-否): ", 0, 1); if (review_choice == 1) { review_process(1); // 1 for AI mode } handle_save_record(1); // 1 for AI mode } /** * @brief 运行双人对战模式 * @note 从文件中加载历史记录并进行复盘 */ void run_pvp_game() { setup_game_options(); // 双人对战模式 setup_board_size(); empty_board(); int current_player = determine_first_player(PLAYER3, PLAYER4); print_board(); while (1) { int old_step_count = step_count; if (!handle_player_turn(current_player)) { break; // 游戏结束或超时 } if (step_count == BOARD_SIZE * BOARD_SIZE) { printf("\n平局!\n"); break; } if (step_count > old_step_count) { current_player = (current_player == PLAYER3) ? PLAYER4 : PLAYER3; } } printf("===== 游戏结束 =====\n"); int review_choice; review_choice = get_integer_input("是否要复盘本局比赛? (1-是, 0-否): ", 0, 1); if (review_choice == 1) { review_process(2); // 2 for PvP mode } handle_save_record(2); // 2 for PvP mode } /** * @brief 运行复盘模式 * @note 从文件中加载历史记录并进行复盘 */ void run_review_mode() { char filename[100]; char record_files[100][100]; int file_count = 0; #ifdef _WIN32 WIN32_FIND_DATA ffd; HANDLE hFind = FindFirstFile("records\\*", &ffd); if (hFind != INVALID_HANDLE_VALUE) { do { if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { strcpy(record_files[file_count++], ffd.cFileName); } } while (FindNextFile(hFind, &ffd) != 0); FindClose(hFind); } #endif if (file_count > 0) { printf("发现以下复盘文件:\n"); for (int i = 0; i < file_count; i++) { printf("%d. %s\n", i + 1, record_files[i]); } char prompt[150]; sprintf(prompt, "请输入复盘文件编号(1-%d),或输入0以手动输入文件名: ", file_count); int choice = get_integer_input(prompt, 0, file_count); if (choice > 0) { strcpy(filename, record_files[choice - 1]); } else { printf("请输入完整文件名: "); scanf("%s", filename); int c; while ((c = getchar()) != '\n' && c != EOF); int possible_choice = atoi(filename); if (possible_choice > 0 && possible_choice <= file_count) { strcpy(filename, record_files[possible_choice - 1]); } } } else { printf("未找到任何复盘文件,请输入复盘文件地址: "); scanf("%s", filename); int c; while ((c = getchar()) != '\n' && c != EOF); } int game_mode = load_game_from_file(filename); if (game_mode != 0) { if (game_mode == 1) { printf("加载AI对战模式复盘文件成功!\n"); } else if (game_mode == 2) { printf("加载双人对战模式复盘文件成功!\n"); } review_process(game_mode); } }