mirror of
https://github.com/LHY0125/Gobang-Game.git
synced 2026-05-10 02:19:46 +08:00
Add files via upload
This commit is contained in:
@@ -1,3 +1,11 @@
|
||||
/**
|
||||
* @file ai.h
|
||||
* @note 本文件定义了AI模块的函数和变量
|
||||
* @note 包括:
|
||||
* 1. 评估一个落子位置的综合得分(结合进攻和防守)
|
||||
* 2. 评估指定位置的价值
|
||||
* 3. 评估棋盘价值
|
||||
*/
|
||||
#ifndef AI_H
|
||||
#define AI_H
|
||||
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
/**
|
||||
* @file config.h
|
||||
* @author 刘航宇(3364451258@qq.com、15236416560@163.com、lhy3364451258@outlook.com)
|
||||
* @brief 五子棋游戏参数配置头文件
|
||||
* @version 6.0
|
||||
* @date 2025-07-10
|
||||
*
|
||||
* @copyright Copyright (c) 2025
|
||||
*
|
||||
* @note 本文件集中定义了五子棋游戏的所有参数配置,便于统一管理和修改
|
||||
*/
|
||||
|
||||
@@ -19,6 +13,11 @@
|
||||
#define DEFAULT_BOARD_SIZE 15 // 默认棋盘尺寸
|
||||
#define MAX_STEPS (MAX_BOARD_SIZE * MAX_BOARD_SIZE) // 游戏最大步数
|
||||
|
||||
//---------- 游戏模式参数 ----------//
|
||||
#define GAME_MODE_AI 1 // 人机对战模式
|
||||
#define GAME_MODE_PVP 2 // 双人对战模式
|
||||
#define GAME_MODE_NETWORK 3 // 网络对战模式
|
||||
|
||||
//---------- 玩家标识参数 ----------//
|
||||
#define EMPTY 0 // 棋盘空位标识
|
||||
#define PLAYER 1 // 玩家标识 (用于人机对战模式)
|
||||
|
||||
+358
-104
@@ -11,6 +11,7 @@
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <ctype.h>
|
||||
|
||||
// 全局变量现在在globals.c中定义
|
||||
#ifdef _WIN32
|
||||
@@ -95,7 +96,7 @@ bool parse_player_input(int *x, int *y)
|
||||
{
|
||||
printf("无法悔棋!\n");
|
||||
}
|
||||
return false; // 特殊命令
|
||||
return 0; // 特殊命令已处理
|
||||
}
|
||||
else if (*x == INPUT_SAVE)
|
||||
{
|
||||
@@ -107,10 +108,10 @@ bool parse_player_input(int *x, int *y)
|
||||
// ... 处理退出 ...
|
||||
return false; // 特殊命令
|
||||
}
|
||||
printf("无效输入,请输入两个数字坐标。");
|
||||
printf("无效输入,请输入两个数字坐标。\n");
|
||||
while (getchar() != '\n')
|
||||
;
|
||||
return false; // 无效输入
|
||||
return 0; // 无效输入
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -138,7 +139,7 @@ bool parse_player_input(int *x, int *y)
|
||||
if (confirm)
|
||||
{
|
||||
printf("玩家选择认输!\n");
|
||||
return true; // 返回认输命令
|
||||
return 1; // 正常回合完成 // 返回认输命令
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -146,7 +147,121 @@ bool parse_player_input(int *x, int *y)
|
||||
return false; // 取消认输
|
||||
}
|
||||
}
|
||||
printf("无效输入,请输入数字坐标、'r'悔棋或's'认输。");
|
||||
printf("无效输入,请输入数字坐标、'r'悔棋或's'认输。\n");
|
||||
return 0; // 无效输入
|
||||
}
|
||||
return 1; // 有效坐标
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 解析网络对战模式下的玩家输入
|
||||
* @param x 行坐标指针
|
||||
* @param y 列坐标指针
|
||||
* @return true 有效坐标输入
|
||||
* @return false 特殊命令或无效输入
|
||||
*/
|
||||
bool parse_network_player_input(int *x, int *y)
|
||||
{
|
||||
char input[10];
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (_kbhit())
|
||||
{
|
||||
scanf("%s", input);
|
||||
break;
|
||||
}
|
||||
Sleep(100); // 短暂延迟以防止CPU占用过高
|
||||
}
|
||||
|
||||
if (sscanf(input, "%d", x) == 1)
|
||||
{
|
||||
// 成功解析第一个数字,现在解析第二个
|
||||
if (scanf("%d", y) != 1)
|
||||
{
|
||||
printf("无效输入,请输入两个数字坐标。\n");
|
||||
while (getchar() != '\n')
|
||||
;
|
||||
return false; // 无效输入
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// sscanf失败,检查特殊命令
|
||||
if (input[0] == 'r' || input[0] == 'R')
|
||||
{
|
||||
int steps_to_undo;
|
||||
steps_to_undo = get_integer_input("请输入要悔棋的步数(双方各退步数相同): ", 1, step_count / 2);
|
||||
|
||||
printf("发送悔棋请求给对方...\n");
|
||||
if (send_undo_request(steps_to_undo))
|
||||
{
|
||||
printf("悔棋请求已发送,等待对方回应...\n");
|
||||
|
||||
// 等待对方回应
|
||||
NetworkMessage msg;
|
||||
time_t start_time = time(NULL);
|
||||
|
||||
while (difftime(time(NULL), start_time) < 30) // 30秒超时
|
||||
{
|
||||
if (receive_network_message(&msg, 1000))
|
||||
{
|
||||
if (msg.type == MSG_UNDO_RESPONSE && msg.x == steps_to_undo)
|
||||
{
|
||||
if (msg.y == 1) // 对方同意
|
||||
{
|
||||
if (return_move(steps_to_undo * 2))
|
||||
{
|
||||
printf("对方同意悔棋,双方各退 %d 步!\n", steps_to_undo);
|
||||
print_board();
|
||||
return 2; // 悔棋成功,需要重新开始回合
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("悔棋失败!\n");
|
||||
return 0; // 悔棋失败,继续当前回合
|
||||
}
|
||||
}
|
||||
else // 对方拒绝
|
||||
{
|
||||
printf("对方拒绝了悔棋请求。\n");
|
||||
return 0; // 悔棋被拒绝,继续当前回合
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_network_connected())
|
||||
{
|
||||
printf("网络连接断开\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
printf("悔棋请求超时,对方未回应。\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("发送悔棋请求失败!\n");
|
||||
}
|
||||
return 0; // 特殊命令已处理
|
||||
}
|
||||
else if (input[0] == 's' || input[0] == 'S')
|
||||
{
|
||||
*x = INPUT_SURRENDER;
|
||||
int confirm = get_integer_input("确认认输?(1:是/0:否): ", 0, 1);
|
||||
if (confirm)
|
||||
{
|
||||
printf("你选择认输!\n");
|
||||
*x = INPUT_SURRENDER;
|
||||
return -1; // 返回认输命令
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("取消认输!\n");
|
||||
return 0; // 取消认输
|
||||
}
|
||||
}
|
||||
printf("无效输入,请输入数字坐标、'r'悔棋或's'认输。\n");
|
||||
return false; // 无效输入
|
||||
}
|
||||
return true; // 有效坐标
|
||||
@@ -166,44 +281,52 @@ bool handle_player_turn(int current_player)
|
||||
time(&start_time);
|
||||
}
|
||||
|
||||
printf("\n玩家%d, 请输入落子坐标(行 列,1~%d),或输入R/r悔棋,S/s认输:", current_player, BOARD_SIZE);
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (use_timer)
|
||||
printf("\n玩家%d, 请输入落子坐标(行 列,1~%d),或输入R/r悔棋,S/s认输:", current_player, BOARD_SIZE);
|
||||
|
||||
bool input_received = false;
|
||||
while (!input_received)
|
||||
{
|
||||
time(&end_time);
|
||||
if (difftime(end_time, start_time) > time_limit)
|
||||
if (use_timer)
|
||||
{
|
||||
printf("\n玩家%d超时, 对方获胜!\n", current_player);
|
||||
return false; // Timeout
|
||||
time(&end_time);
|
||||
if (difftime(end_time, start_time) > time_limit)
|
||||
{
|
||||
printf("\n玩家%d超时, 对方获胜!\n", current_player);
|
||||
return false; // Timeout
|
||||
}
|
||||
}
|
||||
|
||||
if (parse_player_input(&x, &y))
|
||||
{
|
||||
if (x == INPUT_SURRENDER)
|
||||
{
|
||||
printf("\n玩家%d选择认输,对方获胜!\n", current_player);
|
||||
return false; // 游戏结束,认输
|
||||
}
|
||||
input_received = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 已处理特殊命令或无效输入,继续循环
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (parse_player_input(&x, &y))
|
||||
x--;
|
||||
y--;
|
||||
|
||||
if (player_move(x, y, current_player))
|
||||
{
|
||||
if (x == INPUT_SURRENDER)
|
||||
{
|
||||
printf("\n玩家%d选择认输,对方获胜!\n", current_player);
|
||||
return false; // 游戏结束,认输
|
||||
}
|
||||
break; // 收到有效输入
|
||||
break; // 成功落子,跳出循环
|
||||
}
|
||||
else
|
||||
{
|
||||
// 已处理特殊命令或无效输入,继续循环
|
||||
return true;
|
||||
printf("坐标无效!请重新输入。\n");
|
||||
// 继续循环,重新输入坐标
|
||||
}
|
||||
}
|
||||
|
||||
x--;
|
||||
y--;
|
||||
|
||||
if (!player_move(x, y, current_player))
|
||||
{
|
||||
printf("坐标无效!请重新输入。\n");
|
||||
return true; // 坐标无效,但回合继续
|
||||
}
|
||||
print_board();
|
||||
|
||||
if (check_win(x, y, current_player))
|
||||
@@ -301,8 +424,8 @@ void run_ai_game()
|
||||
}
|
||||
}
|
||||
printf("===== 游戏结束 =====\n");
|
||||
review_process(1); // 1 for AI mode
|
||||
handle_save_record(1); // 1 for AI mode
|
||||
review_process(GAME_MODE_AI); // AI对战模式
|
||||
handle_save_record(GAME_MODE_AI); // AI对战模式
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -339,8 +462,8 @@ void run_pvp_game()
|
||||
}
|
||||
}
|
||||
printf("===== 游戏结束 =====\n");
|
||||
review_process(2); // 2 for PvP mode
|
||||
handle_save_record(2); // 2 for PvP mode
|
||||
review_process(GAME_MODE_PVP); // 双人对战模式
|
||||
handle_save_record(GAME_MODE_PVP); // 双人对战模式
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -437,7 +560,8 @@ void run_network_game()
|
||||
scores_calculated = 0;
|
||||
|
||||
// 初始化网络模块
|
||||
if (!init_network()) {
|
||||
if (!init_network())
|
||||
{
|
||||
printf("网络初始化失败!\n");
|
||||
pause_for_input("按任意键返回主菜单...");
|
||||
return;
|
||||
@@ -451,27 +575,96 @@ void run_network_game()
|
||||
|
||||
bool connection_success = false;
|
||||
|
||||
if (choice == 1) {
|
||||
if (choice == 1)
|
||||
{
|
||||
// 服务器模式
|
||||
int port = get_integer_input("请输入监听端口(默认8888): ", MIN_NETWORK_PORT, MAX_NETWORK_PORT);
|
||||
if (port == 0) port = network_port;
|
||||
|
||||
printf("\n正在创建房间...\n");
|
||||
connection_success = create_server(port);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// 客户端模式
|
||||
char ip[MAX_IP_LENGTH];
|
||||
printf("请输入服务器IP地址: ");
|
||||
scanf("%s", ip);
|
||||
|
||||
// 循环直到输入有效的IP地址或用户选择退出
|
||||
while (1)
|
||||
{
|
||||
printf("请输入服务器IP地址 (输入'exit'退出): ");
|
||||
if (scanf("%s", ip) != 1)
|
||||
{
|
||||
printf("输入错误,请重新输入。\n");
|
||||
// 清除输入缓冲区
|
||||
while (getchar() != '\n');
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查是否要退出
|
||||
if (strcmp(ip, "exit") == 0 || strcmp(ip, "EXIT") == 0)
|
||||
{
|
||||
printf("取消连接,返回主菜单。\n");
|
||||
cleanup_network();
|
||||
pause_for_input("按任意键返回主菜单...");
|
||||
return;
|
||||
}
|
||||
|
||||
// 简单的IP地址格式验证
|
||||
if (strlen(ip) < 7 || strlen(ip) > 15)
|
||||
{
|
||||
printf("IP地址格式错误!请输入有效的IP地址(如:192.168.1.100)\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查IP地址是否包含有效字符
|
||||
bool valid_ip = true;
|
||||
for (int i = 0; i < strlen(ip); i++)
|
||||
{
|
||||
if (!(isdigit(ip[i]) || ip[i] == '.'))
|
||||
{
|
||||
valid_ip = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid_ip)
|
||||
{
|
||||
printf("IP地址格式错误!只能包含数字和点号。\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查点号数量
|
||||
int dot_count = 0;
|
||||
for (int i = 0; i < strlen(ip); i++)
|
||||
{
|
||||
if (ip[i] == '.') dot_count++;
|
||||
}
|
||||
|
||||
if (dot_count != 3)
|
||||
{
|
||||
printf("IP地址格式错误!应包含3个点号(如:192.168.1.100)\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("输入的IP地址: %s\n", ip);
|
||||
int confirm = get_integer_input("确认连接到此IP?(1:是/0:否,重新输入): ", 0, 1);
|
||||
if (confirm)
|
||||
{
|
||||
break; // 确认IP地址,跳出循环
|
||||
}
|
||||
// 如果选择否,继续循环重新输入
|
||||
}
|
||||
|
||||
int port = get_integer_input("请输入服务器端口(默认8888): ", MIN_NETWORK_PORT, MAX_NETWORK_PORT);
|
||||
if (port == 0) port = network_port;
|
||||
|
||||
printf("\n正在连接到服务器...\n");
|
||||
printf("\n正在连接到服务器 %s:%d...\n", ip, port);
|
||||
connection_success = connect_to_server(ip, port);
|
||||
}
|
||||
|
||||
if (!connection_success) {
|
||||
if (!connection_success)
|
||||
{
|
||||
printf("网络连接失败!\n");
|
||||
cleanup_network();
|
||||
pause_for_input("按任意键返回主菜单...");
|
||||
@@ -487,11 +680,14 @@ void run_network_game()
|
||||
empty_board();
|
||||
print_board();
|
||||
|
||||
if (network_game_loop()) {
|
||||
if (network_game_loop())
|
||||
{
|
||||
printf("===== 游戏结束 =====\n");
|
||||
review_process(2); // 使用PvP模式的复盘
|
||||
handle_save_record(2); // 保存为PvP模式记录
|
||||
} else {
|
||||
review_process(GAME_MODE_NETWORK); // 网络对战模式的复盘
|
||||
handle_save_record(GAME_MODE_NETWORK); // 保存为网络对战模式记录
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("游戏因网络错误而结束\n");
|
||||
}
|
||||
|
||||
@@ -505,128 +701,177 @@ void run_network_game()
|
||||
*/
|
||||
bool handle_network_player_turn(int current_player, bool is_local_turn)
|
||||
{
|
||||
if (is_local_turn) {
|
||||
if (is_local_turn)
|
||||
{
|
||||
// 本地玩家回合
|
||||
int x, y;
|
||||
time_t start_time, end_time;
|
||||
|
||||
if (use_timer) {
|
||||
if (use_timer)
|
||||
{
|
||||
time(&start_time);
|
||||
}
|
||||
|
||||
|
||||
printf("\n轮到你了,请输入落子坐标(行 列,1~%d),或输入R/r悔棋,S/s认输: ", BOARD_SIZE);
|
||||
|
||||
while (1) {
|
||||
if (use_timer) {
|
||||
time(&end_time);
|
||||
if (difftime(end_time, start_time) > time_limit) {
|
||||
printf("\n你超时了,对方获胜!\n");
|
||||
send_surrender(); // 发送认输消息
|
||||
return false;
|
||||
while (1)
|
||||
{
|
||||
printf("\n轮到你了,请输入落子坐标(行 列,1~%d),或输入R/r悔棋,S/s认输: ", BOARD_SIZE);
|
||||
|
||||
bool input_received = false;
|
||||
while (!input_received)
|
||||
{
|
||||
if (use_timer)
|
||||
{
|
||||
time(&end_time);
|
||||
if (difftime(end_time, start_time) > time_limit)
|
||||
{
|
||||
printf("\n你超时了,对方获胜!\n");
|
||||
send_surrender(); // 发送认输消息
|
||||
return 0; // 游戏结束
|
||||
}
|
||||
}
|
||||
|
||||
int parse_result = parse_network_player_input(&x, &y);
|
||||
if (parse_result == 1) // 有效坐标输入
|
||||
{
|
||||
input_received = true;
|
||||
}
|
||||
else if (parse_result == -1) // 认输命令
|
||||
{
|
||||
printf("\n你选择认输,对方获胜!\n");
|
||||
send_surrender();
|
||||
return 0; // 游戏结束
|
||||
}
|
||||
else if (parse_result == 2) // 悔棋成功
|
||||
{
|
||||
return 2; // 悔棋发生,需要重新开始回合
|
||||
}
|
||||
else // parse_result == 0, 特殊命令已处理或无效输入
|
||||
{
|
||||
// 继续等待输入
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (parse_player_input(&x, &y)) {
|
||||
if (x == INPUT_SURRENDER) {
|
||||
printf("\n你选择认输,对方获胜!\n");
|
||||
send_surrender();
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
// 处理特殊命令或继续等待输入
|
||||
continue;
|
||||
x--; y--; // 转换为0-based坐标
|
||||
|
||||
if (player_move(x, y, current_player))
|
||||
{
|
||||
break; // 成功落子,跳出循环
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("坐标无效!请重新输入。\n");
|
||||
// 继续循环,重新输入坐标
|
||||
}
|
||||
}
|
||||
|
||||
x--; y--; // 转换为0-based坐标
|
||||
|
||||
if (!player_move(x, y, current_player)) {
|
||||
printf("坐标无效!请重新输入。\n");
|
||||
return true; // 继续当前回合
|
||||
}
|
||||
|
||||
// 发送落子消息
|
||||
if (!send_move(x, y, current_player)) {
|
||||
if (!send_move(x, y, current_player))
|
||||
{
|
||||
printf("发送落子消息失败!\n");
|
||||
return false;
|
||||
return 0; // 游戏结束
|
||||
}
|
||||
|
||||
print_board();
|
||||
|
||||
if (check_win(x, y, current_player)) {
|
||||
if (check_win(x, y, current_player))
|
||||
{
|
||||
printf("\n你获胜了!\n");
|
||||
return false;
|
||||
return 0; // 游戏结束
|
||||
}
|
||||
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// 等待对方落子
|
||||
printf("\n等待对方落子...\n");
|
||||
|
||||
NetworkMessage msg;
|
||||
time_t start_time = time(NULL);
|
||||
|
||||
while (1) {
|
||||
if (receive_network_message(&msg, 1000)) { // 1秒超时
|
||||
if (msg.type == MSG_MOVE && msg.player_id == current_player) {
|
||||
while (1)
|
||||
{
|
||||
if (receive_network_message(&msg, 1000))
|
||||
{
|
||||
// 1秒超时
|
||||
if (msg.type == MSG_MOVE && msg.player_id == current_player)
|
||||
{
|
||||
// 收到落子消息
|
||||
if (!player_move(msg.x, msg.y, current_player)) {
|
||||
if (!player_move(msg.x, msg.y, current_player))
|
||||
{
|
||||
printf("收到无效的落子坐标!\n");
|
||||
return false;
|
||||
return 0; // 游戏结束
|
||||
}
|
||||
|
||||
printf("对方落子: (%d, %d)\n", msg.x + 1, msg.y + 1);
|
||||
print_board();
|
||||
|
||||
if (check_win(msg.x, msg.y, current_player)) {
|
||||
if (check_win(msg.x, msg.y, current_player))
|
||||
{
|
||||
printf("\n对方获胜!\n");
|
||||
return false;
|
||||
return 0; // 游戏结束
|
||||
}
|
||||
break;
|
||||
|
||||
} else if (msg.type == MSG_SURRENDER) {
|
||||
}
|
||||
else if (msg.type == MSG_SURRENDER)
|
||||
{
|
||||
printf("\n对方认输,你获胜了!\n");
|
||||
return false;
|
||||
return 0; // 游戏结束
|
||||
|
||||
} else if (msg.type == MSG_DISCONNECT) {
|
||||
}
|
||||
else if (msg.type == MSG_DISCONNECT)
|
||||
{
|
||||
printf("\n对方已断开连接\n");
|
||||
return false;
|
||||
return 0; // 游戏结束
|
||||
|
||||
} else if (msg.type == MSG_CHAT) {
|
||||
}
|
||||
else if (msg.type == MSG_CHAT)
|
||||
{
|
||||
printf("[对方]: %s\n", msg.message);
|
||||
|
||||
} else if (msg.type == MSG_UNDO_REQUEST) {
|
||||
}
|
||||
else if (msg.type == MSG_UNDO_REQUEST)
|
||||
{
|
||||
int steps = msg.x;
|
||||
printf("\n对方请求悔棋 %d 步,是否同意?(1:同意/0:拒绝): ", steps);
|
||||
int response = get_integer_input("", 0, 1);
|
||||
|
||||
if (response && return_move(steps * 2)) {
|
||||
if (response && return_move(steps * 2))
|
||||
{
|
||||
printf("同意悔棋,双方各退 %d 步\n", steps);
|
||||
send_undo_response(true, steps);
|
||||
print_board();
|
||||
return true; // 继续游戏
|
||||
} else {
|
||||
// 悔棋后需要重新开始当前回合,不改变current_player
|
||||
return 2; // 悔棋发生,需要重新开始回合
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("拒绝悔棋\n");
|
||||
send_undo_response(false, steps);
|
||||
// 继续等待对方落子
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查超时
|
||||
if (use_timer && difftime(time(NULL), start_time) > time_limit) {
|
||||
if (use_timer && difftime(time(NULL), start_time) > time_limit)
|
||||
{
|
||||
printf("\n对方超时,你获胜!\n");
|
||||
return false;
|
||||
return 0; // 游戏结束
|
||||
}
|
||||
|
||||
// 检查网络连接
|
||||
if (!is_network_connected()) {
|
||||
if (!is_network_connected())
|
||||
{
|
||||
printf("\n网络连接断开\n");
|
||||
return false;
|
||||
return 0; // 游戏结束
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return 1; // 正常回合完成
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -636,15 +881,23 @@ bool network_game_loop()
|
||||
{
|
||||
int current_player = PLAYER1; // 总是从玩家1开始
|
||||
|
||||
while (1) {
|
||||
while (1)
|
||||
{
|
||||
bool is_local_turn = (current_player == network_state.local_player_id);
|
||||
|
||||
if (!handle_network_player_turn(current_player, is_local_turn)) {
|
||||
return true; // 游戏结束
|
||||
int turn_result = handle_network_player_turn(current_player, is_local_turn);
|
||||
if (turn_result == 0) // 游戏结束
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (turn_result == 2) // 悔棋发生,重新开始当前回合
|
||||
{
|
||||
continue; // 不切换玩家,重新开始当前回合
|
||||
}
|
||||
|
||||
// 检查平局
|
||||
if (step_count == BOARD_SIZE * BOARD_SIZE) {
|
||||
if (step_count == BOARD_SIZE * BOARD_SIZE)
|
||||
{
|
||||
printf("\n平局!\n");
|
||||
return true;
|
||||
}
|
||||
@@ -653,7 +906,8 @@ bool network_game_loop()
|
||||
current_player = (current_player == PLAYER1) ? PLAYER2 : PLAYER1;
|
||||
|
||||
// 检查网络连接
|
||||
if (!is_network_connected()) {
|
||||
if (!is_network_connected())
|
||||
{
|
||||
printf("\n网络连接断开\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
+9
-6
@@ -1,12 +1,6 @@
|
||||
/**
|
||||
* @file game_mode.h
|
||||
* @author 刘航宇(3364451258@qq.com、15236416560@163.com、lhy3364451258@outlook.com)
|
||||
* @brief 五子棋游戏框架头文件
|
||||
* @version 4.0
|
||||
* @date 2025-07-02
|
||||
*
|
||||
* @copyright Copyright (c) 2025
|
||||
*
|
||||
* @note 本文件定义了五子棋游戏的四种主要模式:
|
||||
* 1. AI对战模式
|
||||
* 2. 双人对战模式
|
||||
@@ -40,6 +34,15 @@ int get_integer_input(const char *prompt, int min, int max);
|
||||
*/
|
||||
bool parse_player_input(int *x, int *y);
|
||||
|
||||
/**
|
||||
* @brief 解析网络对战模式下的玩家输入
|
||||
* @param x 行坐标指针
|
||||
* @param y 列坐标指针
|
||||
* @return true 有效坐标输入
|
||||
* @return false 特殊命令或无效输入
|
||||
*/
|
||||
bool parse_network_player_input(int *x, int *y);
|
||||
|
||||
/**
|
||||
* @brief 处理AI回合
|
||||
*
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
/**
|
||||
* @file globals.h
|
||||
* @author 刘航宇(3364451258@qq.com、15236416560@163.com、lhy3364451258@outlook.com)
|
||||
* @brief 全局变量声明头文件
|
||||
* @version 6.0
|
||||
* @date 2025-07-10
|
||||
* @note 集中管理所有全局变量的声明,提高代码可维护性
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
/**
|
||||
* @file gobang.h
|
||||
* @brief 五子棋游戏头文件
|
||||
* @note 本文件定义了五子棋游戏的主要数据结构、函数和全局变量。
|
||||
* 它包含了游戏棋盘的表示、玩家操作、规则检查以及AI决策等功能。
|
||||
*/
|
||||
#ifndef GO_BANG_H
|
||||
#define GO_BANG_H
|
||||
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
/**
|
||||
* @file init_board.h
|
||||
* @brief 初始化游戏棋盘头文件
|
||||
* @note 本文件定义了初始化游戏棋盘的相关函数和全局变量。
|
||||
* 它负责设置游戏的初始状态,包括棋盘大小、玩家标识、游戏规则等。
|
||||
*/
|
||||
#ifndef INIT_BOARD_H
|
||||
#define INIT_BOARD_H
|
||||
|
||||
|
||||
@@ -37,31 +37,39 @@ int main(int argc, char *argv[])
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
// 1. 人机对战
|
||||
case 1:
|
||||
run_ai_game();
|
||||
break;
|
||||
// 2. 玩家对战
|
||||
case 2:
|
||||
run_pvp_game();
|
||||
break;
|
||||
// 3. 网络对战
|
||||
case 3:
|
||||
run_network_game();
|
||||
break;
|
||||
// 4. 复盘模式
|
||||
case 4:
|
||||
run_review_mode();
|
||||
break;
|
||||
// 5. 配置管理
|
||||
case 5:
|
||||
config_management_menu();
|
||||
break;
|
||||
// 6. 游戏规则
|
||||
case 6:
|
||||
clear_screen();
|
||||
display_game_rules();
|
||||
pause_for_input("\n按任意键返回主菜单...");
|
||||
break;
|
||||
// 7. 关于
|
||||
case 7:
|
||||
clear_screen();
|
||||
display_about();
|
||||
pause_for_input("\n按任意键返回主菜单...");
|
||||
break;
|
||||
// 8. 退出游戏
|
||||
case 8:
|
||||
save_game_config();
|
||||
printf("感谢使用五子棋游戏!\n");
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
/**
|
||||
* @file network.h
|
||||
* @author 刘航宇(3364451258@qq.com、15236416560@163.com、lhy3364451258@outlook.com)
|
||||
* @brief 五子棋网络对战模块头文件
|
||||
* @version 1.0
|
||||
* @date 2025-01-15
|
||||
*
|
||||
* @copyright Copyright (c) 2025
|
||||
*
|
||||
* @note 本文件定义了五子棋游戏的网络对战功能:
|
||||
* 1. 服务器模式(主机)
|
||||
* 2. 客户端模式(加入游戏)
|
||||
|
||||
@@ -75,7 +75,7 @@ void review_process(int game_mode)
|
||||
|
||||
// 打印当前步骤信息
|
||||
// 根据游戏模式显示不同的标题和玩家信息
|
||||
if (game_mode == 1)
|
||||
if (game_mode == GAME_MODE_AI)
|
||||
{
|
||||
// 人机对战
|
||||
printf("\n===== 五子棋人机对战(%dX%d棋盘) =====", BOARD_SIZE, BOARD_SIZE);
|
||||
@@ -84,7 +84,7 @@ void review_process(int game_mode)
|
||||
(s.player == PLAYER) ? "玩家" : "AI",
|
||||
s.x + 1, s.y + 1);
|
||||
}
|
||||
else
|
||||
else if (game_mode == GAME_MODE_PVP)
|
||||
{
|
||||
// 双人对战
|
||||
printf("\n===== 五子棋双人对战(%dX%d棋盘) =====", BOARD_SIZE, BOARD_SIZE);
|
||||
@@ -93,6 +93,15 @@ void review_process(int game_mode)
|
||||
(s.player == PLAYER1) ? "玩家1(黑棋)" : "玩家2(白棋)",
|
||||
s.x + 1, s.y + 1);
|
||||
}
|
||||
else if (game_mode == GAME_MODE_NETWORK)
|
||||
{
|
||||
// 网络对战
|
||||
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(" ");
|
||||
@@ -222,14 +231,21 @@ void display_game_scores(int game_mode)
|
||||
|
||||
if (sum_score > 0)
|
||||
{
|
||||
if (game_mode == 1)
|
||||
if (game_mode == GAME_MODE_AI)
|
||||
{
|
||||
printf("玩家得分: %d, 占比: %.2f%%\n",
|
||||
player1_final_score, (double)player1_final_score * 100.0 / sum_score);
|
||||
printf("AI得分: %d, 占比: %.2f%%\n",
|
||||
player2_final_score, (double)player2_final_score * 100.0 / sum_score);
|
||||
}
|
||||
else
|
||||
else if (game_mode == GAME_MODE_PVP)
|
||||
{
|
||||
printf("玩家1(黑棋)得分: %d, 占比: %.2f%%\n",
|
||||
player1_final_score, (double)player1_final_score * 100.0 / sum_score);
|
||||
printf("玩家2(白棋)得分: %d, 占比: %.2f%%\n",
|
||||
player2_final_score, (double)player2_final_score * 100.0 / sum_score);
|
||||
}
|
||||
else if (game_mode == GAME_MODE_NETWORK)
|
||||
{
|
||||
printf("玩家1(黑棋)得分: %d, 占比: %.2f%%\n",
|
||||
player1_final_score, (double)player1_final_score * 100.0 / sum_score);
|
||||
@@ -239,7 +255,7 @@ void display_game_scores(int game_mode)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (game_mode == 1)
|
||||
if (game_mode == GAME_MODE_AI)
|
||||
{
|
||||
printf("玩家得分: %d\n", player1_final_score);
|
||||
printf("AI得分: %d\n", player2_final_score);
|
||||
@@ -255,11 +271,11 @@ void display_game_scores(int game_mode)
|
||||
// 评选MVP
|
||||
if (player1_final_score > player2_final_score)
|
||||
{
|
||||
printf("\nMVP: %s (领先 %d 分)\n", (game_mode == 1) ? "玩家" : "玩家1(黑棋)", player1_final_score - player2_final_score);
|
||||
printf("\nMVP: %s (领先 %d 分)\n", (game_mode == GAME_MODE_AI) ? "玩家" : "玩家1(黑棋)", player1_final_score - player2_final_score);
|
||||
}
|
||||
else if (player2_final_score > player1_final_score)
|
||||
{
|
||||
printf("\nMVP: %s (领先 %d 分)\n", (game_mode == 1) ? "AI" : "玩家2(白棋)", player2_final_score - player1_final_score);
|
||||
printf("\nMVP: %s (领先 %d 分)\n", (game_mode == GAME_MODE_AI) ? "AI" : "玩家2(白棋)", player2_final_score - player1_final_score);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -362,7 +378,7 @@ int save_game_to_file(const char *filename, int game_mode)
|
||||
Step last_step = steps[step_count - 1];
|
||||
if (check_win(last_step.x, last_step.y, last_step.player))
|
||||
{
|
||||
if (game_mode == 1)
|
||||
if (game_mode == GAME_MODE_AI)
|
||||
{
|
||||
// 人机对战
|
||||
if (last_step.player == PLAYER)
|
||||
@@ -374,7 +390,7 @@ int save_game_to_file(const char *filename, int game_mode)
|
||||
strcpy(winner_info, "AI获胜");
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (game_mode == GAME_MODE_PVP)
|
||||
{
|
||||
// 双人对战
|
||||
if (last_step.player == PLAYER1)
|
||||
@@ -386,6 +402,18 @@ int save_game_to_file(const char *filename, int game_mode)
|
||||
strcpy(winner_info, "玩家2获胜");
|
||||
}
|
||||
}
|
||||
else if (game_mode == GAME_MODE_NETWORK)
|
||||
{
|
||||
// 网络对战
|
||||
if (last_step.player == PLAYER1)
|
||||
{
|
||||
strcpy(winner_info, "玩家1获胜");
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(winner_info, "玩家2获胜");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -464,7 +492,7 @@ int load_game_from_file(const char *filename)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (game_mode != 1 && game_mode != 2)
|
||||
if (game_mode != GAME_MODE_AI && game_mode != GAME_MODE_PVP && game_mode != GAME_MODE_NETWORK)
|
||||
{
|
||||
fclose(file);
|
||||
return 0; // 无效的游戏模式
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
/**
|
||||
* @file record.h
|
||||
* @brief 游戏复盘与记录头文件
|
||||
* @note 本文件定义了游戏复盘与记录相关的函数和数据结构。
|
||||
* 它负责管理游戏的历史记录、加载和保存游戏文件、计算游戏评分等功能。
|
||||
*/
|
||||
#ifndef RECORD_H
|
||||
#define RECORD_H
|
||||
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
/**
|
||||
* @file ui.h
|
||||
* @brief
|
||||
* @note 本文件定义了用户界面相关的函数和数据结构。
|
||||
* 它负责处理用户输入、显示游戏界面、提示信息等与用户交互的功能。
|
||||
*/
|
||||
#ifndef UI_H
|
||||
#define UI_H
|
||||
|
||||
|
||||
Reference in New Issue
Block a user