diff --git a/MD/AI_Enhancement_Guide.md b/MD/AI_Enhancement_Guide.md deleted file mode 100644 index 1b6a793..0000000 --- a/MD/AI_Enhancement_Guide.md +++ /dev/null @@ -1,105 +0,0 @@ -## 🎯 项目优势 -### ✅ 已经做得很好的方面 -- 📚 代码质量优秀 :注释覆盖率30.1%,使用Doxygen格式文档 -- 🏗️ 架构设计合理 :模块化设计,职责分离清晰 -- 🎮 功能完整丰富 :支持人机对战、双人对战、网络对战、GUI界面 -- 🔧 技术栈现代化 :SDL3图形库、双版本架构、专业安装包 -- 📋 文档完善 :详细的README、AI增强指南、架构重构指南 -- 🌐 跨平台考虑 :已有条件编译支持Windows/Linux -## 🚀 改进建议 -### 1. 🧪 测试体系建设(高优先级) -当前状况 :项目缺乏自动化测试 - -建议改进 : - -- 添加单元测试框架(如Unity或自制简单测试框架) -- 为核心模块编写测试用例:AI算法、棋盘逻辑、网络通信 -- 添加集成测试验证各模块协作 -- 创建性能基准测试 -### 2. 🛡️ 错误处理和安全性增强(高优先级) -当前状况 :基础错误处理存在,但可以更完善 - -建议改进 : - -- 增强输入验证,防止缓冲区溢出 -- 添加网络通信的安全验证机制 -- 完善内存管理,添加内存泄漏检测 -- 增加异常恢复机制 -### 3. 🎯 AI算法优化(中优先级) -当前状况 :基础Minimax+α-β剪枝,搜索深度3层 - -建议改进 : - -- 实现置换表缓存系统 -- 添加开局库和残局库 -- 实现迭代加深搜索 -- 增加威胁检测优化 -- 支持多线程并行搜索 -### 4. 🔧 构建和部署优化(中优先级) -当前状况 :编译脚本功能完善,但可以更自动化 - -建议改进 : - -- 添加CMake构建系统支持 -- 实现持续集成/持续部署(CI/CD) -- 添加依赖管理和版本控制 -- 完善跨平台构建脚本 -### 5. 📊 性能监控和分析(中优先级) -建议添加 : - -- AI决策时间统计 -- 内存使用监控 -- 网络延迟分析 -- 性能瓶颈识别工具 -### 6. 🎮 用户体验提升(低优先级) -建议改进 : - -- 添加音效和动画效果 -- 实现主题和皮肤系统 -- 增加游戏统计和成就系统 -- 支持自定义快捷键 -### 7. 🌐 网络功能增强(低优先级) -建议改进 : - -- 实现房间系统和匹配机制 -- 添加观战功能 -- 支持断线重连 -- 实现聊天系统 -## 📋 具体实施建议 -### 立即可实施(1-2周) -1. 1. - 创建基础测试框架 -2. 2. - 添加输入验证和边界检查 -3. 3. - 完善错误日志记录 -4. 4. - 优化编译警告处理 -### 短期目标(1-2月) -1. 1. - 完善单元测试覆盖 -2. 2. - 实现置换表和开局库 -3. 3. - 添加性能监控 -4. 4. - 增强网络安全性 -### 长期规划(3-6月) -1. 1. - 实现神经网络AI -2. 2. - 完整跨平台支持 -3. 3. - 添加数据库支持 -4. 4. - 实现云端对战 -## 🏆 总体评价 -你的项目已经达到了 专业级别的开源项目标准 !代码架构清晰、功能完整、文档详尽。主要的改进空间在于测试覆盖和一些高级特性的添加。 - -项目亮点 : - -- 从v7.0的架构重构到v8.2的编译优化,版本迭代思路清晰 -- SDL3图形化界面实现现代化 -- 网络对战功能完整 -- 代码注释和文档非常专业 -这是一个非常值得继续完善和推广的优秀项目!🎉 \ No newline at end of file diff --git a/MD/AI_function.md b/MD/AI_function.md deleted file mode 100644 index fa13c2f..0000000 --- a/MD/AI_function.md +++ /dev/null @@ -1,157 +0,0 @@ -# 🧠 五子棋AI实现详解 - -## 📜 算法概述 -本五子棋AI采用α-β剪枝优化的极小极大算法,结合专业的棋型评估系统和多层次的威胁检测机制。v8.0版本新增SDL3图形化界面支持,提供可视化AI决策过程和双版本架构(控制台+GUI)。支持人机对战、双人对战和网络对战多种模式。 - -```mermaid -graph TD - A[AI决策开始] --> B{威胁检测} - B -->|有威胁| C[防御性落子] - B -->|无威胁| D[α-β剪枝搜索] - D --> E[评估候选位置] - E --> F[选择最优落子] -``` - -## 🔢 数据结构 - -### 🎲 棋盘表示 -```c -int board[MAX_BOARD_SIZE][MAX_BOARD_SIZE]; // 25x25最大棋盘 -``` -- `0` 空位 -- `1` 玩家(✖) -- `2` AI(◯) - -### 📝 步数记录 -```c -typedef struct { - int player; // 1=玩家, 2=AI - int x, y; // 坐标(0-based) -} Step; -Step steps[MAX_STEPS]; // 最大步数记录 -``` - -### 🧭 方向分析 -```c -typedef struct { - int continuous_chess; // 连续同色棋子数 - bool check_start; // 起始方向开放 - bool check_end; // 结束方向开放 -} DirInfo; -``` - -### 🌐 网络对战支持 -```c -// 网络模式下的AI决策 -void network_ai_move(int depth, int player_id); -// 同步AI决策到网络对手 -void sync_ai_decision(int x, int y); -``` - -### 🎨 GUI界面AI支持 (v8.0新增) -```c -// GUI模式下的AI可视化决策 -void gui_ai_move_with_animation(int x, int y); -// 显示AI思考过程 -void show_ai_thinking_process(SDL_Renderer* renderer); -// AI决策结果的图形化展示 -void render_ai_decision_info(SDL_Renderer* renderer, int score, int depth); -``` - -## ⚙️ 核心函数 - -### 1. ai_move(int depth) -```c -void ai_move(int depth); -``` -**执行流程**: -1. 🔍 扫描棋盘检测威胁 -2. 🛡️ 优先防御关键威胁 -3. 🔎 使用α-β剪枝搜索最佳位置 -4. ✅ 执行最优落子 - -### 2. dfs() - α-β剪枝核心 -```c -int dfs(int x, int y, int player, int depth, int alpha, int beta, bool is_maximizing); -``` -**剪枝条件**: -- 极大节点: α ≥ β -- 极小节点: β ≤ α - -### 3. evaluate_pos() - 位置评估 -**评分标准**: -| 棋型 | 图示 | 分数 | -|------|------|------| -| 活四 | ○○○○● | 100000 | -| 冲四 | ○○○○■ | 10000 | -| 活三 | ○○○●● | 5000 | - -## 🏆 评估系统 - -### 棋型评分表 -| 棋型 | 分数 | 示例 | -|------|------|------| -| 活四 | 100000 | `-----○-----` | -| 冲四 | 10000 | `----○■----` | -| 活三 | 5000 | `---○●●---` | - -### 位置权重计算 -```python -权重 = 50 * (BOARD_SIZE - |x-center| - |y-center|) -``` - -## ⚡ 性能优化 - -1. **评估缓存**: - - 哈希表存储重复位置评估 - - 命中率: ~85% - -2. **搜索优化**: - - 局部搜索范围: 2格 - - 平均剪枝率: 65% - -3. **典型搜索深度**: - - 基础难度: 3层 - - 最高难度: 5层 - -4. **网络优化**: - - 异步AI计算,避免网络延迟 - - 决策结果实时同步 - - 支持断线重连后状态恢复 - -## 🎯 典型场景 - -### 必胜局面处理 -``` -局面: ○○○○_ -决策: 立即落子形成五连 -``` - -### 双活三防御 -``` -威胁: 玩家有两个活三 -应对: 必须阻挡关键交叉点 -``` - -## 📊 性能基准 - -| 指标 | 15x15棋盘 | 19x19棋盘 | -|------|-----------|-----------| -| 平均决策时间 | 120ms | 350ms | -| 最大搜索节点 | 8,200 | 24,500 | -| 平均剪枝率 | 68% | 62% | - -## 🛠️ 开发建议 - -1. **调试技巧**: - - 启用`DEBUG_MODE`查看搜索过程 - - 使用`print_board()`可视化评估 - - 网络模式下使用`network_debug()`监控通信 - -2. **扩展方向**: - - 添加开局库 - - 实现并行搜索 - - 优化评估函数 - - 增强网络对战AI适应性 - - 支持AI难度动态调整 -``` diff --git a/MD/Architecture_Refactoring_Guide.md b/MD/Architecture_Refactoring_Guide.md deleted file mode 100644 index 47725e8..0000000 --- a/MD/Architecture_Refactoring_Guide.md +++ /dev/null @@ -1,270 +0,0 @@ -# 五子棋项目代码架构重构指南 - -## 📋 概述 - -本文档详细记录了五子棋项目在v7.0-v8.0版本中进行的重大代码架构重构,包括重构的目标、实施过程、技术细节和带来的改进。v8.0版本新增了SDL3图形化界面模块,实现了双版本架构设计。 - -## 🎯 重构目标 - -### 主要目标 -1. **代码模块化** - 实现清晰的模块分离和职责划分 -2. **配置统一管理** - 集中管理所有配置参数和宏定义 -3. **全局变量规范化** - 统一管理全局变量,避免散乱分布 -4. **类型定义标准化** - 集中定义所有数据结构和类型 -5. **提升可维护性** - 降低代码耦合度,提高可读性和可维护性 -6. **双版本架构** - (v8.0新增) 实现控制台版本和GUI版本的并行支持 -7. **图形化界面集成** - (v8.0新增) 无缝集成SDL3图形库,提供现代化用户界面 - -### 预期收益 -- 减少代码重复和冗余 -- 提高开发效率和调试便利性 -- 增强代码的可扩展性和可移植性 -- 为后续功能开发奠定坚实基础 - -## 🏗️ 重构实施 - -### 1. 配置参数统一管理 - -#### 重构前状态 -- 配置参数散落在多个头文件中 -- 存在重复定义和不一致的问题 -- 网络相关配置分散在`network.h`中 -- 缺乏统一的配置管理机制 - -#### 重构措施 -- **集中到config.h**:将所有配置宏定义迁移到`config.h`文件 -- **分类管理**:按功能模块对配置参数进行分组 -- **消除重复**:移除重复的宏定义,确保唯一性 -- **标准化命名**:统一配置参数的命名规范 - -#### 配置分类结构 -```c -// 棋盘配置 -#define BOARD_SIZE 15 -#define MIN_BOARD_SIZE 5 -#define MAX_BOARD_SIZE 25 - -// 游戏模式配置 -#define MODE_HUMAN_VS_AI 1 -#define MODE_HUMAN_VS_HUMAN 2 -#define MODE_NETWORK_BATTLE 3 - -// AI参数配置 -#define DEFAULT_AI_DEPTH 3 -#define MAX_AI_DEPTH 6 -#define AI_TIMEOUT_MS 5000 - -// 网络配置 -#define DEFAULT_PORT 8888 -#define BUFFER_SIZE 1024 -#define MAX_IP_LENGTH 16 - -// 评分参数 -#define SCORE_FIVE 100000 -#define SCORE_LIVE_FOUR 10000 -#define SCORE_RUSH_FOUR 1000 -``` - -### 2. 全局变量统一管理 - -#### 重构前状态 -- 全局变量分散在各个源文件中 -- 缺乏统一的声明和定义管理 -- 变量作用域不清晰 -- 初始化逻辑分散 - -#### 重构措施 -- **创建globals模块**:新建`globals.h`和`globals.c`文件 -- **集中声明**:在`globals.h`中统一声明所有全局变量 -- **集中定义**:在`globals.c`中统一定义和初始化 -- **访问规范化**:通过包含`globals.h`访问全局变量 - -#### 全局变量分类 -```c -// 游戏状态变量 -extern int current_board[MAX_BOARD_SIZE][MAX_BOARD_SIZE]; -extern int current_player; -extern int game_over; - -// 配置变量 -extern GameConfig game_config; -extern AIConfig ai_config; -extern NetworkConfig network_config; - -// 统计变量 -extern GameStats game_stats; -extern int total_games_played; -``` - -### 3. 类型定义标准化 - -#### 重构前状态 -- 结构体定义分散在各个头文件中 -- 类型定义不统一 -- 缺乏标准的数据结构规范 - -#### 重构措施 -- **创建type.h**:集中定义所有数据结构和类型 -- **标准化命名**:采用统一的命名规范 -- **逻辑分组**:按功能对类型进行分组 -- **文档化**:为每个类型添加详细注释 - -#### 类型定义结构 -```c -// 基础类型定义 -typedef enum { - PLAYER_NONE = 0, - PLAYER_BLACK = 1, - PLAYER_WHITE = 2 -} PlayerType; - -// 游戏配置结构 -typedef struct { - int board_size; - int ai_level; - int enable_forbidden; - int time_limit; -} GameConfig; - -// 网络消息结构 -typedef struct { - int type; - int x, y; - int player; - char data[256]; -} NetworkMessage; -``` - -### 4. 网络配置重构 - -#### 具体实施 -1. **迁移宏定义**:将`network.h`中的配置宏移动到`config.h` -2. **统一命名**:规范网络相关宏的命名 -3. **添加引用**:在`network.h`中添加`#include "config.h"` -4. **消息类型统一**:将消息类型定义集中管理 - -#### 迁移的配置项 -```c -// 从network.h迁移到config.h -#define DEFAULT_PORT 8888 -#define BUFFER_SIZE 1024 -#define MAX_IP_LENGTH 16 -#define MSG_MOVE 1 -#define MSG_CHAT 2 -#define MSG_SURRENDER 3 -#define MSG_DISCONNECT 4 -``` - -## 📊 重构效果评估 - -### 代码质量提升 -- **模块耦合度降低**:各模块职责更加清晰 -- **代码重复减少**:消除了重复的宏定义和类型定义 -- **可读性增强**:统一的命名规范和代码结构 -- **维护性提高**:集中管理使得修改更加便捷 - -### 开发效率提升 -- **配置修改便捷**:只需在一个地方修改配置参数 -- **调试更容易**:全局变量集中管理,状态更清晰 -- **扩展更简单**:标准化的接口和数据结构 -- **错误减少**:统一管理避免了不一致性错误 - -### 性能影响 -- **编译时间**:略有增加(由于更多的头文件包含) -- **运行时性能**:无显著影响 -- **内存使用**:无显著变化 -- **整体评估**:性能影响微乎其微,收益远大于成本 - -## 🔧 技术细节 - -### 文件结构变化 - -#### 新增文件 -- `type.h` - 类型定义集中文件 -- `globals.h` - 全局变量声明文件 -- `globals.c` - 全局变量定义文件 - -#### 修改文件 -- `config.h` - 扩展为完整的配置管理文件 -- `network.h` - 移除配置定义,添加config.h引用 -- 所有源文件 - 更新头文件包含关系 - -### 编译依赖关系 - -``` -type.h (基础类型) - ↓ -config.h (配置参数) - ↓ -globals.h (全局变量声明) - ↓ -各功能模块头文件 - ↓ -源文件实现 -``` - -### 包含关系规范 - -1. **type.h**:被所有需要类型定义的文件包含 -2. **config.h**:被所有需要配置参数的文件包含 -3. **globals.h**:被所有需要访问全局变量的文件包含 -4. **功能模块头文件**:按需包含上述基础头文件 - -## 📝 最佳实践 - -### 配置管理 -1. **新增配置参数**:统一添加到`config.h`的相应分组中 -2. **命名规范**:使用描述性的宏名称,避免缩写 -3. **分组管理**:按功能模块对配置进行逻辑分组 -4. **文档注释**:为每个配置参数添加清晰的注释 - -### 全局变量管理 -1. **声明规范**:在`globals.h`中使用extern声明 -2. **定义规范**:在`globals.c`中进行实际定义和初始化 -3. **访问规范**:通过包含`globals.h`访问,避免重复声明 -4. **初始化管理**:在`globals.c`中集中进行初始化 - -### 类型定义管理 -1. **命名规范**:使用PascalCase命名结构体和枚举 -2. **分组管理**:按功能对类型进行逻辑分组 -3. **文档化**:为每个类型和字段添加详细注释 -4. **版本兼容**:考虑结构体的向后兼容性 - -## 🚀 未来扩展 - -### 短期计划 -1. **配置文件增强**:支持更多配置项的动态加载 -2. **类型安全增强**:添加更多的类型检查和验证 -3. **模块接口标准化**:定义标准的模块接口规范 - -### 长期规划 -1. **插件架构**:基于当前架构实现插件系统 -2. **配置热重载**:支持运行时配置的动态更新 -3. **跨平台适配**:利用统一架构实现跨平台支持 - -## 📚 参考资料 - -### 相关文档 -- [C语言编程规范](https://www.kernel.org/doc/html/latest/process/coding-style.html) -- [软件架构设计原则](https://en.wikipedia.org/wiki/Software_architecture) -- [模块化编程最佳实践](https://en.wikipedia.org/wiki/Modular_programming) - -### 工具推荐 -- **静态分析**:使用cppcheck进行代码质量检查 -- **格式化**:使用clang-format统一代码格式 -- **文档生成**:使用Doxygen生成API文档 - -## 📈 总结 - -v7.0版本的代码架构重构是一次重要的技术升级,通过系统性的重构实现了: - -✅ **配置参数的统一管理** - 提高了配置的一致性和可维护性 -✅ **全局变量的规范化** - 降低了代码的复杂度和耦合度 -✅ **类型定义的标准化** - 增强了代码的可读性和类型安全 -✅ **模块结构的优化** - 为后续功能扩展奠定了坚实基础 - -这次重构不仅解决了当前的技术债务,更为项目的长期发展提供了良好的架构基础。后续的功能开发将能够更加高效和稳定地进行。 - ---- - -*本文档将随着项目的发展持续更新,记录架构演进的每一个重要节点。* \ No newline at end of file diff --git a/MD/BUILD.md b/MD/BUILD.md deleted file mode 100644 index eb9b168..0000000 --- a/MD/BUILD.md +++ /dev/null @@ -1,83 +0,0 @@ -# 五子棋游戏编译指南 - -本项目现在支持使用 `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/MD/ICON_GUIDE.md b/MD/ICON_GUIDE.md deleted file mode 100644 index e9dbf5c..0000000 --- a/MD/ICON_GUIDE.md +++ /dev/null @@ -1,78 +0,0 @@ -# 为五子棋游戏添加图标指南 - -## 问题说明 - -在尝试为可执行文件添加图标时,发现icon文件夹中的图标文件格式不正确: -- `gobang_icon1.ico` 和 `gobang_icon2.ico` 实际上是HTML文件和PNG文件,而不是真正的ICO格式文件 - -## 解决方案 - -### 方法一:获取正确的ICO文件 - -1. **下载或创建真正的ICO文件** - - 使用在线ICO转换工具将PNG/JPG转换为ICO格式 - - 推荐网站:https://www.icoconverter.com/ - - 或使用GIMP、Photoshop等图像编辑软件导出ICO格式 - -2. **替换现有文件** - - 将正确的ICO文件保存为 `icon/gobang_icon.ico` - - 确保文件是真正的ICO格式(文件头应为 00 00 01 00) - -3. **修改资源文件** - - 编辑 `gobang.rc` 文件 - - 取消注释图标行:`IDI_APPLICATION ICON "icon\\gobang_icon.ico"` - -4. **重新编译** - ```bash - windres gobang.rc -o gobang.res - gcc -std=c17 -o gobang.exe *.c gobang.res -lws2_32 - ``` - -### 方法二:使用现有PNG文件(需要转换) - -如果你有PNG格式的图标文件,可以: - -1. **在线转换** - - 访问 https://convertio.co/png-ico/ - - 上传PNG文件并转换为ICO格式 - - 下载转换后的ICO文件 - -2. **使用ImageMagick(如果已安装)** - ```bash - magick convert icon/your_image.png icon/gobang_icon.ico - ``` - -### 方法三:使用Windows资源编辑器 - -1. 编译不带图标的exe文件(当前状态) -2. 使用Resource Hacker等工具后期添加图标 -3. 下载Resource Hacker:http://www.angusj.com/resourcehacker/ - -## 当前状态 - -- ✅ 程序可以正常编译和运行 -- ✅ 包含版本信息资源 -- ❌ 暂时没有应用程序图标 -- ✅ 提供了完整的构建脚本 - -## 编译指令 - -### 不带图标版本(当前可用) -```bash -gcc -std=c17 -o gobang.exe *.c -lws2_32 -``` - -### 带图标版本(需要正确的ICO文件) -```bash -windres gobang.rc -o gobang.res -gcc -std=c17 -o gobang.exe *.c gobang.res -lws2_32 -``` - -## 验证ICO文件格式 - -可以使用以下PowerShell命令检查文件是否为真正的ICO格式: -```powershell -Get-Content icon/gobang_icon.ico -AsByteStream -TotalCount 4 | ForEach-Object { '{0:X2}' -f $_ } -``` - -正确的ICO文件应该显示:`00 00 01 00` \ No newline at end of file diff --git a/MD/NETWORK_README.md b/MD/NETWORK_README.md deleted file mode 100644 index 56ed175..0000000 --- a/MD/NETWORK_README.md +++ /dev/null @@ -1,150 +0,0 @@ -# 五子棋网络对战使用说明 - -## 功能概述 - -本项目支持网络对战功能,允许两台设备通过网络进行实时五子棋对战,支持服务器/客户端连接。v8.0版本新增了GUI界面的网络对战支持,提供更直观的可视化网络游戏体验。 - -### v8.2 (2025-10-08) -- 专业安装包制作 - 支持Inno Setup和NSIS双重安装方案 -- 安装程序优化 - 完整的文件打包和快捷方式创建 -- 分发体系完善 - 提供标准化的软件分发解决方案 -- 用户体验提升 - 一键安装部署,支持完整卸载功能 - -## 编译方法 - -### 控制台版本 -```bash -gcc -std=c17 -o gobang.exe *.c -lws2_32 -``` - -### GUI版本 -```bash -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 -copy "D:\settings\SDL\SDL3-3.2.22\x86_64-w64-mingw32\bin\SDL3.dll" . -``` - -**注意:** -- Windows系统需要添加 `-lws2_32` 链接库 -- GUI版本需要SDL3库支持 -- Linux系统不需要ws2_32链接库参数 - -## 使用方法 - -### 1. 启动游戏 -运行编译后的程序 -```bash -.\gobang.exe -``` - -### 2. 选择网络对战模式 -在主菜单中选择 `3. 网络对战` - -### 3. 选择连接模式 - -#### 模式1:创建房间(作为服务器) -- 选择 `1. 创建房间(作为服务器)` -- 输入监听端口(默认8888,建议使用1024-65535范围内的端口) -- 程序会显示本机IP地址,将此IP告知对方 -- 等待对方连接 - -#### 模式2:加入房间(连接到服务器) -- 选择 `2. 加入房间(连接到服务器)` -- 输入服务器IP地址 -- 输入服务器的端口号(与服务器设置的端口一致) -- 连接到服务器 - -### 4. 开始游戏 -- 连接成功后游戏自动开始 -- 服务器为玩家1(黑棋),客户端为玩家2(白棋) -- 玩家1先手 - -## 游戏操作 - -### 基本操作 -- **落子**:输入坐标 `行号 列号`,例如:`7 7` -- **认输**:输入 `S` 或 `s` -- **悔棋**:输入 `R` 或 `r`(需要对方同意) - -### 网络功能 -- **自动同步**:落子操作会自动同步给对方 -- **连接检测**:自动检测网络连接状态 -- **延时显示**:支持回合延时显示,避免过快操作 -- **悔棋协商**:悔棋需要对方同意才能生效 - -## 网络配置 - -### 端口设置 -- 默认端口:8888 -- 可设端口范围:1024-65535 -- 确保防火墙允许选定端口的通信 - -### IP地址 -- **局域网**:使用内网IP地址,例如:192.168.1.100 -- **广域网**:使用公网IP地址,可能需要路由器端口转发 - -### 防火墙设置 -如果连接失败,请检查防火墙设置: - -#### Windows防火墙 -1. 打开Windows安全中心 -2. 选择"防火墙和网络保护" -3. 选择"允许应用通过防火墙" -4. 添加gobang.exe到允许列表 - -#### 路由器设置(用于广域网对战) -如果通过互联网对战,可能需要: -1. 在路由器中设置端口转发 -2. 将选定端口转发到服务器内网IP -3. 将路由器的公网IP告知对方 - -## 故障排除 - -### 常见问题 - -1. **连接失败** - - 检查IP地址和端口是否正确 - - 确认防火墙设置 - - 确保两台设备网络连通 - -2. **游戏中断** - - 检查网络连接稳定性 - - 重新启动游戏重新连接 - -3. **端口被占用** - - 更换其他端口号 - - 关闭占用端口的其他程序 - -### 网络测试 -可以使用以下命令测试网络连通性: -```bash -# 测试网络连通 -ping <对方IP地址> - -# 测试端口(需要telnet客户端) -telnet <对方IP地址> <端口号> -``` - -## 技术细节 - -- **协议**:TCP/IP -- **消息格式**:自定义二进制协议 -- **支持功能**: - - 棋盘同步 - - 悔棋处理 - - 认输协商 - - 连接检测 - - 延时控制 - -## 安全注意事项 - -1. **局域网使用**:建议安全的家庭或办公环境 -2. **广域网使用**: - - 不要使用默认端口8888 - - 游戏结束后及时关闭程序 - - 注意保护个人网络信息 - - - -**开发者:** 刘航宇 -**联系邮箱:** 3364451258@qq.com -**项目主页:** https://github.com/LHY0125/Gobang-Game \ No newline at end of file diff --git a/MD/README_GUI.md b/MD/README_GUI.md deleted file mode 100644 index 430ebe6..0000000 --- a/MD/README_GUI.md +++ /dev/null @@ -1,137 +0,0 @@ -# 五子棋游戏 - 图形化界面说明 (v8.3) - -## 概述 - -v8.3版本引入了基于IUP的现代化图形界面,实现了完整的双版本架构: - -- **控制台界面**:传统的文本界面,保持原有功能完整性 -- **图形化界面**:基于IUP的现代图形界面,提供可视化操作体验 - -## v8.3 新增功能 - -- ✅ **IUP图形化界面**:原生控件风格,轻量高效 -- ✅ **鼠标交互支持**:点击落子,直观操作 -- ✅ **窗口管理优化**:自动居中,响应式设计 -- ✅ **事件驱动架构**:流畅的用户交互体验 -- ✅ **安装包支持**:提供专业的安装程序 -- ✅ **双版本并行**:控制台和GUI版本独立运行 - -## 环境要求 - -### IUP库配置 - -项目已内置IUP库(位于 `libs/iup-3.31_Win64_dllw6_lib`),无需额外安装。 - -### 编译环境 - -- GCC编译器(MinGW-w64) -- Make工具(mingw32-make) -- Windows 10/11操作系统 - -## 编译方法 - -### 方法一:使用Makefile(推荐) - -```bash -# 编译图形化版本 -mingw32-make gui -``` - -### 方法二:手动编译 - -```bash -# GUI版本 -gcc -std=c17 -o bin/gobang_gui.exe src/*.c -Iinclude -Ilibs/iup-3.31_Win64_dllw6_lib/include -Llibs/iup-3.31_Win64_dllw6_lib -liup -lgdi32 -lcomdlg32 -lcomctl32 -luuid -lole32 -lws2_32 - -# 复制IUP动态库到bin目录 -copy libs\iup-3.31_Win64_dllw6_lib\iup.dll bin\ -``` - -## 运行方法 - -### 图形化版本 - -```bash -.\bin\gobang_gui.exe -``` - -或者在主菜单选择模式8启动图形化界面。 - -## 图形化界面功能 - -- **窗口大小**:800x600像素 -- **棋盘显示**:15x15标准五子棋棋盘 -- **鼠标操作**:点击棋盘交叉点进行落子 -- **键盘操作**: - - `ESC`:退出图形化界面返回主菜单 -- **游戏状态**: - - 实时显示当前玩家(黑子/白子) - - 显示游戏进度和状态 - - 胜负结果提示 -- **视觉效果**: - - 清晰的黑白棋子 - - 当前玩家指示器 - - 平滑的图形渲染 -- **胜负判定**:自动检测五子连珠并显示获胜者 - -## 故障排除 - -### 编译错误 - -1. **找不到IUP头文件** - - 检查Makefile中的`IUP_PATH`配置是否正确指向`libs`目录 - -2. **链接错误** - - 确保链接了所有必要的Windows系统库(`-lgdi32 -lcomdlg32 -lcomctl32 -luuid -lole32`) - -3. **运行时错误** - - 确保`iup.dll`位于可执行文件同级目录或系统PATH中 - -### 图形化界面启动失败 - -- 确保`iup.dll`文件在exe同目录下 -- 尝试以管理员权限运行 -- 确认Windows版本兼容性 - -### 运行时问题 - -- **中文乱码**:确保代码中已启用UTF-8模式 `IupSetGlobal("UTF8MODE", "YES");` -- **鼠标点击无响应**:确认点击在棋盘交叉点附近 - -## 使用说明 - -### 快速开始 - -1. 运行 `mingw32-make gui` 编译图形化版本 -2. 运行 `bin\gobang_gui.exe` 启动程序 -3. 在主菜单选择 "8. 图形化界面" -4. 使用鼠标点击棋盘进行游戏 -5. 按ESC键退出图形化界面 - -### 游戏规则 - -- 黑子先行,轮流落子 -- 率先形成五子连珠者获胜 -- 支持横、竖、斜四个方向的连珠判定 - -## 开发说明 - -### 文件结构 - -- `include/gui.h` - 图形化界面头文件 -- `src/gui.c` - 图形化界面实现(基于IUP) -- `src/main.c` - 主程序(已添加图形化模式) -- `Makefile` - 构建脚本 - -### 扩展功能 - -图形化界面支持进一步扩展: - -- 更多IUP控件集成 -- 主题切换 -- 网络对战界面优化 -- AI难度可视化调节 - ---- - -**注意**:首次使用图形化界面前,请确保IUP动态库已正确复制。 diff --git a/Makefile b/Makefile index bf1122c..095ac45 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # 五子棋游戏 Makefile -# 支持编译控制台版本和GUI版本 (IUP) +# 支持编译GUI版本 (IUP) # 编译器设置 CC = gcc @@ -22,35 +22,27 @@ OBJ_DIR = obj BIN_DIR = bin # 源文件 -COMMON_SOURCES = $(SRC_DIR)/main.c $(SRC_DIR)/gobang.c $(SRC_DIR)/ai.c $(SRC_DIR)/config.c \ - $(SRC_DIR)/game_mode.c $(SRC_DIR)/globals.c $(SRC_DIR)/init_board.c \ - $(SRC_DIR)/network.c $(SRC_DIR)/record.c $(SRC_DIR)/ui.c $(SRC_DIR)/gui.c \ +COMMON_SOURCES = $(SRC_DIR)/gobang.c $(SRC_DIR)/ai.c $(SRC_DIR)/config.c \ + $(SRC_DIR)/globals.c \ + $(SRC_DIR)/network.c $(SRC_DIR)/record.c $(SRC_DIR)/gui.c \ $(SRC_DIR)/gui_menu.c -GUI_SOURCES = $(COMMON_SOURCES) -CONSOLE_SOURCES = $(COMMON_SOURCES) - # 目标文件 (src/xxx.c -> obj/xxx.o) COMMON_OBJECTS = $(patsubst $(SRC_DIR)/%.c,$(OBJ_DIR)/%.o,$(COMMON_SOURCES)) # 可执行文件 -CONSOLE_TARGET = $(BIN_DIR)/gobang_console.exe GUI_TARGET = $(BIN_DIR)/gobang_gui.exe # 默认目标 -all: directories $(CONSOLE_TARGET) $(GUI_TARGET) +all: directories $(GUI_TARGET) # 创建目录 (PowerShell 语法) directories: if (!(Test-Path "$(OBJ_DIR)")) { New-Item -ItemType Directory -Path "$(OBJ_DIR)" | Out-Null } if (!(Test-Path "$(BIN_DIR)")) { New-Item -ItemType Directory -Path "$(BIN_DIR)" | Out-Null } -# 控制台版本 -$(CONSOLE_TARGET): $(COMMON_OBJECTS) - $(CC) $(CFLAGS) $(IUP_INCLUDE) -o $@ $^ $(IUP_LIBS) $(LDFLAGS) - # GUI版本 -$(GUI_TARGET): $(COMMON_OBJECTS) +$(GUI_TARGET): $(COMMON_OBJECTS) $(OBJ_DIR)/main.o $(CC) $(CFLAGS) $(IUP_INCLUDE) -o $@ $^ $(IUP_LIBS) $(LDFLAGS) Copy-Item -Path "$(subst /,\,$(IUP_PATH))\iup.dll" -Destination "$(BIN_DIR)" -Force @@ -58,27 +50,23 @@ $(GUI_TARGET): $(COMMON_OBJECTS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(CC) $(CFLAGS) $(IUP_INCLUDE) -c -o $@ $< +# 编译 main.c +$(OBJ_DIR)/main.o: $(SRC_DIR)/main.c + $(CC) $(CFLAGS) $(IUP_INCLUDE) -c -o $@ $< + # 清理规则 (PowerShell 语法) clean: if (Test-Path "$(OBJ_DIR)") { Remove-Item -Path "$(OBJ_DIR)" -Recurse -Force } if (Test-Path "$(BIN_DIR)") { Remove-Item -Path "$(BIN_DIR)" -Recurse -Force } -# 只编译控制台版本 -console: directories $(CONSOLE_TARGET) - -# 只编译GUI版本 +# 编译GUI版本 gui: directories $(GUI_TARGET) # 安装规则(可选) install: all Write-Host "Installing executables..." - Copy-Item -Path "$(CONSOLE_TARGET)" -Destination "C:\Program Files\Gobang\" -Force Copy-Item -Path "$(GUI_TARGET)" -Destination "C:\Program Files\Gobang\" -Force -# 运行控制台版本 -run-console: $(CONSOLE_TARGET) - & ".\$(CONSOLE_TARGET)" - # 运行GUI版本 run-gui: $(GUI_TARGET) & ".\$(GUI_TARGET)" @@ -86,14 +74,12 @@ run-gui: $(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 all - Build GUI version + @echo gui - Build GUI version @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 directories +.PHONY: all clean gui install run-gui help directories diff --git a/TXT/代码统计报告.txt b/TXT/代码统计报告.txt deleted file mode 100644 index 458aef4..0000000 --- a/TXT/代码统计报告.txt +++ /dev/null @@ -1,193 +0,0 @@ -五子棋对战系统 - 代码统计报告 -======================================== - -项目名称:五子棋多模式对战系统 -统计时间:2025年10月8日 -项目版本:v8.2 -开发语言:C语言 + SDL3图形库 -GitHub仓库:https://github.com/LHY0125/Gobang-Game.git - -======================================== -📊 代码行数统计 -======================================== - -【C源文件 (.c)】 -├── main.c :85行 -├── gobang.c :269行 -├── game_mode.c :917行 -├── ai.c :589行 -├── record.c :531行 -├── init_board.c :118行 -├── ui.c :204行 -├── config.c :331行 -├── network.c :426行 -├── globals.c :37行 -└── gui.c :450行 (v8.0新增) - -【头文件 (.h)】 -├── gobang.h :101行 -├── game_mode.h :99行 -├── ai.h :39行 -├── record.h :45行 -├── init_board.h :35行 -├── ui.h :62行 -├── config.h :170行 -├── network.h :186行 -├── globals.h :41行 -├── type.h :93行 -└── gui.h :85行 (v8.0新增) - -======================================== -📈 总计统计 -======================================== - -总代码行数:4,933行 (v8.0新增535行) - -文件类型分布: -• C源文件:3,977行 (80.6%) -• 头文件:956行 (19.4%) - -v8.0版本新增: -• GUI图形界面模块:535行 (10.8%) -• 安装包配置文件:2个 -• 编译脚本文件:1个 - -模块代码分布: -• 游戏模式模块:917行 (18.6%) -• AI智能模块:589行 (11.9%) -• GUI图形界面模块:535行 (10.8%) (v8.0新增) -• 记录系统模块:531行 (12.1%) -• 网络对战模块:426行 (9.7%) -• 配置管理模块:331行 (7.5%) -• 核心游戏模块:269行 (6.1%) -• 用户界面模块:204行 (4.6%) -• 配置参数模块:170行 (3.9%) -• 棋盘初始化模块:118行 (2.7%) -• 类型定义模块:93行 (2.1%) -• 主程序模块:84行 (1.9%) -• 全局变量模块:41行 (0.9%) - -======================================== -💬 注释统计 -======================================== - -【注释统计】 -总注释行数:1,248行 -注释覆盖率:30.1% - -注释类型分布: -• 函数说明注释:498行 (39.9%) -• 代码逻辑注释:425行 (34.1%) -• 文件头注释:325行 (26.0%) - -注释质量分析: -• 文件头注释:每个文件都有详细的文档头 -• 函数注释:使用Doxygen格式的完整函数文档 -• 行内注释:关键逻辑的解释说明 -• 分块注释:代码段落的功能说明 - -估算注释字数:约8,500-10,000字 - -注释内容包括: -• 详细的函数参数和返回值说明 -• 算法逻辑的中文解释 -• 代码块的功能描述 -• 重要变量和常量的用途说明 -• 网络协议和数据结构的详细文档 - -======================================== -🏆 代码质量评价 -======================================== - -【优秀特点】 -✓ 注释覆盖率高:几乎每个函数都有详细文档 -✓ 代码结构清晰:模块化设计,职责分离明确 -✓ 命名规范:变量和函数名具有良好的可读性 -✓ 文档完整:包含完整的API文档和使用说明 -✓ 架构合理:网络模块、AI模块、UI模块分离 -✓ 跨平台支持:Windows和Linux双平台兼容 - -【技术亮点】 -• SDL3图形化界面实现(v8.0新增) -• 双版本架构设计(控制台+GUI)(v8.0新增) -• 鼠标交互和事件驱动架构(v8.0新增) -• 专业安装包制作支持(v8.2新增) -• Inno Setup和NSIS双重打包方案(v8.2新增) -• 完整的软件分发体系(v8.2新增) -• 完整的网络对战功能实现 -• 智能AI算法与评估系统 -• 灵活的配置管理系统 -• 详细的游戏记录与复盘功能 -• 规范的禁手规则实现 -• 实时计时器系统 -• 全局变量统一管理 -• 跨平台网络通信支持 -• 代码架构模块化重构 -• 配置参数集中化管理 -• 类型定义标准化 - -【总体评价】 -这是一个非常优秀的C语言项目,代码量适中但功能完整, -注释详尽,体现了良好的编程习惯和专业素养! - -项目从单一的五子棋游戏发展为支持多种对战模式的完整系统, -包括人机对战、双人对战和网络对战,功能丰富,架构清晰, -是C语言项目开发的优秀范例。 - -v8.2版本进一步完善了软件分发体系, -通过Inno Setup和NSIS双重安装包方案, -实现了专业级的软件打包和部署功能, -为用户提供了便捷的一键安装体验, -标志着项目从开发阶段向产品化阶段的重要转变。 - -v8.0版本的图形化界面是项目发展的重大突破, -通过SDL3图形库实现了现代化的可视化界面, -支持鼠标交互操作,大幅提升了用户体验。 -双版本架构设计既保持了控制台版本的轻量特性, -又提供了GUI版本的现代化体验,满足不同用户需求。 - -网络对战功能的加入使得项目具备了现代化游戏的特征, -支持实时在线对战,为用户提供了更丰富的游戏体验。 - -v7.0版本的代码架构重构是项目发展的重要里程碑, -通过配置统一管理、全局变量规范化、类型定义标准化等措施, -大幅提升了代码的可维护性和扩展性,为v8.0的GUI功能 -奠定了坚实的架构基础。 - -======================================== -📋 项目文件结构 -======================================== - -核心模块: -• main.c/gobang.c - 主程序和核心游戏逻辑 -• game_mode.c/h - 游戏模式管理(人机/双人/网络) -• ai.c/h - AI智能算法实现 -• gui.c/h - SDL3图形化界面模块(v8.0新增) -• network.c/h - 网络对战功能 -• record.c/h - 游戏记录与复盘 -• ui.c/h - 用户界面管理 -• config.c/h - 配置文件管理 -• init_board.c/h - 棋盘初始化 -• globals.c/h - 全局变量统一管理 -• type.h - 数据结构和类型定义集中文件(v7.0新增) - -配置文件: -• gobang_config.ini - 游戏配置文件 -• compile_gui.bat - GUI版本编译脚本(v8.0新增) - -安装包目录: -• installer/ - 安装包制作目录(v8.0新增) - • setup.iss - Inno Setup安装脚本 - • installer.nsi - NSIS安装脚本 - -文档目录: -• MD/ - 项目文档目录 - • README_GUI.md - GUI版本使用指南(v8.0新增) -• TXT/ - 文本文档目录 -• records/ - 游戏记录存储目录 - -开发环境: -• .vscode/ - VS Code配置 -• .idea/ - IntelliJ IDEA配置 - -======================================== \ No newline at end of file diff --git a/TXT/简介.txt b/TXT/简介.txt deleted file mode 100644 index 7916380..0000000 --- a/TXT/简介.txt +++ /dev/null @@ -1,108 +0,0 @@ -/** - * @file 五子棋对战系统 - * @brief C语言五子棋多模式对战系统 - * @details 支持人机对战、双人对战、网络对战的完整五子棋游戏系统,v8.3新增IUP图形化界面 - * @author 刘航宇(3364451258@qq.com、15236416560@163.com、lhy3364451258@outlook.com) - * @date 2026-03-16 - * @version 8.3 - * @note - * 1. v8.3 图形界面重构: - * - 🎨 IUP图形化界面:迁移至轻量级IUP库,无需复杂配置即可运行 - * - 🏗️ 构建系统优化:引入Makefile,实现标准化编译流程 - * - 📂 目录结构重构:分离src、obj、bin目录,项目结构更清晰 - * - 🌐 本地化资源:集成第三方库到libs目录,实现开箱即用 - * - * 2. v8.2专业安装包: - * - 📦 双重打包方案:支持Inno Setup和NSIS两种安装包制作 - * - 🚀 一键安装部署:完整的软件分发解决方案 - * - 🔧 安装程序优化:自动创建快捷方式和注册表项 - * - 🗂️ 完整文件打包:包含所有源码、文档和依赖文件 - * - 🔄 完整卸载功能:支持干净的软件卸载和清理 - * - 💼 产品化部署:从开发工具向商业软件的转变 - * - * 3. v8.0图形化界面: - * - 🎨 SDL3图形化界面:实现现代化可视化棋盘界面(已废弃,迁移至IUP) - * - 🖱️ 鼠标交互支持:直观的点击落子操作 - * - 🏗️ 双版本架构:控制台版本和GUI版本并行支持 - * - 🪟 窗口管理优化:自动居中、响应式设计 - * - ⚡ 事件驱动架构:流畅的用户交互体验 - * - 🌐 GUI网络支持:图形化界面支持网络对战 - * 4. v7.0架构重构: - * - 🏗️ 代码架构全面重构,实现模块化设计 - * - 📋 配置参数统一管理,所有配置集中到config.h - * - 🔧 全局变量规范化,统一在globals模块管理 - * - 📝 类型定义标准化,集中在type.h中定义 - * - 🌐 网络配置重构,从network.h迁移到config.h - * - 🔄 消除重复定义,提高代码一致性 - * - 📚 完善文档体系,新增架构重构指南 - * 5. v6.1完善功能: - * - 🌐 完善的网络对战模式,支持服务器/客户端架构 - * - 🔗 实时数据同步,支持落子、悔棋、认输等网络功能 - * - 🛡️ 网络安全验证和连接状态管理 - * - 📡 跨平台网络支持(Windows/Linux) - * - 🔧 全局变量统一管理,优化代码结构 - * - 📋 宏定义统一管理,消除重复定义 - * - 🔄 网络协议优化,改进通信稳定性 - * 6. 核心游戏功能: - * - 增加了对禁手规则的支持,防止玩家进行无意义的走法。 - * - 新增了游戏计时器功能,限制每回合的思考时间。 - * - 添加了复盘功能,支持保存和回顾对局记录。 - * - 实现了评分系统,可以对每一步棋进行评分和分析。 - * 7. 性能优化: - * - 🚀 优化了AI算法,使用Alpha-Beta剪枝提高搜索效率 - * - 🎨 改进了棋盘渲染算法,减少了不必要的重绘操作 - * - 💾 增加了内存管理优化,避免内存泄漏问题 - * - ⚡ 网络通信优化,支持异步消息处理 - * - 🔍 智能评分算法优化,提升AI决策质量 - * 8. 用户界面改进: - * - 🎮 美化了游戏界面,增加了更多的视觉效果 - * - ⌨️ 改进了用户交互体验,增加了快捷键支持 - * - 🔊 添加了音效和背景音乐,提升游戏沉浸感 - * - 💬 网络对战聊天界面,支持实时交流 - * - 📊 游戏状态显示优化,清晰展示连接状态 - * 9. 代码结构优化: - * - 🏗️ 重构了代码架构,提高了代码的可读性和可维护性 - * - 📝 增加了详细的注释和文档,便于理解和修改 - * - 🧩 采用了模块化设计,各功能模块相对独立 - * - 🌍 新增网络模块,完整的网络通信架构 - * - 🔧 全局状态统一管理,消除代码重复 - * - 📋 配置文件标准化,支持灵活配置 - * 10. 异常处理: - * - 🛡️ 增加了输入错误的异常处理机制,确保游戏的稳定性 - * - 💡 优化了错误提示信息,帮助用户快速定位问题 - * - 🔄 增加了程序崩溃恢复功能,提高游戏的可靠性 - * - 🌐 网络连接异常处理,自动重连和超时管理 - * - 📡 消息传输错误处理,确保数据完整性 - * 11. 文档更新: - * - 📚 更新了README文件,提供详细的安装和使用说明 - * - 💬 增加了代码注释,提高代码的可读性 - * - 👨‍💻 添加了开发者文档,便于后续的功能扩展 - * - 🌐 新增网络对战使用指南和配置说明 - * - 🔧 API文档完善,支持二次开发 - * 12. 版本控制: - * - 📦 使用Git进行版本控制,便于代码管理和协作开发 - * - 🚀 建立了清晰的版本发布流程,确保代码质量 - * - 🏷️ v7.0版本更新,代码架构全面重构 - * - 🏷️ v6.1版本更新,网络功能完善优化 - * - 📋 完整的变更日志,追踪功能演进 - * 13. 测试: - * - ✅ 进行了全面的功能测试,确保各项功能正常运行 - * - 🧪 增加了单元测试,提高代码的可靠性 - * - ⚡ 进行了性能测试,优化了程序的运行效率 - * - 🌐 网络功能压力测试,确保多人对战稳定性 - * - 🔒 安全性测试,验证网络通信安全 - * - 🔄 协议兼容性测试,确保通信协议稳定 - * 14. 开源协议: - * - 📄 选择了MIT开源协议,允许用户自由使用、修改和分发代码 - * - 🤝 欢迎社区贡献,共同完善项目 - * 15. 贡献者: - * - 👨‍💻 感谢所有为项目做出贡献的开发者和用户 - * - 🌟 特别感谢网络功能开发、测试和优化的贡献者 - * 16. 联系信息: - * - 📧 如有问题或建议,请联系开发者: - * - 3364451258@qq.com - * - 15236416560@163.com - * - lhy3364451258@outlook.com - * - 🐛 Bug报告和功能建议欢迎通过邮件反馈 - * - 💡 网络对战相关问题请详细描述网络环境和连接状态 - */ diff --git a/TXT/项目要求.txt b/TXT/项目要求.txt deleted file mode 100644 index 4a5adbc..0000000 --- a/TXT/项目要求.txt +++ /dev/null @@ -1,71 +0,0 @@ -项目要求文档 - 五子棋游戏 (v8.3) - -1. 项目概述 - - 开发一个基于C语言的五子棋游戏,支持本地多人、AI对战和网络对战模式。 - - v8.3版本(当前版本)引入了IUP图形库,实现了轻量级、跨平台的图形界面。 - - v8.2版本完善了专业安装包制作体系,提供企业级的软件分发解决方案。 - - v8.0版本实现双版本架构:支持命令行界面和GUI图形化界面。 - - 包括游戏配置、记录保存、复盘功能和专业安装包。 - - 提供现代化的可视化用户体验和传统控制台体验。 - -2. 功能需求 - - **游戏模式**: - - 单人模式:玩家 vs AI - - 双人模式:本地两人对战 - - 网络模式:通过TCP/IP进行远程对战 - - **棋盘和规则**: - - 默认15x15棋盘,支持自定义大小(5-25) - - 支持禁手规则选项 - - 先手黑子,五连珠获胜 - - **AI功能**: - - 实现AI算法,支持不同难度级别(1-5级) - - AI应能计算最佳落子位置 - - 支持Alpha-Beta剪枝算法和威胁检测 - - **配置管理**: - - 支持修改棋盘大小、禁手规则、计时器、网络端口等 - - 配置保存到INI文件 - - 默认配置和重置功能 - - 统一的输入验证机制 - - **游戏记录**: - - 自动保存对局记录到CSV文件 - - 支持复盘功能,查看历史对局 - - 记录包含时间戳、玩家信息、棋局步骤等 - - **用户界面**: - - **控制台界面**:传统命令行界面显示棋盘 - - **图形化界面**(v8.3新增IUP):基于IUP的轻量级GUI界面 - - **鼠标交互**:支持点击落子操作 - - **窗口管理**:自动居中、响应式设计 - - **事件驱动**:流畅的用户交互体验 - - 支持坐标输入落子(数字格式:行 列) - - 显示当前玩家、计时、游戏状态等信息 - - 菜单系统和配置界面 - - **网络功能**: - - 支持服务器/客户端模式 - - 实时传输棋子位置 - - 超时和断线处理 - - 支持端口配置 - -3. 技术要求 - - 使用C语言开发 - - Windows平台,包含Winsock网络库(-lws2_32链接) - - **IUP图形库**(v8.3新增):用于GUI界面开发,替代原SDL3方案 - - **双版本架构**:控制台版本和GUI版本并行支持 - - 模块化设计:分离游戏逻辑、AI、配置、网络、UI、GUI等模块 - - **安装包制作**:支持Inno Setup和NSIS专业安装程序 - - **构建系统**:使用Makefile管理编译流程 - - 错误处理和统一的输入验证 - - 支持跨平台编译(Windows/Linux) - -4. 非功能需求 - - 性能:响应时间<1秒(AI计算除外) - - 可维护性:代码模块化,注释清晰 - - 兼容性:Windows 11,支持GCC编译器 - - 可扩展性:易于添加新的AI算法和游戏模式 - - 部署便捷:依赖库本地化,开箱即用 - -5. 交付物 - - 源代码文件(.c/.h文件) - - 配置文件(gobang_config.ini) - - 记录文件夹(records/) - - 文档:README.md、AI增强指南、架构重构指南、网络功能说明、图标指南等 - - 代码统计报告和项目简介 diff --git a/bin/gobang_gui.exe b/bin/gobang_gui.exe deleted file mode 100644 index be63b0b..0000000 Binary files a/bin/gobang_gui.exe and /dev/null differ diff --git a/bin/iup.dll b/bin/iup.dll deleted file mode 100644 index aceb679..0000000 Binary files a/bin/iup.dll and /dev/null differ diff --git a/gobang_config.ini b/gobang_config.ini index 1c32df1..3b2123c 100644 --- a/gobang_config.ini +++ b/gobang_config.ini @@ -16,3 +16,6 @@ NETWORK_PORT=8888 # 网络超时时间 (毫秒) NETWORK_TIMEOUT=5000 + +# AI难度 (1-5) +AI_DIFFICULTY=3 diff --git a/include/config.h b/include/config.h index c3f52e9..ae34b0a 100644 --- a/include/config.h +++ b/include/config.h @@ -153,34 +153,4 @@ void save_game_config(); */ void reset_to_default_config(); -/** - * @brief 显示当前配置 - */ -void display_current_config(); - -/** - * @brief 配置棋盘大小 - */ -void config_board_size(); - -/** - * @brief 配置禁手规则 - */ -void config_forbidden_moves(); - -/** - * @brief 配置计时器 - */ -void config_timer(); - -/** - * @brief 配置网络参数 - */ -void config_network(); - -/** - * @brief 配置管理主菜单 - */ -void config_management_menu(); - #endif // CONFIG_H \ No newline at end of file diff --git a/include/game_mode.h b/include/game_mode.h deleted file mode 100644 index b8a8618..0000000 --- a/include/game_mode.h +++ /dev/null @@ -1,108 +0,0 @@ -/** - * @file game_mode.h - * @brief 五子棋游戏框架头文件 - * @note 本文件定义了五子棋游戏的四种主要模式: - * 1. AI对战模式 - * 2. 双人对战模式 - * 3. 网络对战模式 - * 4. 复盘模式 - */ - -#ifndef GAME_MODE_H -#define GAME_MODE_H - -#include "gobang.h" -#include "config.h" - -/** - * @brief 从用户获取整数输入 - * - * @param prompt 提示信息 - * @param min 最小值 - * @param max 最大值 - * @return int 输入的整数 - */ -int get_integer_input(const char *prompt, int min, int max); - -/** - * @brief 处理玩家回合 - * - * @param x 玩家输入的横坐标 - * @param y 玩家输入的纵坐标 - * @return true 输入有效 - * @return false 输入无效 - */ -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回合 - * - * @param current_player 当前玩家 - */ -bool handle_player_turn(int current_player); - -/** - * @brief AI对战模式 - * 实现玩家与AI的对战逻辑 - */ -void run_ai_game(); - -/** - * @brief 双人对战模式 - * 实现两个玩家之间的对战逻辑 - */ -void run_pvp_game(); - -/** - * @brief 复盘模式 - * 加载并重现历史对局 - */ -void run_review_mode(); - -/** - * @brief 网络对战模式 - * 实现两台设备之间的在线对战 - */ -void run_network_game(); - -/** - * @brief 处理网络玩家回合 - * @param current_player 当前玩家 - * @param is_local_turn 是否为本地玩家回合 - * @return true 回合处理成功 - * @return false 游戏结束或网络错误 - */ -bool handle_network_player_turn(int current_player, bool is_local_turn); - -/** - * @brief 网络游戏主循环 - * @return true 游戏正常结束 - * @return false 网络错误 - */ -bool network_game_loop(); - -/** - * @brief 显示游戏规则 - */ -void show_game_rules(); - -/** - * @brief 显示关于游戏信息 - */ -void show_about_game(); - -/** - * @brief 启动图形化界面 - */ -void run_gui_mode(); - -#endif // GAME_MODE_H \ No newline at end of file diff --git a/include/gobang.h b/include/gobang.h index 681ee58..3c3e94c 100644 --- a/include/gobang.h +++ b/include/gobang.h @@ -20,6 +20,11 @@ // 函数原型 // --- 游戏核心逻辑 --- +/** + * @brief 初始化棋盘,将所有位置设置为空(EMPTY) + */ +void empty_board(); + /** * @brief 检查指定坐标是否为有效落子点(在棋盘内且为空) * @param x 待检查的行坐标 (0-based) diff --git a/include/gui.h b/include/gui.h index 81a3507..cc0ff47 100644 --- a/include/gui.h +++ b/include/gui.h @@ -81,4 +81,16 @@ void start_pve_game_gui(); */ void start_replay_gui(); +/** + * @brief 启动图形化界面模式 + * @note 替代原来的 main 函数中的 GUI 分支逻辑 + */ +int init_gui(); // Already declared + +/** + * @brief 运行图形化界面模式 + * @details 主循环处理事件、渲染画面和更新状态 + */ +void run_gui_mode(); + #endif // GUI_H \ No newline at end of file diff --git a/include/init_board.h b/include/init_board.h deleted file mode 100644 index dd81706..0000000 --- a/include/init_board.h +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @file init_board.h - * @brief 初始化游戏棋盘头文件 - * @note 本文件定义了初始化游戏棋盘的相关函数和全局变量。 - * 它负责设置游戏的初始状态,包括棋盘大小、玩家标识、游戏规则等。 - */ - -#ifndef INIT_BOARD_H -#define INIT_BOARD_H - -#include "gobang.h" - -// --- 游戏初始化 --- -/** - * @brief 初始化棋盘,将所有位置设置为空(EMPTY) - */ -void empty_board(); - -/** - * @brief 将当前棋盘状态打印到控制台 - */ -void print_board(); - -/** - * @brief 设置当前游戏的棋盘大小 - */ -void setup_board_size(); - -/** - * @brief 设置游戏选项,如是否启用禁手、计时器等 - */ -void setup_game_options(); - -/** - * @brief 决定先手玩家 - * @param player1 玩家1的标识 - * @param player2 玩家2的标识 - * @return 返回先手玩家的标识 - */ -int determine_first_player(int player1, int player2); - -#endif // INIT_H \ No newline at end of file diff --git a/include/record.h b/include/record.h index a5452ef..5eaf9d5 100644 --- a/include/record.h +++ b/include/record.h @@ -10,12 +10,6 @@ #include "gobang.h" // --- 复盘与记录功能 --- -/** - * @brief 进入复盘流程,回顾整局游戏 - * @param game_mode 游戏模式(1为人机对战,2为双人对战) - */ -void review_process(int game_mode); - /** * @brief 将当前对局记录保存到文件 * @param filename 要保存到的文件名 @@ -24,12 +18,6 @@ void review_process(int game_mode); */ int save_game_to_file(const char *filename, int game_mode); -/** - * @brief 处理保存游戏记录的逻辑 - * @param game_mode 游戏模式 - */ -void handle_save_record(int game_mode); - /** * @brief 从文件加载游戏记录 * @param filename 要加载的文件名 diff --git a/include/ui.h b/include/ui.h deleted file mode 100644 index da26b1f..0000000 --- a/include/ui.h +++ /dev/null @@ -1,69 +0,0 @@ -/** - * @file ui.h - * @brief - * @note 本文件定义了用户界面相关的函数和数据结构。 - * 它负责处理用户输入、显示游戏界面、提示信息等与用户交互的功能。 - */ - -#ifndef UI_H -#define UI_H - -#include "gobang.h" - -/** - * @brief UI模块 - 用户界面相关功能 - * @author 刘航宇 - * @date 2025-07-10 - * @version 5.0 - */ - -/** - * @brief 显示游戏主菜单 - */ -void display_main_menu(); - -/** - * @brief 显示棋盘 - */ -void display_board(); - -/** - * @brief 显示游戏状态信息 - * @param current_player 当前玩家 - * @param step_count 当前步数 - */ -void display_game_status(int current_player, int step_count); - -/** - * @brief 显示获胜信息 - * @param winner 获胜者 - */ -void display_winner(int winner); - -/** - * @brief 显示游戏设置菜单 - */ -void display_settings_menu(); - -/** - * @brief 清屏函数 - */ -void clear_screen(); - -/** - * @brief 暂停等待用户输入 - * @param prompt 提示信息 - */ -void pause_for_input(const char* prompt); - -/** - * @brief 显示游戏规则 - */ -void display_game_rules(); - -/** - * @brief 显示关于信息 - */ -void display_about(); - -#endif // UI_H \ No newline at end of file diff --git a/src/config.c b/src/config.c index 1c0ee95..2811f43 100644 --- a/src/config.c +++ b/src/config.c @@ -5,8 +5,6 @@ */ #include "config.h" -#include "ui.h" -#include "game_mode.h" #include "globals.h" #include #include @@ -131,129 +129,4 @@ void reset_to_default_config() defense_coefficient = DEFAULT_DEFENSE_COEFFICIENT + (ai_difficulty - 1) * 0.1; printf("已重置为默认配置\n"); -} - -/** - * @brief 显示当前配置 - */ -void display_current_config() -{ - printf("\n===== 当前游戏配置 =====\n"); - printf("棋盘大小: %d x %d\n", BOARD_SIZE, BOARD_SIZE); - printf("禁手规则: %s\n", use_forbidden_moves ? "开启" : "关闭"); - printf("计时器: %s\n", use_timer ? "开启" : "关闭"); - if (use_timer) - { - printf("时间限制: %d 分钟\n", time_limit / 60); - } - printf("网络端口: %d\n", network_port); - printf("网络超时: %d 毫秒\n", network_timeout); - printf("=====================\n"); -} - -/** - * @brief 配置棋盘大小 - */ -void config_board_size() -{ - printf("\n当前棋盘大小: %d x %d\n", BOARD_SIZE, BOARD_SIZE); - - int new_size = get_integer_input("请输入新的棋盘大小: ", MIN_BOARD_SIZE, MAX_BOARD_SIZE); - BOARD_SIZE = new_size; - printf("棋盘大小已设置为: %d x %d\n", BOARD_SIZE, BOARD_SIZE); -} - -/** - * @brief 配置禁手规则 - */ -void config_forbidden_moves() -{ - printf("\n当前禁手规则: %s\n", use_forbidden_moves ? "开启" : "关闭"); - - int choice = get_integer_input("是否启用禁手规则?(1=开启, 0=关闭): ", 0, 1); - use_forbidden_moves = (choice != 0); - printf("禁手规则已%s\n", use_forbidden_moves ? "开启" : "关闭"); -} - -/** - * @brief 配置计时器 - */ -void config_timer() -{ - printf("\n当前计时器: %s\n", use_timer ? "开启" : "关闭"); - - int choice = get_integer_input("是否启用计时器?(1=开启, 0=关闭): ", 0, 1); - use_timer = choice; - if (use_timer) - { - int new_limit = get_integer_input("请输入时间限制(分钟): ", 1, 999); - time_limit = new_limit * 60; // 转换为秒数存储 - printf("计时器已开启,时间限制: %d 分钟\n", time_limit / 60); - } - else - { - printf("计时器已关闭\n"); - } -} - -/** - * @brief 配置网络参数 - */ -void config_network() -{ - printf("\n===== 网络配置 =====\n"); - printf("当前网络端口: %d\n", network_port); - printf("当前网络超时: %d 毫秒\n", network_timeout); - - int new_port = get_integer_input("请输入新的网络端口: ", MIN_NETWORK_PORT, MAX_NETWORK_PORT); - network_port = new_port; - printf("网络端口已设置为: %d\n", network_port); - - int new_timeout = get_integer_input("请输入网络超时时间(毫秒, 建议1000-10000): ", 1000, 60000); - network_timeout = new_timeout; - printf("网络超时已设置为: %d 毫秒\n", network_timeout); -} - -/** - * @brief 配置管理主菜单 - */ -void config_management_menu() -{ - int choice; - - while (1) - { - clear_screen(); - display_settings_menu(); - display_current_config(); - - choice = get_integer_input("请选择操作(0-5): ", 0, 5); - - switch (choice) - { - case 1: - config_board_size(); - break; - case 2: - config_forbidden_moves(); - break; - case 3: - config_timer(); - break; - case 4: - config_network(); - break; - case 5: - printf("AI难度设置功能开发中...\n"); - break; - case 0: - save_game_config(); - return; - default: - printf("无效的选择!\n"); - break; - } - - pause_for_input("按任意键继续..."); - } } \ No newline at end of file diff --git a/src/game_mode.c b/src/game_mode.c deleted file mode 100644 index 1a0d163..0000000 --- a/src/game_mode.c +++ /dev/null @@ -1,971 +0,0 @@ -/** - * @file game_mode.c - * @brief 五子棋游戏框架源文件 - * @note 本文件定义了五子棋游戏的四种主要模式: - * 1. AI对战模式 - * 2. 双人对战模式 - * 3. 网络对战模式 - * 4. 复盘模式 - */ - -#include "game_mode.h" -#include "init_board.h" -#include "gobang.h" -#include "ai.h" -#include "record.h" -#include "config.h" -#include "network.h" -#include "ui.h" -#include "gui.h" -#include "globals.h" -#include -#include -#include -#include -#include - -// 全局变量现在在globals.c中定义 -#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 parse_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) - { - // 如果第二个数字不可用,则检查特殊命令 - if (*x == INPUT_UNDO) - { - int steps_to_undo; - steps_to_undo = get_integer_input("请输入要悔棋的步数(双方各退步数相同): ", 1, step_count / 2); - if (return_move(steps_to_undo * 2)) - { - printf("成功悔棋,双方各退 %d 步!\n", steps_to_undo); - print_board(); - } - else - { - printf("无法悔棋!\n"); - } - return 0; // 特殊命令已处理 - } - else if (*x == INPUT_SAVE) - { - // ... 处理保存 ... - return false; // 特殊命令 - } - else if (*x == INPUT_EXIT) - { - // ... 处理退出 ... - return false; // 特殊命令 - } - printf("无效输入,请输入两个数字坐标。\n"); - while (getchar() != '\n') - ; - return 0; // 无效输入 - } - } - else - { - // sscanf失败,检查特殊命令 - if (input[0] == 'r' || input[0] == 'R') - { - int steps_to_undo; - steps_to_undo = get_integer_input("请输入要悔棋的步数(双方各退步数相同): ", 1, step_count / 2); - if (return_move(steps_to_undo * 2)) - { - printf("成功悔棋,双方各退 %d 步!\n", steps_to_undo); - print_board(); - } - else - { - printf("无法悔棋!\n"); - } - return false; // 特殊命令 - } - else if (input[0] == 's' || input[0] == 'S') - { - *x = INPUT_SURRENDER; - int confirm = get_integer_input("确认认输?(1:是/0:否): ", 0, 1); - if (confirm) - { - printf("玩家选择认输!\n"); - return 1; // 正常回合完成 // 返回认输命令 - } - else - { - printf("取消认输!\n"); - return false; // 取消认输 - } - } - 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; // 有效坐标 -} - -/** - * @brief 处理玩家回合 - * @param current_player 当前玩家 - * @return true - */ -bool handle_player_turn(int current_player) -{ - int x, y; - time_t start_time, end_time; - if (use_timer) - { - time(&start_time); - } - - while (1) - { - printf("\n玩家%d, 请输入落子坐标(行 列,1~%d),或输入R/r悔棋,S/s认输:", current_player, 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玩家%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; - } - } - - x--; - y--; - - if (player_move(x, y, current_player)) - { - break; // 成功落子,跳出循环 - } - else - { - printf("坐标无效!请重新输入。\n"); - // 继续循环,重新输入坐标 - } - } - print_board(); - - if (check_win(x, y, current_player)) - { - printf("\n玩家%d获胜!\n", current_player); - return false; // 游戏结束 - } - - return true; // 成功落子 -} - -/** - * @brief 运行AI游戏 - * @note 从文件中加载历史记录并进行复盘 - * @param AI_DEPTH AI的搜索深度 - */ -void run_ai_game() -{ - // 重置评分计算标志,确保每局游戏都会重新计算评分 - scores_calculated = 0; - - // AI对战模式 - int AI_DEPTH = DEFAULT_AI_DEPTH; - AI_DEPTH = get_integer_input("请选择AI难度(1~5), 数字越大越强,注意数字越大AI思考时间越长!):", 1, 5); - - /** - * @brief AI的防守系数,系数越大越倾向于防守 - * @note 1~1.5 - * 2~1.6 - * 3~1.7 - * 4~1.8 - * 5~1.9 - */ - defense_coefficient = DEFAULT_DEFENSE_COEFFICIENT + (AI_DEPTH - 1) * 0.1; - - 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) - { - // 检查玩家是否获胜 - Step last_step = steps[step_count - 1]; - if (check_win(last_step.x, last_step.y, PLAYER)) - { - printf("\n玩家获胜!\n"); - break; - } - 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"); - review_process(GAME_MODE_AI); // AI对战模式 - handle_save_record(GAME_MODE_AI); // AI对战模式 -} - -/** - * @brief 运行双人对战模式 - * @note 从文件中加载历史记录并进行复盘 - */ -void run_pvp_game() -{ - // 重置评分计算标志,确保每局游戏都会重新计算评分 - scores_calculated = 0; - - // 双人对战模式 - empty_board(); - int current_player = determine_first_player(PLAYER1, PLAYER2); - 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 == PLAYER1) ? PLAYER2 : PLAYER1; - } - } - printf("===== 游戏结束 =====\n"); - review_process(GAME_MODE_PVP); // 双人对战模式 - handle_save_record(GAME_MODE_PVP); // 双人对战模式 -} - -/** - * @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); - } - else - { - printf("加载复盘文件失败!可能是旧版本文件格式或文件损坏\n"); - } -} - -/** - * @brief 网络对战模式 - */ -void run_network_game() -{ - // 重置评分计算标志 - scores_calculated = 0; - - // 初始化网络模块 - if (!init_network()) - { - printf("网络初始化失败!\n"); - pause_for_input("按任意键返回主菜单..."); - return; - } - - printf("=== 网络对战模式 ===\n"); - printf("1. 创建房间(作为主机)\n"); - printf("2. 加入房间(连接到主机)\n"); - - int choice = get_integer_input("请选择模式(1-2): ", 1, 2); - - bool connection_success = false; - - 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 - { - // 客户端模式 - char ip[MAX_IP_LENGTH]; - - // 循环直到输入有效的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正在连接到服务器 %s:%d...\n", ip, port); - connection_success = connect_to_server(ip, port); - } - - if (!connection_success) - { - printf("网络连接失败!\n"); - cleanup_network(); - pause_for_input("按任意键返回主菜单..."); - return; - } - - printf("\n网络连接成功!游戏即将开始...\n"); - printf("你是玩家%d,%s先手\n", - network_state.local_player_id, - network_state.local_player_id == PLAYER1 ? "你" : "对方"); - - // 开始网络游戏 - empty_board(); - print_board(); - - if (network_game_loop()) - { - printf("===== 游戏结束 =====\n"); - review_process(GAME_MODE_NETWORK); // 网络对战模式的复盘 - handle_save_record(GAME_MODE_NETWORK); // 保存为网络对战模式记录 - } - else - { - printf("游戏因网络错误而结束\n"); - } - - // 清理网络连接 - disconnect_network(); - pause_for_input("按任意键返回主菜单..."); -} - -/** - * @brief 显示游戏规则 - */ -void show_game_rules() -{ - clear_screen(); - display_game_rules(); - pause_for_input("\n按任意键返回主菜单..."); -} - -/** - * @brief 显示关于游戏信息 - */ -void show_about_game() -{ - clear_screen(); - display_about(); - pause_for_input("\n按任意键返回主菜单..."); -} - -/** - * @brief 启动图形化界面 - */ -void run_gui_mode() -{ - if (init_gui() == 0) - { - printf("启动图形化界面...\n"); - printf("图形化界面已启动,窗口应该可见\n"); - printf("如果看不到窗口,请检查任务栏或按Alt+Tab切换\n"); - while (gui_running && handle_events()) - { - render_game(); - } - printf("退出图形化界面\n"); - cleanup_gui(); - } - else - { - printf("图形化界面启动失败!请检查SDL3库是否正确安装。\n"); - pause_for_input("按任意键返回主菜单..."); - } -} - -/** - * @brief 处理网络玩家回合 - */ -bool handle_network_player_turn(int current_player, bool is_local_turn) -{ - if (is_local_turn) - { - // 本地玩家回合 - int x, y; - time_t start_time, end_time; - - if (use_timer) - { - time(&start_time); - } - - 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; - } - } - - x--; - y--; // 转换为0-based坐标 - - if (player_move(x, y, current_player)) - { - break; // 成功落子,跳出循环 - } - else - { - printf("坐标无效!请重新输入。\n"); - // 继续循环,重新输入坐标 - } - } - - // 发送落子消息 - if (!send_move(x, y, current_player)) - { - printf("发送落子消息失败!\n"); - return 0; // 游戏结束 - } - - print_board(); - - if (check_win(x, y, current_player)) - { - printf("\n你获胜了!\n"); - return 0; // 游戏结束 - } - } - 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) - { - // 收到落子消息 - if (!player_move(msg.x, msg.y, current_player)) - { - printf("收到无效的落子坐标!\n"); - return 0; // 游戏结束 - } - - printf("对方落子: (%d, %d)\n", msg.x + 1, msg.y + 1); - print_board(); - - if (check_win(msg.x, msg.y, current_player)) - { - printf("\n对方获胜!\n"); - return 0; // 游戏结束 - } - break; - } - else if (msg.type == MSG_SURRENDER) - { - printf("\n对方认输,你获胜了!\n"); - return 0; // 游戏结束 - } - else if (msg.type == MSG_DISCONNECT) - { - printf("\n对方已断开连接\n"); - return 0; // 游戏结束 - } - else if (msg.type == MSG_CHAT) - { - printf("[对方]: %s\n", msg.message); - } - 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)) - { - printf("同意悔棋,双方各退 %d 步\n", steps); - send_undo_response(true, steps); - print_board(); - // 悔棋后需要重新开始当前回合,不改变current_player - return 2; // 悔棋发生,需要重新开始回合 - } - else - { - printf("拒绝悔棋\n"); - send_undo_response(false, steps); - // 继续等待对方落子 - } - } - } - - // 检查超时 - if (use_timer && difftime(time(NULL), start_time) > time_limit) - { - printf("\n对方超时,你获胜!\n"); - return 0; // 游戏结束 - } - - // 检查网络连接 - if (!is_network_connected()) - { - printf("\n网络连接断开\n"); - return 0; // 游戏结束 - } - } - } - - return 1; // 正常回合完成 -} - -/** - * @brief 网络游戏主循环 - */ -bool network_game_loop() -{ - int current_player = PLAYER1; // 总是从玩家1开始 - - while (1) - { - bool is_local_turn = (current_player == network_state.local_player_id); - - 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) - { - printf("\n平局!\n"); - return true; - } - - // 切换玩家 - current_player = (current_player == PLAYER1) ? PLAYER2 : PLAYER1; - - // 检查网络连接 - if (!is_network_connected()) - { - printf("\n网络连接断开\n"); - return false; - } - } - - return true; -} \ No newline at end of file diff --git a/src/gobang.c b/src/gobang.c index 6ed40ab..4dcf6c9 100644 --- a/src/gobang.c +++ b/src/gobang.c @@ -5,8 +5,6 @@ * 它包含了游戏棋盘的表示、玩家操作、规则检查以及AI决策等功能。 */ -#include "game_mode.h" -#include "init_board.h" #include "gobang.h" #include "ai.h" #include "record.h" @@ -16,6 +14,23 @@ #include #include +/** + * @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, y)位置是否为空 * @param x 行坐标(0-base) diff --git a/src/gui.c b/src/gui.c index f844253..2d7feeb 100644 --- a/src/gui.c +++ b/src/gui.c @@ -9,9 +9,7 @@ #include "gui.h" #include #include -#include "ui.h" #include "globals.h" -#include "init_board.h" #include "gobang.h" #include "gui_menu.h" #include "ai.h" @@ -26,13 +24,15 @@ static Ihandle *lbl_player = NULL; static Ihandle *lbl_status = NULL; static int gui_loop_running = 0; static int gui_game_mode = 0; // 0: PvP, 1: PvE, 2: Replay -static int replay_total_steps = 0; // For Replay Mode +static int replay_total_steps = 0; // 为了复盘而记录的总步数 // 回调函数 static int action_cb(Ihandle *ih); static int button_cb(Ihandle *ih, int button, int pressed, int x, int y, char *status); static int k_any_cb(Ihandle *ih, int c); void create_game_window(); // 移除前向声明 +static int btn_replay_sel_ok_cb(Ihandle *ih); +static int btn_replay_sel_cancel_cb(Ihandle *ih); // 辅助函数:设置绘图颜色 static void set_draw_color(Ihandle *ih, unsigned char r, unsigned char g, unsigned char b) @@ -123,7 +123,7 @@ static void draw_stones_iup(Ihandle *ih) } // 标记最后落子位置 (红色小点) - if (step_count > 0) + if (step_count > 0 && step_count <= MAX_STEPS) { // 绘制最后一步的标记 // 最后一步的坐标是 steps[step_count-1] @@ -179,6 +179,17 @@ static void update_ui_labels() } } +/** + * @brief 显示消息 + */ +void show_message(const char *message) +{ + strncpy(status_message, message, sizeof(status_message) - 1); + status_message[sizeof(status_message) - 1] = '\0'; + update_ui_labels(); + printf("%s\n", message); +} + // ACTION 回调:负责重绘 static int action_cb(Ihandle *ih) { @@ -294,7 +305,7 @@ static int btn_replay_prev_cb(Ihandle *ih) static int btn_replay_next_cb(Ihandle *ih) { (void)ih; - if (step_count < replay_total_steps) + if (step_count < replay_total_steps && step_count >= 0) // Ensure step_count is valid { Step s = steps[step_count]; board[s.x][s.y] = s.player; @@ -310,12 +321,29 @@ static int btn_replay_next_cb(Ihandle *ih) static int btn_back_cb(Ihandle *ih) { (void)ih; + printf("DEBUG: Back to Menu clicked\n"); + + // 1. Show main menu FIRST + show_main_menu(); + printf("DEBUG: Main menu shown\n"); + + // 2. Destroy game window + // Important: We must destroy the game window to free resources and potentially stop its event loop contribution. + // But we must NOT close the application. + // If we only Hide, it stays in memory. + // If we Destroy, it's gone. + if (dlg) { - IupHide(dlg); - show_main_menu(); + // IupHide(dlg); // Hiding is safer if Destroy causes loop exit + // printf("DEBUG: Hiding game window\n"); + Ihandle *old_dlg = dlg; + dlg = NULL; // Clear global pointer first + IupDestroy(old_dlg); + printf("DEBUG: Destroyed game window\n"); } - return IUP_DEFAULT; + + return IUP_IGNORE; // Return IUP_IGNORE to prevent default processing (like closing if CLOSE_CB) } // 鼠标点击回调 @@ -421,20 +449,33 @@ static int k_any_cb(Ihandle *ih, int c) // 创建游戏窗口 void create_game_window() { + printf("DEBUG: create_game_window start\n"); + // if (dlg) + // { + // IupDestroy(dlg); // 销毁旧窗口 + // dlg = NULL; + // } + // Only destroy if it exists and is not the current dialog? + // Actually, creating a new dialog while old one is valid is fine, but we should destroy old one to save memory. + // However, if destroying dlg causes main loop to exit because it was the last visible window (if main menu was hidden)... + if (dlg) { - IupDestroy(dlg); // 销毁旧窗口 + IupDestroy(dlg); dlg = NULL; } // 创建Canvas (Board) board_canvas = IupCanvas(NULL); + if (!board_canvas) + printf("ERROR: Failed to create board_canvas\n"); + IupSetAttribute(board_canvas, "ACTION", "action_cb"); IupSetCallback(board_canvas, "ACTION", (Icallback)action_cb); IupSetCallback(board_canvas, "BUTTON_CB", (Icallback)button_cb); IupSetCallback(board_canvas, "K_ANY", (Icallback)k_any_cb); - // + // int board_pixel_size = BOARD_SIZE * CELL_SIZE + BOARD_OFFSET_X * 2; char size[32]; sprintf(size, "%dx%d", board_pixel_size, board_pixel_size); @@ -443,10 +484,10 @@ void create_game_window() // 创建标签 (玩家信息和游戏状态) lbl_player = IupLabel("当前玩家: 黑子"); - IupSetAttribute(lbl_player, "FONT", "SimHei, 14"); + // IupSetAttribute(lbl_player, "FONT", "SimHei, 14"); // Comment out potentially problematic font setting lbl_status = IupLabel("准备开始"); - IupSetAttribute(lbl_status, "FONT", "SimHei, 12"); + // IupSetAttribute(lbl_status, "FONT", "SimHei, 12"); Ihandle *vbox_controls; @@ -509,10 +550,14 @@ void create_game_window() // 创建Dialog dlg = IupDialog(hbox_main); + if (!dlg) + printf("ERROR: Failed to create dialog\n"); + IupSetAttribute(dlg, "TITLE", "五子棋 - IUP版本"); IupSetAttribute(dlg, "RESIZE", "NO"); IupMap(dlg); + printf("DEBUG: create_game_window end\n"); } void start_pvp_game_gui() @@ -533,6 +578,7 @@ void start_pvp_game_gui() void start_pve_game_gui() { + printf("DEBUG: start_pve_game_gui start\n"); gui_game_mode = 1; // ai_difficulty is global empty_board(); @@ -540,67 +586,162 @@ void start_pve_game_gui() game_over = 0; create_game_window(); + printf("DEBUG: create_game_window returned\n"); + + if (dlg) + { + IupShowXY(dlg, IUP_CENTER, IUP_CENTER); + printf("DEBUG: IupShowXY called\n"); + } + else + { + printf("ERROR: dlg is NULL in start_pve_game_gui\n"); + return; + } - IupShowXY(dlg, IUP_CENTER, IUP_CENTER); sprintf(status_message, "人机对战模式 - 玩家执黑先行"); update_ui_labels(); + printf("DEBUG: update_ui_labels returned\n"); + + // Force initial draw if (board_canvas) + { IupUpdate(board_canvas); + // IupFlush(); // Comment out to check if this caused the crash + } + printf("DEBUG: start_pve_game_gui end\n"); } -void start_replay_gui() +#ifdef _WIN32 +#include +#endif + +// 选择复盘文件 +static void select_replay_file_gui() { - // Open file dialog - Ihandle *file_dlg = IupFileDlg(); - IupSetAttribute(file_dlg, "DIALOGTYPE", "OPEN"); - IupSetAttribute(file_dlg, "TITLE", "选择复盘文件"); - IupSetAttribute(file_dlg, "FILTER", "*.csv"); - IupSetAttribute(file_dlg, "FILTERINFO", "CSV Files"); + // List files in records/ directory + char record_files[100][100]; + int file_count = 0; - IupPopup(file_dlg, IUP_CENTER, IUP_CENTER); - - if (IupGetInt(file_dlg, "STATUS") != -1) +#ifdef _WIN32 + WIN32_FIND_DATA ffd; + HANDLE hFind = FindFirstFile("records\\*.csv", &ffd); + if (hFind != INVALID_HANDLE_VALUE) { - char *filename = IupGetAttribute(file_dlg, "VALUE"); + do + { + if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + strcpy(record_files[file_count++], ffd.cFileName); + if (file_count >= 100) + break; + } + } while (FindNextFile(hFind, &ffd) != 0); + FindClose(hFind); + } +#endif - char *base_name = strrchr(filename, '\\'); - if (!base_name) - base_name = strrchr(filename, '/'); - if (base_name) - base_name++; - else - base_name = filename; + if (file_count == 0) + { + IupMessage("提示", "未找到复盘记录文件 (records/*.csv)"); + show_main_menu(); + return; + } - if (load_game_from_file(base_name)) // returns game_mode (non-zero) on success + // 创建列表框 + Ihandle *list = IupList(NULL); + IupSetAttribute(list, "EXPAND", "YES"); + IupSetAttribute(list, "VISIBLELINES", "10"); + + for (int i = 0; i < file_count; i++) + { + IupSetAttributeId(list, "", i + 1, record_files[i]); + } + IupSetAttribute(list, "VALUE", "1"); + + // 创建确定和取消按钮 + Ihandle *btn_ok = IupButton("确定", NULL); + IupSetCallback(btn_ok, "ACTION", (Icallback)btn_replay_sel_ok_cb); + IupSetAttribute(btn_ok, "SIZE", "60x30"); + + Ihandle *btn_cancel = IupButton("取消", NULL); + IupSetCallback(btn_cancel, "ACTION", (Icallback)btn_replay_sel_cancel_cb); + IupSetAttribute(btn_cancel, "SIZE", "60x30"); + + Ihandle *vbox = IupVbox( + IupLabel("请选择复盘文件:"), + list, + IupHbox(btn_ok, btn_cancel, NULL), + NULL); + IupSetAttribute(vbox, "MARGIN", "10x10"); + IupSetAttribute(vbox, "GAP", "10"); + IupSetAttribute(vbox, "ALIGNMENT", "ACENTER"); + + Ihandle *dlg_sel = IupDialog(vbox); + IupSetAttribute(dlg_sel, "TITLE", "选择复盘文件"); + IupSetAttribute(dlg_sel, "MINBOX", "NO"); + IupSetAttribute(dlg_sel, "MAXBOX", "NO"); + IupSetAttribute(dlg_sel, "RESIZE", "NO"); + + // 存储列表框句柄到对话框属性 + IupSetAttribute(dlg_sel, "MY_LIST", (char *)list); +} + +static int btn_replay_sel_ok_cb(Ihandle *ih) +{ + Ihandle *dlg = IupGetDialog(ih); + Ihandle *list = (Ihandle *)IupGetAttribute(dlg, "MY_LIST"); + char *filename = IupGetAttribute(list, "VALUE"); // Returns index + int index = atoi(filename); + char *selected_file = IupGetAttributeId(list, "", index); + + if (selected_file) + { + if (load_game_from_file(selected_file)) { replay_total_steps = step_count; step_count = 0; - // load_game_from_file already cleared board when reading steps, but steps were read into array - // wait, load_game_from_file calls empty_board() then reads steps. - // But it doesn't set board array. - // So board is empty. - gui_game_mode = 2; // Replay create_game_window(); + IupShowXY(dlg, IUP_CENTER, IUP_CENTER); // 展示 + + Ihandle *dlg_sel = dlg; + IupHide(dlg_sel); + IupDestroy(dlg_sel); IupShowXY(dlg, IUP_CENTER, IUP_CENTER); - sprintf(status_message, "复盘模式 - %s", base_name); + + sprintf(status_message, "复盘模式 - %s", selected_file); update_ui_labels(); if (board_canvas) IupUpdate(board_canvas); + + return IUP_DEFAULT; } else { IupMessage("错误", "无法加载复盘文件"); - show_main_menu(); } } - else - { - show_main_menu(); - } - IupDestroy(file_dlg); + IupHide(dlg); + IupDestroy(dlg); + show_main_menu(); + return IUP_DEFAULT; +} + +static int btn_replay_sel_cancel_cb(Ihandle *ih) +{ + Ihandle *dlg = IupGetDialog(ih); + IupHide(dlg); + IupDestroy(dlg); + show_main_menu(); + return IUP_DEFAULT; +} + +void start_replay_gui() +{ + select_replay_file_gui(); } /** @@ -691,12 +832,14 @@ void draw_ui_elements() } /** - * @brief 显示消息 + * @brief 运行图形化界面模式 + * @note 包含初始化、主循环和清理 */ -void show_message(const char *message) +void run_gui_mode() { - strncpy(status_message, message, sizeof(status_message) - 1); - status_message[sizeof(status_message) - 1] = '\0'; - update_ui_labels(); - printf("%s\n", message); -} + if (init_gui() == 0) + { + IupMainLoop(); // 使用IUP的主循环 + cleanup_gui(); + } +} \ No newline at end of file diff --git a/src/gui_menu.c b/src/gui_menu.c index 51507ff..ae435f2 100644 --- a/src/gui_menu.c +++ b/src/gui_menu.c @@ -11,16 +11,20 @@ static Ihandle *menu_dlg = NULL; static int btn_pvp_cb(Ihandle *ih) { (void)ih; - hide_main_menu(); + printf("DEBUG: Starting PvP Game\n"); + // hide_main_menu(); // DO NOT HIDE MAIN MENU YET start_pvp_game_gui(); + IupHide(menu_dlg); // Hide main menu manually AFTER game window created return IUP_DEFAULT; } static int btn_pve_cb(Ihandle *ih) { (void)ih; - hide_main_menu(); + printf("DEBUG: Starting PvE Game\n"); + // hide_main_menu(); // DO NOT HIDE MAIN MENU YET start_pve_game_gui(); + IupHide(menu_dlg); // Hide main menu manually AFTER game window created return IUP_DEFAULT; } @@ -35,38 +39,44 @@ static int btn_replay_cb(Ihandle *ih) static int btn_save_settings_cb(Ihandle *ih) { Ihandle *dlg = IupGetDialog(ih); - + // Get values Ihandle *txt_board_size = IupGetDialogChild(dlg, "BOARD_SIZE"); Ihandle *tgl_forbidden = IupGetDialogChild(dlg, "FORBIDDEN"); Ihandle *tgl_timer = IupGetDialogChild(dlg, "TIMER"); Ihandle *txt_time_limit = IupGetDialogChild(dlg, "TIME_LIMIT"); Ihandle *lst_ai = IupGetDialogChild(dlg, "AI_DIFFICULTY"); - + // Update globals int new_size = IupGetInt(txt_board_size, "VALUE"); - if (new_size < MIN_BOARD_SIZE) new_size = MIN_BOARD_SIZE; - if (new_size > MAX_BOARD_SIZE) new_size = MAX_BOARD_SIZE; + if (new_size < MIN_BOARD_SIZE) + new_size = MIN_BOARD_SIZE; + if (new_size > MAX_BOARD_SIZE) + new_size = MAX_BOARD_SIZE; BOARD_SIZE = new_size; - + use_forbidden_moves = IupGetInt(tgl_forbidden, "VALUE"); - + use_timer = IupGetInt(tgl_timer, "VALUE"); - if (use_timer) { + if (use_timer) + { int minutes = IupGetInt(txt_time_limit, "VALUE"); - if (minutes < 1) minutes = 1; + if (minutes < 1) + minutes = 1; time_limit = minutes * 60; } - + int ai_level = IupGetInt(lst_ai, "VALUE"); - if (ai_level < 1) ai_level = 1; - if (ai_level > 5) ai_level = 5; + if (ai_level < 1) + ai_level = 1; + if (ai_level > 5) + ai_level = 5; ai_difficulty = ai_level; defense_coefficient = DEFAULT_DEFENSE_COEFFICIENT + (ai_difficulty - 1) * 0.1; - + // Save config save_game_config(); - + IupHide(dlg); return IUP_DEFAULT; } @@ -89,7 +99,7 @@ static int tgl_timer_cb(Ihandle *ih, int state) static int btn_settings_cb(Ihandle *ih) { (void)ih; - + // 1. Board Size Ihandle *lbl_board_size = IupLabel("棋盘大小 (5-25):"); Ihandle *txt_board_size = IupText(NULL); @@ -99,18 +109,18 @@ static int btn_settings_cb(Ihandle *ih) IupSetAttribute(txt_board_size, "SPINMAX", "25"); IupSetInt(txt_board_size, "VALUE", BOARD_SIZE); IupSetAttribute(txt_board_size, "SIZE", "50x"); - + // 2. Forbidden Moves Ihandle *tgl_forbidden = IupToggle("启用禁手规则", NULL); IupSetAttribute(tgl_forbidden, "NAME", "FORBIDDEN"); IupSetInt(tgl_forbidden, "VALUE", use_forbidden_moves); - + // 3. Timer Ihandle *tgl_timer = IupToggle("启用计时器", NULL); IupSetAttribute(tgl_timer, "NAME", "TIMER"); IupSetInt(tgl_timer, "VALUE", use_timer); IupSetCallback(tgl_timer, "ACTION", (Icallback)tgl_timer_cb); - + // 4. Time Limit Ihandle *lbl_time_limit = IupLabel("时间限制 (分钟):"); Ihandle *txt_time_limit = IupText(NULL); @@ -139,11 +149,11 @@ static int btn_settings_cb(Ihandle *ih) Ihandle *btn_save = IupButton("保存", NULL); IupSetCallback(btn_save, "ACTION", (Icallback)btn_save_settings_cb); IupSetAttribute(btn_save, "SIZE", "60x"); - + Ihandle *btn_cancel = IupButton("取消", NULL); IupSetCallback(btn_cancel, "ACTION", (Icallback)btn_cancel_settings_cb); IupSetAttribute(btn_cancel, "SIZE", "60x"); - + // Layout Ihandle *hbox_board = IupHbox(lbl_board_size, txt_board_size, NULL); IupSetAttribute(hbox_board, "ALIGNMENT", "ACENTER"); @@ -161,7 +171,7 @@ static int btn_settings_cb(Ihandle *ih) IupSetAttribute(hbox_btns, "GAP", "20"); IupSetAttribute(hbox_btns, "MARGIN", "10x0"); IupSetAttribute(hbox_btns, "ALIGNMENT", "ACENTER"); - + Ihandle *vbox = IupVbox( hbox_board, tgl_forbidden, @@ -171,19 +181,19 @@ static int btn_settings_cb(Ihandle *ih) IupLabel(NULL), // Spacer hbox_btns, NULL); - + IupSetAttribute(vbox, "GAP", "15"); IupSetAttribute(vbox, "MARGIN", "30x30"); - + Ihandle *dlg = IupDialog(vbox); IupSetAttribute(dlg, "TITLE", "游戏设置"); IupSetAttribute(dlg, "RESIZE", "NO"); IupSetAttribute(dlg, "MINBOX", "NO"); IupSetAttribute(dlg, "MAXBOX", "NO"); - + IupPopup(dlg, IUP_CENTER, IUP_CENTER); IupDestroy(dlg); - + return IUP_DEFAULT; } @@ -197,7 +207,9 @@ static int btn_exit_cb(Ihandle *ih) void create_main_menu() { - if (menu_dlg) return; + if (menu_dlg) + return; + printf("DEBUG: create_main_menu\n"); Ihandle *lbl_title = IupLabel("五子棋 (Gobang)"); IupSetAttribute(lbl_title, "FONT", "SimHei, 24"); @@ -245,16 +257,22 @@ void create_main_menu() IupSetAttribute(menu_dlg, "RESIZE", "NO"); IupSetAttribute(menu_dlg, "MINBOX", "NO"); IupSetAttribute(menu_dlg, "MAXBOX", "NO"); - + // 设置对话框关闭回调 (点X关闭程序) IupSetCallback(menu_dlg, "CLOSE_CB", (Icallback)btn_exit_cb); + IupMap(menu_dlg); // Map immediately } void show_main_menu() { + printf("DEBUG: show_main_menu start\n"); if (!menu_dlg) + { + printf("DEBUG: Creating main menu\n"); create_main_menu(); + } IupShowXY(menu_dlg, IUP_CENTER, IUP_CENTER); + printf("DEBUG: show_main_menu end\n"); } void hide_main_menu() diff --git a/src/init_board.c b/src/init_board.c deleted file mode 100644 index c2cdfa9..0000000 --- a/src/init_board.c +++ /dev/null @@ -1,125 +0,0 @@ -/** - * @file init_board.c - * @brief 初始化游戏棋盘源文件 - * @note 本文件定义了初始化游戏棋盘的相关函数。 - * 它负责设置游戏的初始状态,包括棋盘大小、玩家标识、游戏规则等。 - */ - -#include "init_board.h" -#include "gobang.h" -#include "game_mode.h" -#include "config.h" -#include "globals.h" -#include -#include -#include - -/** - * @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 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; - } -} \ No newline at end of file diff --git a/src/main.c b/src/main.c index e744e8a..485277d 100644 --- a/src/main.c +++ b/src/main.c @@ -4,22 +4,16 @@ * @note 本文件包含了游戏的主循环、模式选择和游戏初始化等功能 * @brief 将以下指令复制到powershell * - * !控制台版本编译: - * mingw32-make console - .\bin\gobang_console.exe - * * !图形化版本编译(需要IUP库): * mingw32-make gui .\bin\gobang_gui.exe * * @note gcc 为编译器,添加了-lws2_32链接Windows网络库 * @note IUP 的路径:libs\iup-3.31_Win64_dllw6_lib - * @brief & "D:\Program Files (x86)\NSIS\makensis.exe" "installer\\installer.nsi" * @brief & "D:\Program Files (x86)\Inno Setup 6\iscc.exe" installer\\installer.iss */ -#include "game_mode.h" -#include "ui.h" +#include "gui.h" #include "config.h" #include #ifdef _WIN32 @@ -40,58 +34,7 @@ int main(int argc, char *argv[]) // 加载游戏配置 load_game_config(); - // 选择模式 - while (1) - { - clear_screen(); - display_main_menu(); - int mode = get_integer_input("请输入模式(0-8): ", 0, 8); - - 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: - show_game_rules(); - break; - // 7. 关于游戏 - case 7: - show_about_game(); - break; - // 8. 图形化界面 - case 8: - run_gui_mode(); - break; - // 0. 退出游戏 - case 0: - save_game_config(); - printf("感谢使用五子棋游戏!\n"); - return 0; - default: - printf("无效的选择!\n"); - pause_for_input("按任意键继续..."); - break; - } - } - + // 启动图形化界面 + run_gui_mode(); return 0; } \ No newline at end of file diff --git a/src/record.c b/src/record.c index 5c19b96..b279848 100644 --- a/src/record.c +++ b/src/record.c @@ -6,10 +6,7 @@ */ #include "record.h" -#include "game_mode.h" #include "gobang.h" -#include "init_board.h" -#include "ui.h" #include "config.h" #include "globals.h" #include @@ -47,139 +44,7 @@ * - 包含输入缓冲区清理防止意外输入 * - 评分环节调用calculate_final_score()函数 */ -void review_process(int game_mode) -{ - int review_choice = get_integer_input("是否要复盘本局比赛? (1-是, 0-否): ", 0, 1); - - // 如果评分尚未计算,则计算评分 - if (!scores_calculated) - { - calculate_game_scores(); - } - else - { - // 评分已从文件中加载,直接使用 - printf("从记录文件中加载评分数据\n"); - } - - if (review_choice == 1) - { - 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 == GAME_MODE_AI) - { - // 人机对战 - 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 if (game_mode == GAME_MODE_PVP) - { - // 双人对战 - 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); - } - 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(" "); - 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===== 对局结果 ====="); - if (strcmp(winner_info, "玩家获胜") == 0) - { - printf("\n? 恭喜!玩家获胜!\n"); - } - else if (strcmp(winner_info, "AI获胜") == 0) - { - printf("\n? AI获胜!\n"); - } - else if (strcmp(winner_info, "玩家1获胜") == 0) - { - printf("\n? 恭喜!玩家1(黑棋)获胜!\n"); - } - else if (strcmp(winner_info, "玩家2获胜") == 0) - { - printf("\n? 恭喜!玩家2(白棋)获胜!\n"); - } - else - { - printf("\n?? 对局平局或未完成\n"); - } - - printf("\n复盘结束!按Enter查看评分..."); - getchar(); // 等待用户按键 - } - - // 显示评分结果 - display_game_scores(game_mode); - - getchar(); -} +void calculate_game_scores(); /** * @brief 计算游戏评分 @@ -290,57 +155,8 @@ void display_game_scores(int game_mode) } } -/** - * @brief 处理游戏结束后的记录保存 - * @return int 保存状态码(0-成功, 1-目录创建失败, 2-文件打开失败, 3-文件写入失败) - */ -void handle_save_record(int game_mode) -{ - printf("===== 游戏结束 =====\n"); - int save_choice = get_integer_input("是否保存游戏记录? (1-是, 0-否): ", 0, 1); - - 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.csv", t); - - int save_status = save_game_to_file(filename, game_mode); - switch (save_status) - { - case 0: // 成功 - printf("\n游戏记录已成功保存至: %s (CSV格式)\n", filename); - printf("您可以使用以下命令进行复盘: .\\gobang.exe -l %s\n", filename); - printf("CSV格式文件可以直接用Excel打开查看和分析\n"); - 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 filename 要保存的文件名 - * @return int 错误码: - * 0: 成功 - * 1: 目录创建失败 - * 2: 文件打开失败 - * 3: 文件写入失败 */ int save_game_to_file(const char *filename, int game_mode) { diff --git a/src/ui.c b/src/ui.c deleted file mode 100644 index acc73e2..0000000 --- a/src/ui.c +++ /dev/null @@ -1,212 +0,0 @@ -/** - * @file ui.c - * @brief - * @note 本文件定义了用户界面相关的函数和数据结构。 - * 它负责处理用户输入、显示游戏界面、提示信息等与用户交互的功能。 - */ - -#include "ui.h" -#include "gobang.h" -#include "config.h" -#include "globals.h" -#include -#include -#ifdef _WIN32 -#include -#include -#else -#include -#endif - -/** - * @brief 显示游戏主菜单 - */ -void display_main_menu() -{ - printf("===== 五子棋游戏 =====\n"); - printf("1. AI模式\n"); - printf("2. 玩家比赛\n"); - printf("3. 网络对战\n"); - printf("4. 复盘模式\n"); - printf("5. 游戏设置\n"); - printf("6. 游戏规则\n"); - printf("7. 关于游戏\n"); - printf("8. 图形化界面\n"); - printf("0. 退出游戏\n"); - printf("=====================\n"); -} - -/** - * @brief 显示棋盘 - */ -void display_board() -{ - printf("\n "); - // 打印列号 - for (int j = 0; j < BOARD_SIZE; j++) - { - printf("%2d", j); - } - printf("\n"); - - // 打印棋盘内容 - for (int i = 0; i < BOARD_SIZE; i++) - { - printf("%2d", i); // 打印行号 - for (int j = 0; j < BOARD_SIZE; j++) - { - if (board[i][j] == EMPTY) - { - printf(" ·"); // 空位用点表示 - } - else if (board[i][j] == PLAYER || board[i][j] == PLAYER1) - { - printf(" ●"); // 玩家1用实心圆表示 - } - else - { - printf(" ○"); // 玩家2/AI用空心圆表示 - } - } - printf("\n"); - } - printf("\n"); -} - -/** - * @brief 显示游戏状态信息 - * @param current_player 当前玩家 - * @param step_count 当前步数 - */ -void display_game_status(int current_player, int step_count) -{ - printf("当前步数: %d\n", step_count); - if (current_player == PLAYER || current_player == PLAYER1) - { - printf("当前玩家: ●\n"); - } - else - { - printf("当前玩家: ○\n"); - } -} - -/** - * @brief 显示获胜信息 - * @param winner 获胜者 - */ -void display_winner(int winner) -{ - printf("\n游戏结束!\n"); - if (winner == PLAYER) - { - printf("玩家获胜!\n"); - } - else if (winner == AI) - { - printf("AI获胜!\n"); - } - else if (winner == PLAYER1) - { - printf("玩家1获胜!\n"); - } - else if (winner == PLAYER2) - { - printf("玩家2获胜!\n"); - } - else - { - printf("平局!\n"); - } -} - -/** - * @brief 显示游戏设置菜单 - */ -void display_settings_menu() -{ - printf("\n===== 游戏设置 =====\n"); - printf("1. 棋盘大小设置\n"); - printf("2. 禁手规则设置\n"); - printf("3. 计时器设置\n"); - printf("4. 网络配置设置\n"); - printf("5. AI难度设置\n"); - printf("0. 返回主菜单\n"); - printf("==================\n"); -} - -/** - * @brief 清屏函数 - */ -void clear_screen() -{ -#ifdef _WIN32 - system("cls"); -#else - system("clear"); -#endif -} - -/** - * @brief 暂停等待用户输入 - * @param prompt 提示信息 - */ -void pause_for_input(const char *prompt) -{ - printf("%s", prompt); -#ifdef _WIN32 - _getch(); -#else - getchar(); -#endif -} - -/** - * @brief 显示游戏规则 - */ -void display_game_rules() -{ - printf("\n===== 五子棋游戏规则 =====\n"); - printf("1. 🎮 游戏目标:\n"); - printf(" 在棋盘上连成五个同色棋子(横、竖、斜均可)\n\n"); - printf("2. 🔄 游戏流程:\n"); - printf(" - ⚫ 黑棋先行,双方轮流落子\n"); - printf(" - 📍 输入坐标格式:行号 列号(如:7 7)\n"); - printf(" - ✨ 棋子落在棋盘交叉点上\n\n"); - printf("3. 🏆 胜负判定:\n"); - printf(" - 🎉 率先连成五子者获胜\n"); - printf(" - 🤝 棋盘下满无人获胜则为平局\n\n"); - printf("4. 🚫 禁手规则(可选):\n"); - printf(" - ❌ 三三禁手:同时形成两个活三\n"); - printf(" - ❌ 四四禁手:同时形成两个冲四\n"); - printf(" - ❌ 长连禁手:连成六子或以上\n\n"); - printf("5. 🛠️ 特殊功能:\n"); - printf(" - ↩️ 悔棋:输入 'R' 或 'r' 可悔棋\n"); - printf(" - 💾 保存:游戏结束后可保存对局记录\n"); - printf(" - 📖 复盘:可加载历史对局进行复盘\n"); - printf("============================\n"); -} - -/** - * @brief 显示关于信息 - */ -void display_about() -{ - printf("\n===== 关于五子棋游戏 =====\n"); - printf("🎮 游戏名称:五子棋人机对战\n"); - printf("📦 版本:7.0\n"); - printf("👨‍💻 开发者:刘航宇\n"); - printf("📧 联系邮箱:3364451258@qq.com\n"); - printf("🌐 项目主页:https://github.com/LHY0125/Gobang-Game\n\n"); - printf("✨ 主要特性:\n"); - printf(" 🤖 智能AI对战(支持多种难度)\n"); - printf(" 👥 双人对战模式\n"); - printf(" 🌐 网络对战(局域网/互联网)\n"); - printf(" 📝 对局记录与复盘\n"); - printf(" 🚫 禁手规则支持\n"); - printf(" ⏱️ 计时器功能\n"); - printf(" 📏 自定义棋盘大小\n"); - printf(" 📊 评分系统\n\n"); - printf("🙏 感谢使用!\n"); - printf("========================\n"); -} \ No newline at end of file