From 0970c3fd8290abfe8e3783c761dffd3bc78d58d8 Mon Sep 17 00:00:00 2001 From: LHY0125 <3364451258@qq.com> Date: Mon, 30 Jun 2025 18:19:53 +0800 Subject: [PATCH] Add files via upload --- game_mode.c | 121 +++++++++++++++++--- game_mode.h | 10 ++ gobang.c | 312 ++++++++++++++++++++++++++++------------------------ gobang.exe | Bin 0 -> 83970 bytes gobang.h | 28 ++--- 5 files changed, 300 insertions(+), 171 deletions(-) create mode 100644 gobang.exe diff --git a/game_mode.c b/game_mode.c index 2f17c55..b8950fc 100644 --- a/game_mode.c +++ b/game_mode.c @@ -9,6 +9,42 @@ #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 处理玩家回合 * @@ -190,11 +226,9 @@ void run_ai_game() review_choice = get_integer_input("是否要复盘本局比赛? (1-是, 0-否): ", 0, 1); if (review_choice == 1) { - review_process(); + review_process(1); // 1 for AI mode } -end_game: -end_pvp_game: - handle_save_record(); + handle_save_record(1); // 1 for AI mode } /** @@ -235,9 +269,9 @@ void run_pvp_game() review_choice = get_integer_input("是否要复盘本局比赛? (1-是, 0-否): ", 0, 1); if (review_choice == 1) { - review_process(); + review_process(2); // 2 for PvP mode } - handle_save_record(); + handle_save_record(2); // 2 for PvP mode } /** @@ -246,18 +280,75 @@ void run_pvp_game() */ void run_review_mode() { - // 复盘模式 - char filename[256]; - printf("请输入复盘文件地址: "); - scanf("%s", filename); - if (load_game_from_file(filename)) + 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) { - printf("成功加载历史记录: %s\n", filename); - review_process(); + 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("加载历史记录失败: %s\n", filename); - exit(1); + 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); } } \ No newline at end of file diff --git a/game_mode.h b/game_mode.h index 0cdb0ff..466e508 100644 --- a/game_mode.h +++ b/game_mode.h @@ -18,6 +18,16 @@ #include "gobang.h" +/** + * @brief 从用户获取整数输入 + * + * @param prompt 提示信息 + * @param min 最小值 + * @param max 最大值 + * @return int 输入的整数 + */ +int get_integer_input(const char *prompt, int min, int max); + /** * @brief 处理玩家回合 * diff --git a/gobang.c b/gobang.c index d40721d..bdce2ba 100644 --- a/gobang.c +++ b/gobang.c @@ -1,4 +1,5 @@ #include "gobang.h" +#include "game_mode.h" #include #include #include @@ -78,11 +79,10 @@ bool have_space(int x, int y) } /** - * @brief 玩家落子操作 + * @brief 配置棋盘大小 * - * @param player1 - * @param player2 - * @return int player1 or player2 + * @param player1 玩家1 + * @param player2 玩家2 */ void setup_board_size() { @@ -103,7 +103,7 @@ void setup_game_options() use_timer = get_integer_input("是否启用计时器 (1-是, 0-否): ", 0, 1); if (use_timer) { - time_limit = get_integer_input("请输入每回合的时间限制 (分钟): ", 1, 60) * 60; + time_limit = get_integer_input("请输入每回合的时间限制 (1~60分钟): ", 1, 60) * 60; } } @@ -462,32 +462,6 @@ int dfs(int x, int y, int player, int depth, int alpha, int beta, bool is_maximi * - 步数>10时缩小搜索范围到已有棋子附近2格 * - 使用中心位置优先策略 */ -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); - } - } -} - void ai_move(int depth) { // 1. 首先检查是否需要阻止玩家的四子连棋或三子活棋 @@ -616,7 +590,7 @@ void ai_move(int depth) * - 包含输入缓冲区清理防止意外输入 * - 评分环节调用evaluate_performance()函数 */ -void review_process() +void review_process(int game_mode) { printf("\n===== 复盘记录(总步数:%d) =====\n", step_count); // 清空输入缓冲区 @@ -635,11 +609,25 @@ void review_process() temp_board[s.x][s.y] = s.player; // 在临时棋盘上落子 // 打印当前步骤信息 - printf("\n===== 五子棋人机对战(%dX%d棋盘) =====", BOARD_SIZE, BOARD_SIZE); - printf("\n 第%d步/%d步: %s 落子于(%d, %d)\n", - i + 1, step_count, - (s.player == PLAYER) ? "玩家" : "AI", // 三目运算符选择显示文本 - s.x + 1, s.y + 1); // 显示1-base坐标 + // 根据游戏模式显示不同的标题和玩家信息 + if (game_mode == 1) + { + // 人机对战 + printf("\n===== 五子棋人机对战(%dX%d棋盘) =====", BOARD_SIZE, BOARD_SIZE); + printf("\n 第%d步/%d步: %s 落子于(%d, %d)\n", + i + 1, step_count, + (s.player == PLAYER) ? "玩家" : "AI", + s.x + 1, s.y + 1); + } + else + { + // 双人对战 + printf("\n===== 五子棋双人对战(%dX%d棋盘) =====", BOARD_SIZE, BOARD_SIZE); + printf("\n 第%d步/%d步: %s 落子于(%d, %d)\n", + i + 1, step_count, + (s.player == PLAYER3) ? "玩家1(黑棋)" : "玩家2(白棋)", + s.x + 1, s.y + 1); + } // 打印当前复盘棋盘 printf(" "); @@ -652,9 +640,9 @@ void review_process() printf("%2d ", row + 1); // 行号 for (int col = 0; col < BOARD_SIZE; col++) { - if (temp_board[row][col] == PLAYER) + if (temp_board[row][col] == PLAYER || temp_board[row][col] == PLAYER3) printf("x "); - else if (temp_board[row][col] == AI) + else if (temp_board[row][col] == AI || temp_board[row][col] == PLAYER4) printf("○ "); else printf("· "); @@ -675,33 +663,63 @@ void review_process() // 评估双方表现 printf("\n===== 对局评分 =====\n"); - int player_score = evaluate_performance(PLAYER); - int ai_score = evaluate_performance(AI); + int player1_score = 0, player2_score = 0; - double sum_score = (long double)player_score + (long double)ai_score; + // 遍历所有步数,累积每一步的得分 + for (int i = 0; i < step_count; i++) + { + if (steps[i].player == PLAYER || steps[i].player == PLAYER3) + { + player1_score += calculate_step_score(steps[i].x, steps[i].y, steps[i].player); + } + else + { + player2_score += calculate_step_score(steps[i].x, steps[i].y, steps[i].player); + } + } + + double sum_score = (long double)player1_score + (long double)player2_score; if (sum_score > 0) { - printf("玩家得分: %d, 占比: %.2f%%\n", - player_score, (double)player_score * 100.0 / sum_score); - printf("AI得分: %d, 占比: %.2f%%\n", - ai_score, (double)ai_score * 100.0 / sum_score); + if (game_mode == 1) + { + printf("玩家得分: %d, 占比: %.2f%%\n", + player1_score, (double)player1_score * 100.0 / sum_score); + printf("AI得分: %d, 占比: %.2f%%\n", + player2_score, (double)player2_score * 100.0 / sum_score); + } + else + { + printf("玩家1(黑棋)得分: %d, 占比: %.2f%%\n", + player1_score, (double)player1_score * 100.0 / sum_score); + printf("玩家2(白棋)得分: %d, 占比: %.2f%%\n", + player2_score, (double)player2_score * 100.0 / sum_score); + } } else { - printf("玩家得分: %d\n", player_score); - printf("AI得分: %d\n", ai_score); + if (game_mode == 1) + { + printf("玩家得分: %d\n", player1_score); + printf("AI得分: %d\n", player2_score); + } + else + { + printf("玩家1(黑棋)得分: %d\n", player1_score); + printf("玩家2(白棋)得分: %d\n", player2_score); + } printf("注: 双方得分均为0,无法计算占比\n"); } // 评选MVP - if (player_score > ai_score) + if (player1_score > player2_score) { - printf("\nMVP: 玩家 (领先 %d 分)\n", player_score - ai_score); + printf("\nMVP: %s (领先 %d 分)\n", (game_mode == 1) ? "玩家" : "玩家1(黑棋)", player1_score - player2_score); } - else if (ai_score > player_score) + else if (player2_score > player1_score) { - printf("\nMVP: AI (领先 %d 分)\n", ai_score - player_score); + printf("\nMVP: %s (领先 %d 分)\n", (game_mode == 1) ? "AI" : "玩家2(白棋)", player2_score - player1_score); } else { @@ -711,16 +729,11 @@ void review_process() getchar(); } -/** - * @brief 悔棋功能实现 - * @param steps_to_undo 要撤销的步数 - * @return true 悔棋成功 - * @return false 悔棋失败(步数不足) - */ /** * @brief 处理游戏结束后的记录保存 + * @return int 保存状态码(0-成功, 1-目录创建失败, 2-文件打开失败, 3-文件写入失败) */ -void handle_save_record() +void handle_save_record(int game_mode) { int save_choice = 0; printf("===== 游戏结束 =====\n"); @@ -734,7 +747,7 @@ void handle_save_record() char filename[256]; strftime(filename, sizeof(filename), "%Y%m%d_%H%M%S.txt", t); - int save_status = save_game_to_file(filename); + int save_status = save_game_to_file(filename, game_mode); switch (save_status) { case 0: // 成功 @@ -760,6 +773,13 @@ void handle_save_record() } } +/** + * @brief 悔棋功能实现 + * + * @param steps_to_undo 要悔棋的步数 + * @return true 悔棋成功 + * @return false 悔棋失败(步数不足) + */ bool return_move(int steps_to_undo) { if (step_count < steps_to_undo) @@ -776,25 +796,83 @@ bool return_move(int steps_to_undo) return true; } -/** - * @brief 复盘游戏过程,逐步重现所有落子步骤 - * @note 实现逻辑: - * 1. 创建临时棋盘用于复盘展示 - * 2. 按步数顺序逐步重现每个落子 - * 3. 每步显示当前棋盘状态和落子信息 - * 4. 通过用户按Enter键控制步骤前进 - * 5. 显示1-based坐标方便用户查看 - */ + /** * @brief 评估玩家在整盘棋局中的表现 * @param player 要评估的玩家(PLAYER/AI) * @return int 总分(已考虑方向重复计算) * @note 评分标准: - * - 五连:1000000 - * - 活四:100000 冲四:10000 死四:500 - * - 活三:5000 眠三:1000 死三:50 - * - 活二:500 眠二:100 死二:10 - * - 开放单子:50 半开放单子:10 封闭单子:1 + * - 五连:2500 + * - 活四:1000 冲四:500 死四:250 + * - 活三:250 眠三:100 死三:50 + * - 活二:50 眠二:20 死二:10 + * - 开放单子:10 半开放单子:5 封闭单子:1 + * @note 实现细节: + * 1. 遍历棋盘所有位置 + * 2. 对每个棋子检查四个方向 + * 3. 统计所有连子情况并评分 + * 4. 最终分数除以4(消除方向重复计算影响) + */ +int calculate_step_score(int x, int y, int player) +{ + int step_score = 0; + // 检查四个方向 + for (int k = 0; k < 4; k++) + { + DirInfo info = count_specific_direction(x, y, direction[k][0], direction[k][1], player); + // 根据连子数评分 + switch (info.continuous_chess) + { + case 5: + step_score += 2500; + break; // 五连 + case 4: + if (info.check_start && info.check_end) + step_score += 1000; // 活四 + else if (info.check_start || info.check_end) + step_score += 500; // 冲四 + else + step_score += 250; // 死四 + break; + case 3: + if (info.check_start && info.check_end) + step_score += 250; // 活三 + else if (info.check_start || info.check_end) + step_score += 100; // 眠三 + else + step_score += 50; // 死三 + break; + case 2: + if (info.check_start && info.check_end) + step_score += 50; // 活二 + else if (info.check_start || info.check_end) + step_score += 20; // 眠二 + else + step_score += 10; // 死二 + break; + case 1: + if (info.check_start && info.check_end) + step_score += 10; // 开放单子 + else if (info.check_start || info.check_end) + step_score += 5; // 半开放单子 + else + step_score += 1; // 封闭单子 + break; + } + } + return step_score; +} + +/** + * @brief 评估玩家在整盘棋局中的表现 + * @param player 要评估的玩家(PLAYER/AI) + * @return int 总分(已考虑方向重复计算) + * @note 评分标准: + * - 五连:2500 + * - 活四:1000 冲四:500 死四:250 + * - 活三:250 眠三:100 死三:50 + * - 活二:50 眠二:20 死二:10 + * - 开放单子:10 半开放单子:5 封闭单子:1 * @note 实现细节: * 1. 遍历棋盘所有位置 * 2. 对每个棋子检查四个方向 @@ -810,53 +888,9 @@ int evaluate_performance(int player) { for (int j = 0; j < BOARD_SIZE; j++) { - if (board[i][j] != player) - continue; - - // 检查四个方向 - for (int k = 0; k < 4; k++) + if (board[i][j] == player) { - DirInfo info = count_specific_direction(i, j, direction[k][0], direction[k][1], player); - - // 根据连子数评分 - switch (info.continuous_chess) - { - case 5: - total_score += 1000; - break; // 五连 - case 4: - if (info.check_start && info.check_end) - total_score += 1000; // 活四 - else if (info.check_start || info.check_end) - total_score += 500; // 冲四 - else - total_score += 200; // 死四 - break; - case 3: - if (info.check_start && info.check_end) - total_score += 200; // 活三 - else if (info.check_start || info.check_end) - total_score += 100; // 眠三 - else - total_score += 20; // 死三 - break; - case 2: - if (info.check_start && info.check_end) - total_score += 100; // 活二 - else if (info.check_start || info.check_end) - total_score += 50; // 眠二 - else - total_score += 10; // 死二 - break; - case 1: - if (info.check_start && info.check_end) - total_score += 20; // 开放单子 - else if (info.check_start || info.check_end) - total_score += 10; // 半开放单子 - else - total_score += 1; // 封闭单子 - break; - } + total_score += calculate_step_score(i, j, player); } } } @@ -872,7 +906,7 @@ int evaluate_performance(int player) * 2: 文件打开失败 * 3: 文件写入失败 */ -int save_game_to_file(const char *filename) +int save_game_to_file(const char *filename, int game_mode) { // 创建records目录(如果不存在) struct stat st = {0}; @@ -906,8 +940,8 @@ int save_game_to_file(const char *filename) return 2; // 文件打开失败 } - // 写入棋盘大小 - if (fprintf(file, "%d\n", BOARD_SIZE) < 0) + // 写入游戏模式和棋盘大小 + if (fprintf(file, "%d\n%d\n", game_mode, BOARD_SIZE) < 0) { fclose(file); return 3; // 文件写入失败 @@ -937,7 +971,7 @@ int save_game_to_file(const char *filename) * @return true 加载成功 * @return false 加载失败 */ -bool load_game_from_file(const char *filename) +int load_game_from_file(const char *filename) { // 打开文件 char fullpath[256]; @@ -948,8 +982,13 @@ bool load_game_from_file(const char *filename) return false; } - // 读取棋盘大小 - int size; + // 读取游戏模式和棋盘大小 + int game_mode, size; + if (fscanf(file, "%d", &game_mode) != 1 || (game_mode != 1 && game_mode != 2)) + { + fclose(file); + return 0; // 无效的游戏模式 + } if (fscanf(file, "%d", &size) != 1 || size < 5 || size > MAX_BOARD_SIZE) { fclose(file); @@ -960,24 +999,13 @@ bool load_game_from_file(const char *filename) BOARD_SIZE = size; empty_board(); - // 读取并重放所有落子步骤 - int player, x, y; - while (fscanf(file, "%d %d %d", &player, &x, &y) == 3) + // 读取所有落子步骤 + step_count = 0; + while (fscanf(file, "%d %d %d", &steps[step_count].player, &steps[step_count].x, &steps[step_count].y) == 3) { - if (player != PLAYER && player != AI) - { - fclose(file); - return false; - } - if (x < 0 || x >= BOARD_SIZE || y < 0 || y >= BOARD_SIZE) - { - fclose(file); - return false; - } - board[x][y] = player; - steps[step_count++] = (Step){player, x, y}; + step_count++; } fclose(file); - return true; + return game_mode; } \ No newline at end of file diff --git a/gobang.exe b/gobang.exe new file mode 100644 index 0000000000000000000000000000000000000000..f32c0f51c517186b1a3bec4155d635b05f23b572 GIT binary patch literal 83970 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 gP)X1QZ- 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 ZyWptJ#cjYER_vA^g>qY_aJ+Q+>3^r9X4(J% literal 0 HcmV?d00001 diff --git a/gobang.h b/gobang.h index ee9e94e..757ec02 100644 --- a/gobang.h +++ b/gobang.h @@ -203,16 +203,6 @@ int dfs(int x, int y, int player, int depth, int alpha, int beta, bool is_maximi */ void ai_move(int depth); -/** - * @brief Get the integer input object - * - * @param prompt 提示信息 - * @param min 最小值 - * @param max 最大值 - * @return int 输入的整数 - */ -int get_integer_input(const char *prompt, int min, int max); - /** * @brief 悔棋功能实现 * @return true 悔棋成功 @@ -225,7 +215,7 @@ bool return_move(int steps_to_undo); * @brief 复盘游戏过程 * 逐步重现游戏中的所有落子步骤 */ -void review_process(); +void review_process(int game_mode); /** * @brief 评估玩家在整盘棋局中的表现 @@ -234,6 +224,16 @@ void review_process(); */ int evaluate_performance(int player); +/** + * @brief 计算一步棋的得分 + * @param x 行坐标 + * @param y 列坐标 + * @param player 玩家标识 + * @return int 一步棋的得分 + */ +int calculate_step_score(int x, int y, int player); + + /** * @brief 将当前游戏记录保存到文件 * @param filename 要保存的文件名 @@ -243,12 +243,12 @@ int evaluate_performance(int player); * 2: 文件打开失败 * 3: 文件写入失败 */ -int save_game_to_file(const char *filename); +int save_game_to_file(const char *filename, int game_mode); /** * @brief 处理游戏结束后的记录保存 */ -void handle_save_record(); +void handle_save_record(int game_mode); /** * @brief 从文件加载游戏记录 @@ -256,6 +256,6 @@ void handle_save_record(); * @return true 加载成功 * @return false 加载失败 */ -bool load_game_from_file(const char *filename); +int load_game_from_file(const char *filename); #endif // GO_BANG_H \ No newline at end of file