diff --git a/.gitignore b/.gitignore index a3f37de..9803916 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.exe *.out *.app +*.o # IDE配置文件 .idea/ diff --git a/MD/BUILD.md b/MD/BUILD.md new file mode 100644 index 0000000..bddfe65 --- /dev/null +++ b/MD/BUILD.md @@ -0,0 +1,73 @@ +# 五子棋游戏编译指南 + +本项目现在支持使用 `make` 命令进行编译,提供了更便捷的构建方式。 + +## 系统要求 + +- MinGW64 编译器 +- SDL3 开发库(用于图形界面) +- Make 工具 + +## 编译命令 + +### 查看所有可用命令 +```bash +make help +``` + +### 编译所有版本 +```bash +make all +``` +这将同时编译控制台版本和GUI版本。 + +### 只编译控制台版本 +```bash +make console +``` +生成 `gobang_console.exe` + +### 只编译GUI版本 +```bash +make gui +``` +生成 `gobang_gui.exe` + +### 清理编译文件 +```bash +make clean +``` +删除所有目标文件(.o)和可执行文件(.exe) + +### 编译并运行 +```bash +# 编译并运行控制台版本 +make run-console + +# 编译并运行GUI版本 +make run-gui +``` + +## 生成的文件 + +- `gobang_console.exe` - 控制台版本,支持所有功能包括图形界面模式 +- `gobang_gui.exe` - GUI版本,与控制台版本功能相同 + +## 注意事项 + +1. 两个版本都包含完整功能,包括图形界面支持 +2. 需要确保SDL3库路径正确配置在Makefile中 +3. 编译时会显示一些警告,这是正常的 +4. 如果遇到编译错误,请检查MinGW64和SDL3的安装路径 + +## 传统编译方式 + +如果不使用Makefile,仍可以使用传统的gcc命令: + +```bash +# 控制台版本 +gcc -std=c17 -o gobang.exe *.c -lws2_32 + +# GUI版本 +gcc -std=c17 -o gobang_gui.exe *.c -ID:\settings\SDL\SDL3-3.2.22\x86_64-w64-mingw32\include -LD:\settings\SDL\SDL3-3.2.22\x86_64-w64-mingw32\lib -lSDL3 -lws2_32 +``` \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0e0fa29 --- /dev/null +++ b/Makefile @@ -0,0 +1,80 @@ +# 五子棋游戏 Makefile +# 支持编译控制台版本和GUI版本 + +# 编译器设置 +CC = gcc +CFLAGS = -Wall -Wextra -std=c17 -O2 +LDFLAGS = -lws2_32 + +# SDL3路径设置 +SDL3_PATH = D:/settings/SDL/SDL3-3.2.22/x86_64-w64-mingw32 +SDL3_INCLUDE = -I$(SDL3_PATH)/include +SDL3_LIBS = -L$(SDL3_PATH)/lib -lSDL3 -lmingw32 + +# 源文件 +COMMON_SOURCES = main.c gobang.c ai.c config.c game_mode.c globals.c \ + init_board.c network.c record.c ui.c gui.c type.h + +GUI_SOURCES = $(COMMON_SOURCES) +CONSOLE_SOURCES = $(COMMON_SOURCES) + +# 目标文件 +COMMON_OBJECTS = $(patsubst %.c,%.o,$(filter %.c,$(COMMON_SOURCES))) + +# 可执行文件 +CONSOLE_TARGET = gobang_console.exe +GUI_TARGET = gobang_gui.exe + +# 默认目标 +all: $(CONSOLE_TARGET) $(GUI_TARGET) + +# 控制台版本 +$(CONSOLE_TARGET): $(COMMON_OBJECTS) + $(CC) $(CFLAGS) $(SDL3_INCLUDE) -o $@ $^ $(SDL3_LIBS) $(LDFLAGS) + +# GUI版本 +$(GUI_TARGET): $(COMMON_OBJECTS) + $(CC) $(CFLAGS) $(SDL3_INCLUDE) -o $@ $^ $(SDL3_LIBS) $(LDFLAGS) + +# 通用目标文件编译规则(包含SDL3头文件路径,因为多个文件包含gui.h) +%.o: %.c + $(CC) $(CFLAGS) $(SDL3_INCLUDE) -c -o $@ $< + +# 清理规则 +clean: + del /Q *.o *.exe 2>nul || true + +# 只编译控制台版本 +console: $(CONSOLE_TARGET) + +# 只编译GUI版本 +gui: $(GUI_TARGET) + +# 安装规则(可选) +install: all + @echo Installing executables... + copy $(CONSOLE_TARGET) C:\Program Files\Gobang\ 2>nul || echo Install directory not found + copy $(GUI_TARGET) C:\Program Files\Gobang\ 2>nul || echo Install directory not found + +# 运行控制台版本 +run-console: $(CONSOLE_TARGET) + .\$(CONSOLE_TARGET) + +# 运行GUI版本 +run-gui: $(GUI_TARGET) + .\$(GUI_TARGET) + +# 帮助信息 +help: + @echo Available targets: + @echo all - Build both console and GUI versions + @echo console - Build console version only + @echo gui - Build GUI version only + @echo clean - Remove all object files and executables + @echo run-console - Build and run console version + @echo run-gui - Build and run GUI version + @echo install - Install executables to system directory + @echo help - Show this help message + +# 声明伪目标 +.PHONY: all clean console gui install run-console run-gui help \ No newline at end of file diff --git a/README.md b/README.md index bc0c138..0be129e 100644 --- a/README.md +++ b/README.md @@ -19,22 +19,10 @@ - 📱 **响应式界面** - 自适应窗口大小和分辨率 - 🚀 **性能优化** - 图形渲染和事件处理性能提升 -### v7.0 (2025-07-20) - 代码架构重构更新 -- 🏗️ **结构体定义集中化** - 所有数据结构统一管理在type.h中 -- ⚙️ **配置参数统一管理** - 所有配置宏定义集中在config.h中 -- 🔧 **代码模块化优化** - 消除重复定义,提高代码可维护性 -- 📋 **菜单选项优化** - 退出选项调整为"0. 退出游戏" -- 🎯 **类型系统完善** - 独立的type.h文件管理所有数据类型 -- 🌐 **网络配置重构** - 网络相关宏定义统一到config.h -- 📊 **全局变量管理** - 优化全局变量声明和定义结构 -- 🔄 **头文件依赖优化** - 改进模块间依赖关系和包含结构 - - ## 目录 - [C语言五子棋人机对战AI](#c语言五子棋人机对战ai) - [📋 大版本更新](#-大版本更新) - [v8.0 (2025-01-18) - GUI图形化界面更新](#v80-2025-01-18---gui图形化界面更新) - - [v7.0 (2025-07-20) - 代码架构重构更新](#v70-2025-07-20---代码架构重构更新) - [目录](#目录) - [项目简介](#项目简介) - [功能特性](#功能特性) @@ -45,7 +33,11 @@ - [🔧 技术特性](#-技术特性) - [快速开始](#快速开始) - [编译项目](#编译项目) + - [控制台版本编译](#控制台版本编译) + - [GUI版本编译(需要SDL3)](#gui版本编译需要sdl3) - [运行游戏](#运行游戏) + - [控制台版本](#控制台版本) + - [GUI版本](#gui版本) - [游戏玩法](#游戏玩法) - [🚀 快速开始](#-快速开始) - [🎯 对局操作](#-对局操作) diff --git a/config.h b/config.h index 29cfd1f..28af3ca 100644 --- a/config.h +++ b/config.h @@ -116,7 +116,23 @@ #define TIME_WEIGHT_FACTOR 0.5 // 时间权重因子 #define WIN_BONUS 2000 // 胜利奖励分数 -// 文件路径参数 +//---------- GUI界面参数 ----------// +// 窗口和棋盘配置 +#define WINDOW_WIDTH 800 +#define WINDOW_HEIGHT 600 +#define BOARD_OFFSET_X 50 +#define BOARD_OFFSET_Y 50 +#define CELL_SIZE 30 +#define STONE_RADIUS 12 + +// 颜色定义 +#define GUI_COLOR_BACKGROUND {240, 217, 181, 255} +#define GUI_COLOR_BOARD_LINE {0, 0, 0, 255} +#define GUI_COLOR_BLACK_STONE {0, 0, 0, 255} +#define GUI_COLOR_WHITE_STONE {255, 255, 255, 255} +#define GUI_COLOR_STONE_BORDER {100, 100, 100, 255} + +//---------- 文件路径参数 ----------// #define RECORDS_DIR "records" // 记录文件目录 #define CONFIG_FILE "gobang_config.ini" // 配置文件路径 #define MAX_PATH_LENGTH 256 // 最大路径长度 diff --git a/globals.c b/globals.c index 7f5af34..bff3f45 100644 --- a/globals.c +++ b/globals.c @@ -7,6 +7,7 @@ #include "globals.h" #include "config.h" +#include // ==================== 游戏核心变量定义 ==================== int BOARD_SIZE = DEFAULT_BOARD_SIZE; // 实际使用的棋盘尺寸 @@ -28,6 +29,14 @@ double defense_coefficient = DEFAULT_DEFENSE_COEFFICIENT; // 防守系数 // ==================== 网络相关变量定义 ==================== NetworkGameState network_state = {0}; // 网络游戏状态 +// ==================== GUI相关变量定义 ==================== +SDL_Window* window = NULL; // SDL窗口指针 +SDL_Renderer* renderer = NULL; // SDL渲染器指针 +int gui_running = 1; // GUI运行状态标志 +int current_player_gui = PLAYER; // GUI当前玩家 +int game_over = 0; // 游戏结束标志 +char status_message[256] = "五子棋游戏 - 黑子先行"; // 状态消息 + // ==================== 记录相关变量定义 ==================== int player1_final_score = 0; // 玩家1最终得分 int player2_final_score = 0; // 玩家2最终得分 diff --git a/globals.h b/globals.h index 92b7036..d518996 100644 --- a/globals.h +++ b/globals.h @@ -11,6 +11,7 @@ #include "gobang.h" #include "network.h" #include +#include // ==================== 游戏核心变量 ==================== extern int BOARD_SIZE; // 当前实际使用的棋盘尺寸 @@ -32,6 +33,14 @@ extern double defense_coefficient; // 防守系数 // ==================== 网络相关变量 ==================== extern NetworkGameState network_state; // 网络游戏状态 +// ==================== GUI相关变量 ==================== +extern SDL_Window* window; // SDL窗口指针 +extern SDL_Renderer* renderer; // SDL渲染器指针 +extern int gui_running; // GUI运行状态标志 +extern int current_player_gui; // GUI当前玩家 +extern int game_over; // 游戏结束标志 +extern char status_message[256]; // 状态消息 + // ==================== 记录相关变量 ==================== extern int player1_final_score; // 玩家1最终得分 extern int player2_final_score; // 玩家2最终得分 diff --git a/gui.c b/gui.c index 0b6442c..891d497 100644 --- a/gui.c +++ b/gui.c @@ -15,17 +15,17 @@ #include #include -// 全局变量 -SDL_Window* window = NULL; -SDL_Renderer* renderer = NULL; -int gui_running = 1; -int current_player_gui = PLAYER; -int game_over = 0; -char status_message[256] = "五子棋游戏 - 黑子先行"; - /** * @brief 初始化GUI + * @details 初始化SDL3图形库和游戏界面组件: + * - 初始化SDL视频子系统 + * - 创建游戏窗口(可调整大小) + * - 创建SDL渲染器 + * - 初始化游戏状态和棋盘数据 * @return 成功返回0,失败返回-1 + * @note 窗口标题为"五子棋游戏 - SDL3版本" + * 窗口尺寸由WINDOW_WIDTH和WINDOW_HEIGHT定义 + * 失败时会自动清理已创建的资源 */ int init_gui() { if (SDL_Init(SDL_INIT_VIDEO) < 0) { @@ -78,6 +78,13 @@ int init_gui() { /** * @brief 清理GUI资源 + * @details 按顺序释放所有SDL相关资源: + * - 销毁SDL渲染器 + * - 销毁SDL窗口 + * - 退出SDL子系统 + * @note 函数会检查资源是否存在再进行释放 + * 释放后将指针设置为NULL防止重复释放 + * 程序退出时必须调用此函数避免内存泄漏 */ void cleanup_gui() { if (renderer) { @@ -94,6 +101,15 @@ void cleanup_gui() { /** * @brief 渲染游戏画面 + * @details 完整的游戏画面渲染流程: + * - 清空屏幕并设置背景色 + * - 绘制棋盘网格和标记点 + * - 绘制所有棋子 + * - 绘制UI界面元素 + * - 将渲染结果显示到屏幕 + * @note 使用双缓冲技术,通过SDL_RenderPresent显示最终结果 + * 背景色由GUI_COLOR_BACKGROUND定义 + * 每帧都会完全重绘整个画面 */ void render_game() { // 清空屏幕 - 设置背景色 @@ -116,7 +132,14 @@ void render_game() { /** * @brief 处理事件 + * @details 处理所有SDL事件并执行相应操作: + * - SDL_EVENT_QUIT:用户关闭窗口 + * - SDL_EVENT_KEY_DOWN:键盘按键(ESC退出) + * - SDL_EVENT_MOUSE_BUTTON_DOWN:鼠标点击落子 * @return 继续运行返回1,退出返回0 + * @note 鼠标左键点击会转换为棋盘坐标并尝试落子 + * 落子后会检查胜负并切换玩家 + * 游戏结束后不再响应落子操作 */ int handle_events() { SDL_Event event; @@ -172,6 +195,13 @@ int handle_events() { /** * @brief 绘制棋盘 + * @details 绘制15x15的五子棋棋盘,包括: + * - 横竖交叉的网格线 + * - 天元点(棋盘中心的标记点) + * - 四个星位(棋盘上的定位点) + * @note 使用SDL3渲染器绘制线条和填充矩形 + * 棋盘线条颜色由GUI_COLOR_BOARD_LINE定义 + * 天元点和星位用黑色小矩形标记 */ void draw_board() { SDL_Color line_color = GUI_COLOR_BOARD_LINE; @@ -222,6 +252,13 @@ void draw_board() { /** * @brief 绘制棋子 + * @details 遍历整个棋盘数组,绘制所有已落下的棋子: + * - 黑子:使用GUI_COLOR_BLACK_STONE颜色 + * - 白子:使用GUI_COLOR_WHITE_STONE颜色 + * - 每个棋子都有边框:使用GUI_COLOR_STONE_BORDER颜色 + * @note 棋子绘制为圆形,半径由STONE_RADIUS定义 + * 通过draw_circle函数实现圆形绘制 + * 棋子位置根据棋盘坐标和CELL_SIZE计算屏幕坐标 */ void draw_stones() { for (int i = 0; i < BOARD_SIZE; i++) { @@ -256,6 +293,13 @@ void draw_stones() { * @param center_y 圆心Y坐标 * @param radius 半径 * @param color 颜色 + * @details 使用像素级绘制实现圆形: + * - 遍历圆形外接矩形内的所有像素点 + * - 计算每个像素到圆心的距离 + * - 距离小于等于半径的像素点进行着色 + * @note 采用暴力算法,性能较低但实现简单 + * 适用于绘制棋子等小尺寸圆形 + * SDL3没有内置圆形绘制函数,需要自实现 */ void draw_circle(int center_x, int center_y, int radius, SDL_Color color) { SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a); @@ -311,6 +355,13 @@ void draw_ui_elements() { * @param board_x 输出棋盘X坐标 * @param board_y 输出棋盘Y坐标 * @return 转换成功返回1,失败返回0 + * @details 坐标转换算法: + * - 减去棋盘偏移量得到相对坐标 + * - 加上半个格子尺寸实现就近取整 + * - 除以格子尺寸得到棋盘坐标 + * - 检查坐标是否在有效范围内 + * @note 使用就近取整算法,点击格子中心附近都会定位到该格子 + * 坐标范围检查确保不会越界访问棋盘数组 */ int screen_to_board(int screen_x, int screen_y, int* board_x, int* board_y) { int rel_x = screen_x - BOARD_OFFSET_X; @@ -326,6 +377,13 @@ int screen_to_board(int screen_x, int screen_y, int* board_x, int* board_y) { /** * @brief 显示消息 * @param message 要显示的消息 + * @details 消息显示功能: + * - 将消息复制到全局状态消息缓冲区 + * - 同时在控制台输出消息内容 + * - 确保字符串安全复制,防止缓冲区溢出 + * @note 消息会存储在status_message全局变量中 + * 字符串长度限制为缓冲区大小减1 + * 消息可用于游戏状态提示和错误信息显示 */ void show_message(const char* message) { strncpy(status_message, message, sizeof(status_message) - 1); diff --git a/gui.h b/gui.h index 2b7cf4a..865b26b 100644 --- a/gui.h +++ b/gui.h @@ -11,40 +11,144 @@ #include #include "gobang.h" - -// 窗口和棋盘配置 -#define WINDOW_WIDTH 800 -#define WINDOW_HEIGHT 600 -#define BOARD_OFFSET_X 50 -#define BOARD_OFFSET_Y 50 -#define CELL_SIZE 30 -#define STONE_RADIUS 12 - -// 颜色定义 -#define GUI_COLOR_BACKGROUND {240, 217, 181, 255} -#define GUI_COLOR_BOARD_LINE {0, 0, 0, 255} -#define GUI_COLOR_BLACK_STONE {0, 0, 0, 255} -#define GUI_COLOR_WHITE_STONE {255, 255, 255, 255} -#define GUI_COLOR_STONE_BORDER {100, 100, 100, 255} +#include "config.h" +#include "globals.h" // GUI函数声明 + +/** + * @brief 初始化GUI + * @details 初始化SDL3图形库和游戏界面组件: + * - 初始化SDL视频子系统 + * - 创建游戏窗口(可调整大小) + * - 创建SDL渲染器 + * - 初始化游戏状态和棋盘数据 + * @return 成功返回0,失败返回-1 + * @note 窗口标题为"五子棋游戏 - SDL3版本" + * 窗口尺寸由WINDOW_WIDTH和WINDOW_HEIGHT定义 + * 失败时会自动清理已创建的资源 + */ int init_gui(); + +/** + * @brief 清理GUI资源 + * @details 按顺序释放所有SDL相关资源: + * - 销毁SDL渲染器 + * - 销毁SDL窗口 + * - 退出SDL子系统 + * @note 函数会检查资源是否存在再进行释放 + * 释放后将指针设置为NULL防止重复释放 + * 程序退出时必须调用此函数避免内存泄漏 + */ void cleanup_gui(); + +/** + * @brief 渲染游戏画面 + * @details 完整的游戏画面渲染流程: + * - 清空屏幕并设置背景色 + * - 绘制棋盘网格和标记点 + * - 绘制所有棋子 + * - 绘制UI界面元素 + * - 将渲染结果显示到屏幕 + * @note 使用双缓冲技术,通过SDL_RenderPresent显示最终结果 + * 背景色由GUI_COLOR_BACKGROUND定义 + * 每帧都会完全重绘整个画面 + */ void render_game(); + +/** + * @brief 处理事件 + * @details 处理所有SDL事件并执行相应操作: + * - SDL_EVENT_QUIT:用户关闭窗口 + * - SDL_EVENT_KEY_DOWN:键盘按键(ESC退出) + * - SDL_EVENT_MOUSE_BUTTON_DOWN:鼠标点击落子 + * @return 继续运行返回1,退出返回0 + * @note 鼠标左键点击会转换为棋盘坐标并尝试落子 + * 落子后会检查胜负并切换玩家 + * 游戏结束后不再响应落子操作 + */ int handle_events(); + +/** + * @brief 绘制棋盘 + * @details 绘制15x15的五子棋棋盘,包括: + * - 横竖交叉的网格线 + * - 天元点(棋盘中心的标记点) + * - 四个星位(棋盘上的定位点) + * @note 使用SDL3渲染器绘制线条和填充矩形 + * 棋盘线条颜色由GUI_COLOR_BOARD_LINE定义 + * 天元点和星位用黑色小矩形标记 + */ void draw_board(); + +/** + * @brief 绘制棋子 + * @details 遍历整个棋盘数组,绘制所有已落下的棋子: + * - 黑子:使用GUI_COLOR_BLACK_STONE颜色 + * - 白子:使用GUI_COLOR_WHITE_STONE颜色 + * - 每个棋子都有边框:使用GUI_COLOR_STONE_BORDER颜色 + * @note 棋子绘制为圆形,半径由STONE_RADIUS定义 + * 通过draw_circle函数实现圆形绘制 + * 棋子位置根据棋盘坐标和CELL_SIZE计算屏幕坐标 + */ void draw_stones(); + +/** + * @brief 绘制UI元素 + * @details 绘制游戏界面的用户交互元素: + * - 状态信息区域背景和边框 + * - 当前玩家指示器(黑子或白子圆形) + * - 游戏状态显示区域 + * @note 暂时使用简单图形代替文字显示 + * 需要额外字体库支持文字渲染 + * 指示器位置在棋盘右侧固定区域 + */ void draw_ui_elements(); + +/** + * @brief 绘制圆形 + * @param center_x 圆心X坐标 + * @param center_y 圆心Y坐标 + * @param radius 半径 + * @param color 颜色 + * @details 使用像素级绘制实现圆形: + * - 遍历圆形外接矩形内的所有像素点 + * - 计算每个像素到圆心的距离 + * - 距离小于等于半径的像素点进行着色 + * @note 采用暴力算法,性能较低但实现简单 + * 适用于绘制棋子等小尺寸圆形 + * SDL3没有内置圆形绘制函数,需要自实现 + */ void draw_circle(int center_x, int center_y, int radius, SDL_Color color); + +/** + * @brief 屏幕坐标转棋盘坐标 + * @param screen_x 屏幕X坐标 + * @param screen_y 屏幕Y坐标 + * @param board_x 输出棋盘X坐标 + * @param board_y 输出棋盘Y坐标 + * @return 转换成功返回1,失败返回0 + * @details 坐标转换算法: + * - 减去棋盘偏移量得到相对坐标 + * - 加上半个格子尺寸实现就近取整 + * - 除以格子尺寸得到棋盘坐标 + * - 检查坐标是否在有效范围内 + * @note 使用就近取整算法,点击格子中心附近都会定位到该格子 + * 坐标范围检查确保不会越界访问棋盘数组 + */ int screen_to_board(int screen_x, int screen_y, int *board_x, int *board_y); + +/** + * @brief 显示消息 + * @param message 要显示的消息 + * @details 消息显示功能: + * - 将消息复制到全局状态消息缓冲区 + * - 同时在控制台输出消息内容 + * - 确保字符串安全复制,防止缓冲区溢出 + * @note 消息会存储在status_message全局变量中 + * 字符串长度限制为缓冲区大小减1 + * 消息可用于游戏状态提示和错误信息显示 + */ void show_message(const char *message); -// 全局GUI变量 -extern SDL_Window *window; -extern SDL_Renderer *renderer; -extern int gui_running; -extern int current_player_gui; -extern int game_over; -extern char status_message[256]; - #endif // GUI_H \ No newline at end of file