#include "gobang.h" #include "game_mode.h" #include "ai.h" #include #include #include // ?????????? int BOARD_SIZE = 15; // ?????????????(???15) int board[MAX_BOARD_SIZE][MAX_BOARD_SIZE] = {0}; // ?????????????(???????????0) Step steps[MAX_STEPS]; // ??????????????????? const int direction[4][2] = {{1, 0}, {0, 1}, {1, 1}, {1, -1}}; // ?????????????????????????? int step_count = 0; // ????????????? bool use_forbidden_moves = false; // ?????????????? int use_timer = 0; // ????????????? int time_limit = 30; // ???????????30?? /** * @brief ??????????????????????????????? * ?????????????????????????EMPTY??????step_count?????0 */ void empty_board() { // ??????????????? for (int i = 0; i < BOARD_SIZE; i++) { for (int j = 0; j < BOARD_SIZE; j++) { board[i][j] = EMPTY; } } step_count = 0; // ?????????????? } /** * @brief ???????????? * ???????????????????????????????? * ???????????'x'??AI????????'??'??????????'??' */ void print_board() { // ????????1-BOARD_SIZE????? printf("\n "); for (int i = 0; i < BOARD_SIZE; i++) { printf("%2d", i + 1); if (i + 1 == 9) // ????????9??10+????? printf(" "); } printf("\n"); // ??????????????? for (int i = 0; i < BOARD_SIZE; i++) { printf("%2d ", i + 1); // ????????1-BOARD_SIZE?? for (int j = 0; j < BOARD_SIZE; j++) { if (board[i][j] == PLAYER) printf("x "); // ??????? else if (board[i][j] == AI) printf("?? "); // AI????(????????) else printf("?? "); // ???? } printf("\n"); // ??????????? } } /** * @brief ?????????????????????? * @param x ??????(0-base) * @param y ??????(0-base) * @return true ????????????? * @return false ???????????????? */ bool have_space(int x, int y) { // ???????????????????????????? return (x >= 0 && x < BOARD_SIZE && y >= 0 && y < BOARD_SIZE && board[x][y] == EMPTY); } /** * @brief ??????????? * * @param player1 ???1 * @param player2 ???2 */ void setup_board_size() { printf("?????????????????????(13X13)?????????(15X15)??????????(19X19)\n"); char prompt[100]; sprintf(prompt, "?????????????(5~%d)(???????????):\n", MAX_BOARD_SIZE); BOARD_SIZE = get_integer_input(prompt, 5, MAX_BOARD_SIZE); } /** * @brief Set the up game options object * ?????????????????????????????????? */ void setup_game_options() { use_forbidden_moves = get_integer_input("????????????? (1-??, 0-??): ", 0, 1); use_timer = get_integer_input("???????????? (1-??, 0-??): ", 0, 1); if (use_timer) { time_limit = get_integer_input("?????????????????? (1~60????): ", 1, 60) * 60; } } /** * @brief ?????????? * * @param player1 * @param player2 * @return int player1 or player2 */ int determine_first_player(int player1, int player2) { char prompt[100]; sprintf(prompt, "?????????? (1 for Player %d, 2 for Player %d): ", player1, player2); int first_player_choice = get_integer_input(prompt, 1, 2); if (first_player_choice == 1) { return player1; } else { return player2; } } /** * @brief ??????????? * * @param x * @param y * @param player * @return true * @return false */ bool is_forbidden_move(int x, int y, int player) { if (!use_forbidden_moves) { return false; } if (player != PLAYER && player != PLAYER1) { return false; } board[x][y] = player; int three_count = 0; int four_count = 0; for (int i = 0; i < 4; i++) { DirInfo info = count_specific_direction(x, y, direction[i][0], direction[i][1], player); if (info.continuous_chess > 5) { board[x][y] = EMPTY; return true; // ???????? } if (info.continuous_chess == 3 && info.check_start && info.check_end) { three_count++; } if (info.continuous_chess == 4 && (info.check_start || info.check_end)) { four_count++; } } board[x][y] = EMPTY; if (three_count >= 2 || four_count >= 2) { return true; // ????????????? } return false; } /** * @brief ????????????? * @param x ??????(0-base) * @param y ??????(0-base) * @return true ?????? * @return false ???????(????????) */ bool player_move(int x, int y, int player) { // ???????????false if (!have_space(x, y)) return false; if (is_forbidden_move(x, y, player)) { printf("????????????????????\n"); return false; } // ?????????? board[x][y] = player; // ??????????s??????????? steps[step_count++] = (Step){player, x, y}; return true; } /** * @brief ??????????????????????????? * @param x ????????? * @param y ????????? * @param dx ??????????(-1,0,1) * @param dy ??????????(-1,0,1) * @param player ?????(PLAYER/AI) * @return DirInfo ??????????????????????????? * @note ???????????????????????????????????????? */ DirInfo count_specific_direction(int x, int y, int dx, int dy, int player) { DirInfo info; info.continuous_chess = 1; // ??????????????????? info.check_start = false; // ????????? info.check_end = false; // ????????? // ?????????dx, dy?? int nx = x + dx, ny = y + dy; while (nx >= 0 && nx < BOARD_SIZE && ny >= 0 && ny < BOARD_SIZE && board[nx][ny] == player) { info.continuous_chess++; // ??????????????? nx += dx; // ??????????? ny += dy; } // ??????????????????????????? if (nx >= 0 && nx < BOARD_SIZE && ny >= 0 && ny < BOARD_SIZE) if (board[nx][ny] == EMPTY) info.check_end = true; // ????????-dx, -dy?? nx = x - dx, ny = y - dy; while (nx >= 0 && nx < BOARD_SIZE && ny >= 0 && ny < BOARD_SIZE && board[nx][ny] == player) { info.continuous_chess++; // ??????????????? nx -= dx; // ??????????? ny -= dy; } // ?????????????????????????? if (nx >= 0 && nx < BOARD_SIZE && ny >= 0 && ny < BOARD_SIZE) if (board[nx][ny] == EMPTY) info.check_start = true; return info; } bool check_win(int x, int y, int player) { // ?????????????????????? for (int i = 0; i < 4; i++) { DirInfo info = count_specific_direction(x, y, direction[i][0], direction[i][1], player); if (info.continuous_chess >= 5) // ????????>=5????? { return true; } } return false; // ???????????????? } /** * @brief ??????????????????? * @note ???????: * 1. ???????????????? * 2. ?????????????????????? * 3. ??????: * - ???????/????? * - ?????(???/AI) * - ????????(1-based????) * - ????????? * 4. ????????Enter???????????? * 5. ???????????????????????: * - ??????????? * - ??????? * - ???MVP * @note ???????: * - ?????????????????????????? * - ???????????1-based??????????? * - ??????????????????????????? * - ??????????evaluate_performance()???? */ void review_process(int game_mode) { printf("\n===== ??????(???????%d) =====\n", step_count); // ??????????? int c; while ((c = getchar()) != '\n' && c != EOF) ; // ??????????????? int temp_board[MAX_BOARD_SIZE][MAX_BOARD_SIZE]; memset(temp_board, EMPTY, sizeof(temp_board)); // ???????????? // ????????????? for (int i = 0; i < step_count; i++) { Step s = steps[i]; // ?????????? temp_board[s.x][s.y] = s.player; // ??????????????? // ????????????? // ??????????????????????????? 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 == PLAYER1) ? "???1(????)" : "???2(????)", s.x + 1, s.y + 1); } // ?????????????? printf(" "); for (int col = 0; col < BOARD_SIZE; col++) printf("%2d", col + 1); // ???? printf("\n"); for (int row = 0; row < BOARD_SIZE; row++) { printf("%2d ", row + 1); // ???? for (int col = 0; col < BOARD_SIZE; col++) { if (temp_board[row][col] == PLAYER || temp_board[row][col] == PLAYER1) printf("x "); else if (temp_board[row][col] == AI || temp_board[row][col] == PLAYER2) printf("?? "); else printf("?? "); } printf("\n"); // ?????????? } // ????????????????????????????? if (i < step_count - 1) { printf("\n??Enter?????????..."); while (getchar() != '\n') ; // ?????? } } printf("\n???????????Enter??????..."); getchar(); // ?????????? // ??????????? printf("\n===== ??????? =====\n"); int player1_score = 0, player2_score = 0; // ?????????????????????????? for (int i = 0; i < step_count; i++) { if (steps[i].player == PLAYER || steps[i].player == PLAYER1) { 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) { 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 { 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 (player1_score > player2_score) { printf("\nMVP: %s (???? %d ??)\n", (game_mode == 1) ? "???" : "???1(????)", player1_score - player2_score); } else if (player2_score > player1_score) { printf("\nMVP: %s (???? %d ??)\n", (game_mode == 1) ? "AI" : "???2(????)", player2_score - player1_score); } else { printf("\n????????????\n"); } getchar(); } /** * @brief ???????????????????? * @return int ????????(0-???, 1-?????????, 2-????????, 3-??????????) */ void handle_save_record(int game_mode) { int save_choice = 0; printf("===== ??????? =====\n"); printf("??????????? (1-??, 0-??): "); scanf("%d", &save_choice); if (save_choice == 1) { time_t now = time(NULL); struct tm *t = localtime(&now); char filename[256]; strftime(filename, sizeof(filename), "%Y%m%d_%H%M%S.txt", t); int save_status = save_game_to_file(filename, game_mode); switch (save_status) { case 0: // ??? printf("\n????????????????: %s\n", filename); printf("????????????????????????: .\\gobang.exe -l %s\n", filename); break; case 1: // ????????? printf("\n?????????????: ??????? 'records' ????\n"); printf("????????????????????????????????????\n"); break; case 2: // ???????? printf("\n?????????????: ????????? '%s' ?????????\n", filename); printf("????????????????????????????????????\n"); break; case 3: // ?????????? printf("\n?????????????: ????????????????\n"); printf("??????????????????\n"); break; default: printf("\n?????????????: ???????????\n"); break; } } } /** * @brief ?????????? * * @param steps_to_undo ????????? * @return true ?????? * @return false ???????(????????) */ bool return_move(int steps_to_undo) { if (step_count < steps_to_undo) { return false; } for (int i = 0; i < steps_to_undo; i++) { if (step_count > 0) { step_count--; board[steps[step_count].x][steps[step_count].y] = EMPTY; } } return true; } /** * @brief ??????????????????????? * @param player ??????????(PLAYER/AI) * @return int ???(???????????????) * @note ??????: * - ????: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. ?????????????????? * 3. ???????????????????? * 4. ???????????4(??????????????????) */ int evaluate_performance(int player) { int total_score = 0; // ???????????????? for (int i = 0; i < BOARD_SIZE; i++) { for (int j = 0; j < BOARD_SIZE; j++) { if (board[i][j] == player) { total_score += calculate_step_score(i, j, player); } } } return total_score / 4; // ????????????????????4 } /** * @brief ??????????????????? * @param filename ??????????? * @return int ??????: * 0: ??? * 1: ????????? * 2: ???????? * 3: ?????????? */ int save_game_to_file(const char *filename, int game_mode) { // ????records??(?????????) struct stat st = {0}; if (stat("records", &st) == -1) { if (mkdir("records") != 0) { // ?????????????(????????????????????????) if (stat("records", &st) == -1) { #ifdef _WIN32 printf("???????????records??\n"); printf("???????\n"); printf("1. ?????????? - ??????????????????\n"); printf("2. ????????????? - ??????????????\n"); printf("3. ???????? - ?????????\n"); #else perror("?????????"); #endif return 1; // ????????? } } } // ????? char fullpath[256]; snprintf(fullpath, sizeof(fullpath), "records/%s", filename); FILE *file = fopen(fullpath, "w"); if (!file) { return 2; // ???????? } // ?????????????????? if (fprintf(file, "%d\n%d\n", game_mode, BOARD_SIZE) < 0) { fclose(file); return 3; // ?????????? } // ??????????????? for (int i = 0; i < step_count; i++) { if (fprintf(file, "%d %d %d\n", steps[i].player, steps[i].x, steps[i].y) < 0) { fclose(file); return 3; // ?????????? } } if (fclose(file) != 0) { return 3; // ??????/??????? } return 0; // ??? } /** * @brief ??????????????? * @param filename ??????????? * @return true ?????? * @return false ??????? */ int load_game_from_file(const char *filename) { // ????? char fullpath[256]; snprintf(fullpath, sizeof(fullpath), "records/%s", filename); FILE *file = fopen(fullpath, "r"); if (!file) { return false; } // ????????????????? 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); return false; } // ????????? BOARD_SIZE = size; empty_board(); // ?????????????? step_count = 0; while (fscanf(file, "%d %d %d", &steps[step_count].player, &steps[step_count].x, &steps[step_count].y) == 3) { step_count++; } fclose(file); return game_mode; }