diff --git a/README.md b/README.md index 3211e91..ae413a2 100644 --- a/README.md +++ b/README.md @@ -1,146 +1,146 @@ -# 馃幉 浜斿瓙妫嬩汉鏈哄鎴楢I +# ? 五子棋人机对战AI ![Build Status](https://img.shields.io/badge/build-passing-brightgreen) ![License](https://img.shields.io/badge/license-MIT-blue) ![Code Lines](https://img.shields.io/tokei/lines/github/your-username/your-repo) -## 鐩綍 -- [馃幉 浜斿瓙妫嬩汉鏈哄鎴楢I](#-浜斿瓙妫嬩汉鏈哄鎴榓i) - - [鐩綍](#鐩綍) - - [椤圭洰绠浠媇(#椤圭洰绠浠) - - [鉁 鍔熻兘鐗规(#-鍔熻兘鐗规) - - [馃殌 蹇熷紑濮媇(#-蹇熷紑濮) - - [缂栬瘧绋嬪簭](#缂栬瘧绋嬪簭) - - [杩愯娓告垙](#杩愯娓告垙) - - [馃幆 娓告垙鐜╂硶](#-娓告垙鐜╂硶) - - [馃捇 寮鍙戠幆澧僝(#-寮鍙戠幆澧) - - [鈿狅笍 甯歌闂](#锔-甯歌闂) - - [鏉冮檺闂](#鏉冮檺闂) - - [涓枃鏄剧ず闂](#涓枃鏄剧ず闂) - - [馃洜锔 鎶鏈疄鐜癩(#锔-鎶鏈疄鐜) - - [鏍稿績鍐崇瓥绠楁硶](#鏍稿績鍐崇瓥绠楁硶) - - [鍚彂寮忚瘎浼板嚱鏁癩(#鍚彂寮忚瘎浼板嚱鏁) - - [馃搨 浠g爜缁撴瀯](#-浠g爜缁撴瀯) - - [馃摐 璁稿彲璇乚(#-璁稿彲璇) - - [馃檵 鍙嶉涓庤础鐚甝(#-鍙嶉涓庤础鐚) - - [馃殌 鏈潵璁″垝](#-鏈潵璁″垝) +## 目录 +- [? 五子棋人机对战AI](#-五子棋人机对战ai) + - [目录](#目录) + - [项目简介](#项目简介) + - [? 功能特性](#-功能特性) + - [? 快速开始](#-快速开始) + - [编译程序](#编译程序) + - [运行游戏](#运行游戏) + - [? 游戏玩法](#-游戏玩法) + - [? 开发环境](#-开发环境) + - [?? 常见问题](#?-常见问题) + - [权限问题](#权限问题) + - [中文显示问题](#中文显示问题) + - [?? 技术实现](#?-技术实现) + - [核心决策算法](#核心决策算法) + - [启发式评估函数](#启发式评估函数) + - [? 代码结构](#-代码结构) + - [? 许可证](#-许可证) + - [? 反馈与贡献](#-反馈与贡献) + - [? 未来计划](#-未来计划) -## 椤圭洰绠浠 -鍩轰簬C璇█瀹炵幇鐨勪簲瀛愭浜烘満瀵规垬绯荤粺锛岄噰鐢ㄎ-尾鍓灊浼樺寲鐨勬瀬灏忔瀬澶х畻娉曪紝鏀寔鑷畾涔夋鐩樺ぇ灏忋佹父鎴忓鐩樺拰瀹炴椂璇勫垎銆 +## 项目简介 +基于C语言实现的五子棋人机对战系统,采用α-β剪枝优化的极小极大算法,支持自定义棋盘大小、游戏复盘和实时评分。 -## 鉁 鍔熻兘鐗规 -- 馃幃 浜烘満瀵规垬妯″紡 -- 鈿欙笍 鍙皟妫嬬洏灏哄(5x5鍒25x25) -- 馃 鏅鸿兘AI鍐崇瓥(1-5绾ч毦搴) -- 馃攳 瀹屾暣娓告垙澶嶇洏鍔熻兘 -- 馃搳 瀹炴椂瀵瑰眬璇勫垎绯荤粺 -- 鈫╋笍 鎮旀鍔熻兘(鍙挙閿涓婁竴姝) -- 馃枼锔 娓呮櫚鐨勭粓绔晫闈㈡樉绀 -- 鉁旓笍 鍋ュ.鐨勮緭鍏ラ獙璇(纭繚鎵鏈夋暟瀛楄緭鍏ラ兘鍦ㄦ湁鏁堣寖鍥村唴) -- 鈴憋笍 鍙夌殑鍥炲悎璁℃椂鍣 -- 馃捑 鑷姩娓告垙璁板綍淇濆瓨 +## ? 功能特性 +- ? 人机对战模式 +- ?? 可调棋盘尺寸(5x5到25x25) +- ? 智能AI决策(1-5级难度) +- ? 完整游戏复盘功能 +- ? 实时对局评分系统 +- ?? 悔棋功能(可撤销上一步) +- ?? 清晰的终端界面显示 +- ?? 健壮的输入验证(确保所有数字输入都在有效范围内) +- ?? 可选的回合计时器 +- ? 自动游戏记录保存 -## 馃殌 蹇熷紑濮 +## ? 快速开始 -![娓告垙婕旂ず](https://your-gif-url.com/demo.gif) +![游戏演示](https://your-gif-url.com/demo.gif) -### 缂栬瘧绋嬪簭 +### 编译程序 ```bash -gcc 浜斿瓙妫.c gobang.c game_mode.c -o output/浜斿瓙妫.exe +gcc 五子棋.c gobang.c game_mode.c -o output/五子棋.exe ``` -### 杩愯娓告垙 +### 运行游戏 ```bash -.\output\浜斿瓙妫.exe +.\output\五子棋.exe ``` -## 馃幆 娓告垙鐜╂硶 -1. 鍚姩鍚庤缃鐩樺ぇ灏(榛樿15x15) -2. 閫夋嫨AI闅惧害绾у埆(1-5) -3. 杈撳叆鍧愭爣杩涜娓告垙(鏍煎紡:琛 鍒) - - 杈撳叆R/r鍙倲妫 -4. 娓告垙缁撴潫鍙煡鐪嬪畬鏁村鐩樺拰璇勫垎 +## ? 游戏玩法 +1. 启动后设置棋盘大小(默认15x15) +2. 选择AI难度级别(1-5) +3. 输入坐标进行游戏(格式:行 列) + - 输入R/r可悔棋 +4. 游戏结束可查看完整复盘和评分 -## 馃捇 寮鍙戠幆澧 -- 鎿嶄綔绯荤粺: Windows (褰撳墠鐗堟湰浣跨敤浜哤indows鐗规湁鐨 `_kbhit()` 鍜 `Sleep()` 鍑芥暟锛屽洜姝や粎闄怶indows骞冲彴) -- 缂栬瘧鍣: GCC (MinGW(gcc涓14.2.0) on Windows) -- 缁堢: 鏀寔UTF-8缂栫爜鐨勭粓绔 +## ? 开发环境 +- 操作系统: Windows (当前版本使用了Windows特有的 `_kbhit()` 和 `Sleep()` 函数,因此仅限Windows平台) +- 编译器: GCC (MinGW(gcc为14.2.0) on Windows) +- 终端: 支持UTF-8编码的终端 -> **璺ㄥ钩鍙板吋瀹规ц鏄:** +> **跨平台兼容性说明:** > -> 涓轰簡鏈潵鑳藉湪Linux鎴杕acOS绛夊叾浠栨搷浣滅郴缁熶笂杩愯锛岄渶瑕佸皢骞冲彴鐗瑰畾鐨勪唬鐮侊紙濡 `_kbhit()`锛夋浛鎹负璺ㄥ钩鍙扮殑瀹炵幇锛屾垨浣跨敤鏉′欢缂栬瘧锛坄#ifdef _WIN32`锛夎繘琛岄殧绂汇 +> 为了未来能在Linux或macOS等其他操作系统上运行,需要将平台特定的代码(如 `_kbhit()`)替换为跨平台的实现,或使用条件编译(`#ifdef _WIN32`)进行隔离。 -## 鈿狅笍 甯歌闂 +## ?? 常见问题 -### 鏉冮檺闂 -濡傛灉绋嬪簭鍦ㄤ繚瀛樻父鎴忚褰曟椂鎻愮ず鈥滄棤娉曞垱寤烘枃浠垛濇垨绫讳技閿欒锛岄氬父鏄敱浜庣己灏戝啓鍏ユ潈闄愩傝灏濊瘯浠ヤ笅瑙e喅鏂规锛 +### 权限问题 +如果程序在保存游戏记录时提示“无法创建文件”或类似错误,通常是由于缺少写入权限。请尝试以下解决方案: -1. **浠ョ鐞嗗憳韬唤杩愯**锛氬彸閿偣鍑 `浜斿瓙妫.exe` 鎴栧湪绠$悊鍛樻潈闄愮殑缁堢涓繍琛岀▼搴忋 -2. **妫鏌ョ洰褰曟潈闄**锛氱‘淇濈▼搴忔墍鍦ㄧ洰褰曚笉鏄郴缁熶繚鎶ょ洰褰曪紙濡 `C:\Program Files`锛夈傚缓璁皢椤圭洰鏀惧湪鐢ㄦ埛鐩綍涓嬶紙濡 `D:\Code`锛夈 -3. **鎵嬪姩鍒涘缓 `records` 鐩綍**锛氬鏋 `records` 鐩綍涓嶅瓨鍦紝璇峰湪 `output` 鐩綍涓嬫墜鍔ㄥ垱寤轰竴涓 +1. **以管理员身份运行**:右键点击 `五子棋.exe` 或在管理员权限的终端中运行程序。 +2. **检查目录权限**:确保程序所在目录不是系统保护目录(如 `C:\Program Files`)。建议将项目放在用户目录下(如 `D:\Code`)。 +3. **手动创建 `records` 目录**:如果 `records` 目录不存在,请在 `output` 目录下手动创建一个。 -### 涓枃鏄剧ず闂 -濡傛灉鍦╓indows缁堢涓亣鍒颁腑鏂囧瓧绗︽樉绀轰负涔辩爜锛屾槸鐢变簬缁堢缂栫爜椤典笉鍖归厤瀵艰嚧鐨勩傝鍦ㄨ繍琛岀▼搴忓墠鎵ц浠ヤ笅鍛戒护锛 +### 中文显示问题 +如果在Windows终端中遇到中文字符显示为乱码,是由于终端编码页不匹配导致的。请在运行程序前执行以下命令: ```bash chcp 65001 ``` -璇ュ懡浠や細灏嗗綋鍓嶇粓绔殑缂栫爜椤靛垏鎹㈠埌UTF-8锛屼粠鑰屾纭樉绀轰腑鏂囧瓧绗︺備负鏂逛究璧疯锛屼綘鍙互鍒涘缓涓涓惎鍔ㄨ剼鏈紙`.bat` 鏂囦欢锛夋潵鑷姩鎵ц姝ゆ搷浣滐細 +该命令会将当前终端的编码页切换到UTF-8,从而正确显示中文字符。为方便起见,你可以创建一个启动脚本(`.bat` 文件)来自动执行此操作: **start_game.bat** ```batch @echo off chcp 65001 -.\output\浜斿瓙妫.exe +.\output\五子棋.exe ``` -## 馃洜锔 鎶鏈疄鐜 +## ?? 技术实现 -椤圭洰鐨凙I涓昏鍩轰簬浠ヤ笅鎶鏈疄鐜帮細 +项目的AI主要基于以下技术实现: -### 鏍稿績鍐崇瓥绠楁硶 +### 核心决策算法 -- **鏋佸皬鏋佸ぇ绠楁硶 (Minimax)**锛氫綔涓哄喅绛栫殑鍩虹锛屾ā鎷熷寮堝弻鏂圭殑姣忎竴姝ワ紝閫夋嫨瀵规垜鏂规渶鏈夊埄鐨勮蛋娉曘 -- **伪-尾 鍓灊 (Alpha-Beta Pruning)**锛氬鏋佸皬鏋佸ぇ绠楁硶鐨勯棞閸靛劒鍖栵紝閫氳繃鍓帀涓嶅彲鑳藉奖鍝嶆渶缁堝喅绛栫殑鎼滅储鍒嗘敮锛屽ぇ骞呮彁鍗嘇I鐨勮绠楁晥鐜囷紝浣垮叾鑳藉鍦ㄦ湁闄愭椂闂村唴杈惧埌鏇存繁鐨勬悳绱㈡繁搴︺ -- **鎼滅储娣卞害**锛欰I鐨勬濊冩繁搴︼紝榛樿涓3灞傦紝骞跺彲鏍规嵁闅惧害璁剧疆杩涜璋冩暣銆傛悳绱㈡繁搴﹁秺娣憋紝AI鐨勬鍔涜秺寮猴紝浣嗚绠楄楁椂涔熻秺闀裤 +- **极小极大算法 (Minimax)**:作为决策的基础,模拟对弈双方的每一步,选择对我方最有利的走法。 +- **α-β 剪枝 (Alpha-Beta Pruning)**:对极小极大算法的關鍵優化,通过剪掉不可能影响最终决策的搜索分支,大幅提升AI的计算效率,使其能够在有限时间内达到更深的搜索深度。 +- **搜索深度**:AI的思考深度,默认为3层,并可根据难度设置进行调整。搜索深度越深,AI的棋力越强,但计算耗时也越长。 -### 鍚彂寮忚瘎浼板嚱鏁 +### 启发式评估函数 -涓轰簡鍒ゆ柇妫嬪眬鐨勪紭鍔o紝AI浣跨敤浜嗕竴濂楀鏉傜殑鍚彂寮忚瘎浼板嚱鏁帮紝涓昏鍖呮嫭锛 +为了判断棋局的优劣,AI使用了一套复杂的启发式评估函数,主要包括: -- **妫嬪瀷璇嗗埆 (Pattern Recognition)**锛氳兘澶熻瘑鍒苟璇勪及澶氱鍏抽敭妫嬪瀷锛屽鈥滄椿鍥涒濄佲滃啿鍥涒濄佲滄椿涓夆濄佲滅湢涓夆濈瓑锛屽苟涓烘瘡绉嶆鍨嬭祴浜堜笉鍚屾潈閲嶃 -- **浣嶇疆鏉冮噸 (Positional Value)**锛氭鐩樹笂涓嶅悓浣嶇疆鐨勬垬鐣ヤ环鍊间笉鍚岋紝涓績浣嶇疆閫氬父姣旇竟缂樹綅缃洿鏈変紭鍔裤傝瘎浼板嚱鏁颁細涓轰腑蹇冨尯鍩熺殑钀藉瓙缁欎簣棰濆鍔犲垎銆 -- **濞佽儊妫娴 (Threat Detection)**锛氫紭鍏堟悳绱㈣兘澶熺洿鎺ュ舰鎴愬埗鑳滃▉鑳佺殑妫嬫锛屽鈥滆繛浜斺濇垨鈥滄椿鍥涒濓紝浠庤屽揩閫熷搷搴斿鎵嬬殑杩涙敾鎴栨姄浣忓埗鑳滄満浼氥 -- **鍙屽悜寤朵几璇勪及**锛氳瘎浼颁竴涓瀛愬湪鐗瑰畾鏂瑰悜涓婃槸鍚︽湁瓒冲鐨勭┖闂村舰鎴愯繛缁鍨嬶紝閬垮厤鍦ㄨ灏佸牭鐨勪綅缃氮璐规姝ャ +- **棋型识别 (Pattern Recognition)**:能够识别并评估多种关键棋型,如“活四”、“冲四”、“活三”、“眠三”等,并为每种棋型赋予不同权重。 +- **位置权重 (Positional Value)**:棋盘上不同位置的战略价值不同,中心位置通常比边缘位置更有优势。评估函数会为中心区域的落子给予额外加分。 +- **威胁检测 (Threat Detection)**:优先搜索能够直接形成制胜威胁的棋步,如“连五”或“活四”,从而快速响应对手的进攻或抓住制胜机会。 +- **双向延伸评估**:评估一个棋子在特定方向上是否有足够的空间形成连续棋型,避免在被封堵的位置浪费棋步。 -## 馃搨 浠g爜缁撴瀯 -- `浜斿瓙妫.c` - 涓荤▼搴忓叆鍙o紝璐熻矗鍒濆鍖栧拰妯″紡閫夋嫨 -- `gobang.c` - 鏍稿績娓告垙閫昏緫锛屽寘鎷鐩樻搷浣溿佽儨璐熷垽鏂丄I绠楁硶绛 -- `gobang.h` - `gobang.c` 鐨勫ご鏂囦欢锛屽畾涔夋牳蹇冩暟鎹粨鏋勫拰鍑芥暟鍘熷瀷 -- `game_mode.c` - 鍚勭娓告垙妯″紡鐨勫疄鐜帮紝濡備汉鏈哄鎴樸佸弻浜哄鎴樺拰澶嶇洏妯″紡 -- `game_mode.h` - `game_mode.c` 鐨勫ご鏂囦欢锛屽畾涔夋父鎴忔ā寮忕浉鍏冲嚱鏁板師鍨 +## ? 代码结构 +- `五子棋.c` - 主程序入口,负责初始化和模式选择 +- `gobang.c` - 核心游戏逻辑,包括棋盘操作、胜负判断、AI算法等 +- `gobang.h` - `gobang.c` 的头文件,定义核心数据结构和函数原型 +- `game_mode.c` - 各种游戏模式的实现,如人机对战、双人对战和复盘模式 +- `game_mode.h` - `game_mode.c` 的头文件,定义游戏模式相关函数原型 -## 馃摐 璁稿彲璇 +## ? 许可证 -璇ラ」鐩噰鐢 [MIT 璁稿彲璇乚(https://opensource.org/licenses/MIT)杩涜鎺堟潈銆 +该项目采用 [MIT 许可证](https://opensource.org/licenses/MIT)进行授权。 -绠鍗曟潵璇达紝浣犲彲浠ヨ嚜鐢卞湴浣跨敤銆佸鍒躲佷慨鏀广佸悎骞躲佸嚭鐗堛佸垎鍙戙佸啀鎺堟潈鍜/鎴栭攢鍞湰杞欢鐨勫壇鏈紝鍙渶鍦ㄤ綘鐨勯」鐩腑鍖呭惈鍘熷鐨勭増鏉冨拰璁稿彲澹版槑鍗冲彲銆 +简单来说,你可以自由地使用、复制、修改、合并、出版、分发、再授权和/或销售本软件的副本,只需在你的项目中包含原始的版权和许可声明即可。 -## 馃檵 鍙嶉涓庤础鐚 +## ? 反馈与贡献 -鎴戜滑闈炲父娆㈣繋浠讳綍褰㈠紡鐨勫弽棣堝拰璐$尞锛佸鏋滀綘鍙戠幇浜咮ug銆佹湁鍔熻兘寤鸿锛屾垨鑰呭笇鏈涙敼杩涗唬鐮侊紝璇烽殢鏃堕氳繃浠ヤ笅鏂瑰紡鍙備笌锛 +我们非常欢迎任何形式的反馈和贡献!如果你发现了Bug、有功能建议,或者希望改进代码,请随时通过以下方式参与: -- **鎻愪氦 Issue**锛氬鏋滀綘閬囧埌闂鎴栨湁鏂扮殑鎯虫硶锛岃鍦 [GitHub Issues](https://github.com/LHY0125/Gobang-Game/issues) 椤甸潰鎻愪氦璇︾粏鎻忚堪銆 -- **鍙戣捣 Pull Request**锛氬鏋滀綘瀵逛唬鐮佽繘琛屼簡鏀硅繘锛屾杩庢彁浜 Pull Request銆傝纭繚浣犵殑浠g爜椋庢牸涓庨」鐩繚鎸佷竴鑷达紝骞堕檮涓婃竻鏅扮殑鏀瑰姩璇存槑銆 +- **提交 Issue**:如果你遇到问题或有新的想法,请在 [GitHub Issues](https://github.com/LHY0125/Gobang-Game/issues) 页面提交详细描述。 +- **发起 Pull Request**:如果你对代码进行了改进,欢迎提交 Pull Request。请确保你的代码风格与项目保持一致,并附上清晰的改动说明。 -浣犵殑姣忎竴娆¤础鐚兘灏嗕娇杩欎釜椤圭洰鍙樺緱鏇村ソ锛 +你的每一次贡献都将使这个项目变得更好! -## 馃殌 鏈潵璁″垝 +## ? 未来计划 -涓轰簡璁╄繖涓」鐩彉寰楁洿瀹屽杽锛屾垜浠鍒掑湪鏈潵瀹炵幇浠ヤ笅鍔熻兘锛 +为了让这个项目变得更完善,我们计划在未来实现以下功能: -- [ ] **鍥惧舰鐢ㄦ埛鐣岄潰 (GUI)**锛氫娇鐢 `SDL2` 鎴 `Qt` 绛夊簱锛屽皢褰撳墠鐨勭粓绔晫闈㈠崌绾т负鍥惧舰鍖栫晫闈紝鎻愬崌鐢ㄦ埛浣撻獙銆 -- [ ] **缃戠粶瀵规垬鍔熻兘**锛氬鍔犱竴涓湪绾垮鎴樻ā寮忥紝鍏佽涓ゅ悕鐜╁閫氳繃缃戠粶杩涜瀵规垬銆 -- [ ] **妫嬭氨搴撻泦鎴**锛氬紩鍏ュ紑灞搴擄紝浣緼I鍦ㄦ父鎴忓垵鏈熻兘澶熼夋嫨鏇翠紭鐨勫紑灞璧版硶銆 -- [ ] **浠g爜閲嶆瀯涓庝紭鍖**锛氭寔缁紭鍖栫幇鏈変唬鐮侊紝鎻愰珮妯″潡鍖栫▼搴﹀拰杩愯鏁堢巼锛屽苟瀹炵幇瀹屽叏鐨勮法骞冲彴鍏煎鎬с \ No newline at end of file +- [ ] **图形用户界面 (GUI)**:使用 `SDL2` 或 `Qt` 等库,将当前的终端界面升级为图形化界面,提升用户体验。 +- [ ] **网络对战功能**:增加一个在线对战模式,允许两名玩家通过网络进行对战。 +- [ ] **棋谱库集成**:引入开局库,使AI在游戏初期能够选择更优的开局走法。 +- [ ] **代码重构与优化**:持续优化现有代码,提高模块化程度和运行效率,并实现完全的跨平台兼容性。 \ No newline at end of file diff --git a/ai.c b/ai.c new file mode 100644 index 0000000..062472c --- /dev/null +++ b/ai.c @@ -0,0 +1,325 @@ +#include "ai.h" +#include +#include +#include + +extern int BOARD_SIZE; +extern int board[MAX_BOARD_SIZE][MAX_BOARD_SIZE]; +extern int step_count; +extern const int direction[4][2]; +extern Step steps[MAX_STEPS]; + +/** + * @brief 璇勪及鐗瑰畾浣嶇疆瀵瑰綋鍓嶇帺瀹剁殑鎴樼暐浠峰笺 + * 姝ゅ嚱鏁伴氳繃妯℃嫙鍦ㄨ浣嶇疆钀藉瓙锛岀劧鍚庡垎鏋愬舰鎴愮殑妫嬪瀷鏉ヤ负璇ヤ綅缃墦鍒嗐 + * 鍒嗘暟瓒婇珮锛屼唬琛ㄨ浣嶇疆瀵规寚瀹氱帺瀹惰秺鏈夊埄銆 + * @param x 瑕佽瘎浼扮殑琛屽潗鏍 (0-based)銆 + * @param y 瑕佽瘎浼扮殑鍒楀潗鏍 (0-based)銆 + * @param player 鐜╁鏍囪瘑 (PLAYER 鎴 AI)锛屼唬琛ㄤ负鍝竴鏂硅繘琛岃瘎浼般 + * @return int 杩斿洖璇ヤ綅缃殑缁煎悎璇勪及鍒嗘暟銆 + * @note 璇勫垎绯荤粺璁捐锛 + * - 鏍稿績鎬濇兂鏄负涓嶅悓鐨勬鍨嬭祴浜堜笉鍚岀殑鏉冮噸锛屾鍨嬭秺鎺ヨ繎鑳滃埄锛屾潈閲嶈秺楂樸 + * - 鈥滄椿鈥濇鍨嬶紙涓ょ鏃犻樆鎸★級姣斺滅湢鈥濇鍨嬶紙涓绔湁闃绘尅锛夋垨鈥滄鈥濇鍨嬶紙涓ょ琚樆鎸★級寰楀垎楂樺緱澶氾紝 + * 鍥犱负瀹冧滑鏈夋洿澶х殑鍙戝睍娼滃姏銆 + * - 璇勫垎鏍囧噯 (浠呬负绀轰緥锛屽彲璋冩暣浠ヤ紭鍖朅I琛屼负): + * - 杩炰簲: 1,000,000 (鑳滃埄) + * - 娲诲洓: 100,000 (涓嬩竴姝ヨ儨鍒) + * - 鍐插洓: 10,000 (涓嬩竴姝ュ彲鑳借儨鍒) + * - 娲讳笁: 5,000 (娼滃姏宸ㄥぇ) + * - 鐪犱笁: 1,000 + * - 娲讳簩: 500 + * - 鐪犱簩: 100 + * - 鍏朵粬: 鏇翠綆鐨勫垎鏁 + * - 浣嶇疆濂栧姳锛氭鐩樹腑蹇冨尯鍩熼氬父鍏锋湁鏇撮珮鐨勬垬鐣ヤ环鍊硷紝鍥犳浼氱粰浜堥澶栧姞鍒嗭紝榧撳姳AI鍗犳嵁涓績銆 + */ +int evaluate_pos(int x, int y, int player) +{ + // 淇濆瓨鍘熷鍊肩敤浜庤繕鍘 + int original = board[x][y]; + // 妯℃嫙鍦ㄨ浣嶇疆钀藉瓙 + board[x][y] = player; + + int total_score = 0; // 鎬诲垎 + int line_scores[4] = {0}; // 鍥涗釜鏂瑰悜鐨勫緱鍒 + + // 閬嶅巻鍥涗釜鏂瑰悜杩涜璇勪及 + for (int i = 0; i < 4; i++) + { + int dx = direction[i][0], dy = direction[i][1]; + // 鑾峰彇褰撳墠鏂瑰悜涓婄殑妫嬪瀷淇℃伅 + DirInfo info = count_specific_direction(x, y, dx, dy, player); + + // 鐩存帴褰㈡垚浜旇繛鐝犱负蹇呰儨 + if (info.continuous_chess >= 5) + { + board[x][y] = original; // 杩樺師妫嬬洏 + return 1000000; // 杩斿洖鏈澶у垎 + } + + // 鏍规嵁杩炵画妫嬪瓙鏁拌瘎鍒 + switch (info.continuous_chess) + { + case 4: // 鍥涜繛鐝 + if (info.check_start && info.check_end) // 娲诲洓(涓ょ寮鏀) + line_scores[i] = 100000; + else if (info.check_start || info.check_end) // 鍐插洓(涓绔紑鏀) + line_scores[i] = 10000; + else // 姝诲洓(涓ょ灏侀棴) + line_scores[i] = 500; + break; + + case 3: // 涓夎繛鐝 + if (info.check_start && info.check_end) // 娲讳笁 + line_scores[i] = 5000; + else if (info.check_start || info.check_end) // 鐪犱笁 + line_scores[i] = 1000; + else // 姝讳笁 + line_scores[i] = 50; + break; + + case 2: // 浜岃繛鐝 + if (info.check_start && info.check_end) // 娲讳簩 + line_scores[i] = 500; + else if (info.check_start || info.check_end) // 鐪犱簩 + line_scores[i] = 100; + else // 姝讳簩 + line_scores[i] = 10; + break; + + case 1: // 鍗曞瓙 + if (info.check_start && info.check_end) // 寮鏀句綅缃 + line_scores[i] = 50; + else if (info.check_start || info.check_end) // 鍗婂紑鏀句綅缃 + line_scores[i] = 10; + else // 灏侀棴浣嶇疆 + line_scores[i] = 1; + break; + } + } + + // 璁$畻鎬诲垎锛堟渶楂樻柟鍚戝垎+鍏朵粬鏂瑰悜鍒嗗姞鏉冿級 + int max_score = 0; + int sum_score = 0; + for (int i = 0; i < 4; i++) + { + if (line_scores[i] > max_score) + max_score = line_scores[i]; + sum_score += line_scores[i]; + } + total_score = max_score * 10 + sum_score; // 涓绘柟鍚戞潈閲嶆洿楂 + + // 浣嶇疆濂栧姳锛氳秺闈犺繎涓績鍒嗘暟瓒婇珮 + int center_x = BOARD_SIZE / 2; + int center_y = BOARD_SIZE / 2; + int distance = abs(x - center_x) + abs(y - center_y); // 鏇煎搱椤胯窛绂 + int position_bonus = 50 * (BOARD_SIZE - distance); // 璺濈涓績瓒婅繎濂栧姳瓒婇珮 + + board[x][y] = original; // 杩樺師妫嬬洏鐘舵 + return total_score + position_bonus; // 杩斿洖鎬昏瘎浼板垎 +} + +/** + * @brief 浣跨敤甯ξ-尾鍓灊鐨勬繁搴︿紭鍏堟悳绱紙Minimax绠楁硶锛夋潵瀵绘壘鏈浣宠惤瀛愮偣銆 + * 璇ュ嚱鏁伴掑綊鍦版帰绱㈡湭鏉ョ殑鍑犳妫嬶紝璇勪及涓嶅悓閫夋嫨鐨勪紭鍔o紝骞堕夋嫨鏈浼樼瓥鐣ャ + * @param x 涓婁竴姝ヨ惤瀛愮殑琛屽潗鏍囥 + * @param y 涓婁竴姝ヨ惤瀛愮殑鍒楀潗鏍囥 + * @param player 褰撳墠杞埌鐨勭帺瀹 (PLAYER 鎴 AI)銆 + * @param depth 鍓╀綑鐨勬悳绱㈡繁搴︺傛繁搴﹁秺澶э紝AI鐪嬪緱瓒婅繙锛屼絾璁$畻閲忎篃瓒婂ぇ銆 + * @param alpha 伪鍊硷紝鏋佸ぇ鍖栫帺瀹讹紙AI锛夊綋鍓嶈兘纭繚鐨勬渶濂界粨鏋滐紙涓嬬晫锛夈 + * @param beta 尾鍊硷紝鏋佸皬鍖栫帺瀹讹紙瀵规墜锛夊綋鍓嶈兘纭繚鐨勬渶濂界粨鏋滐紙涓婄晫锛夈 + * @param is_maximizing 甯冨皵鍊硷紝true琛ㄧず褰撳墠鏄瀬澶у寲鐜╁锛圓I锛夌殑鍥炲悎锛宖alse琛ㄧず鏄瀬灏忓寲鐜╁锛堝鎵嬶級鐨勫洖鍚堛 + * @return int 杩斿洖鍦ㄥ綋鍓嶅垎鏀笅鐨勬渶浣宠瘎浼板垎鏁般 + * @note 绠楁硶鏍稿績鎬濇兂: + * 1. **閫掑綊缁堟鏉′欢**: 褰撴父鎴忓嚭鐜拌儨璐熴佸钩灞锛屾垨杈惧埌棰勮鐨勬悳绱㈡繁搴︽椂锛屽仠姝㈤掑綊锛屽苟杩斿洖褰撳墠灞闈㈢殑闈欐佽瘎浼板垎鏁般 + * 2. **鏋佸ぇ鍖栫帺瀹 (AI)**: 灏濊瘯鎵鏈夊彲鑳界殑钀藉瓙锛屽苟閫夋嫨鑳戒娇鍏跺緱鍒嗘渶澶у寲鐨勯偅涓姝ャ傛杩囩▼涓紝浼氫笉鏂洿鏂癮lpha鍊笺 + * 3. **鏋佸皬鍖栫帺瀹 (瀵规墜)**: 妯℃嫙瀵规墜鐨勮蛋娉曪紝骞跺亣璁惧鎵嬩細閫夋嫨鑳戒娇AI寰楀垎鏈灏忓寲鐨勯偅涓姝ャ傛杩囩▼涓紝浼氫笉鏂洿鏂癰eta鍊笺 + * 4. **伪-尾鍓灊**: 杩欐槸瀵筂inimax绠楁硶鐨勫叧閿紭鍖栥 + * - **伪鍓灊**: 鍦ㄦ瀬灏忓寲鐜╁鐨勫洖鍚堜腑锛屽鏋滃彂鐜颁竴涓蛋娉曞緱鍒扮殑鍒嗘暟姣攁lpha杩樹綆锛岄偅涔堣繖涓垎鏀彲浠ヨ鍓帀锛 + * 鍥犱负鏋佸ぇ鍖栫帺瀹剁粷涓嶄細閫夋嫨杩涘叆杩欎釜鍒嗘敮锛堜粬鏈夋洿濂界殑閫夋嫨锛夈(if beta <= alpha) + * - **尾鍓灊**: 鍦ㄦ瀬澶у寲鐜╁鐨勫洖ah鍚堜腑锛屽鏋滃彂鐜颁竴涓蛋娉曞緱鍒扮殑鍒嗘暟姣攂eta杩橀珮锛岄偅涔堣繖涓垎鏀篃鍙互琚壀鎺夛紝 + * 鍥犱负鏋佸皬鍖栫帺瀹剁粷涓嶄細璁╂父鎴忚繘鍏ヨ繖涓垎鏀紙浠栨湁鏇村ソ鐨勯夋嫨鏉ラ樆姝級銆(if beta <= alpha) + * 閫氳繃鍓灊锛屽彲浠ラ伩鍏嶅澶ч噺鏃犳晥鍒嗘敮鐨勬悳绱紝鏋佸ぇ鍦版彁楂樹簡AI鐨勫喅绛栨晥鐜囥 + */ +int dfs(int x, int y, int player, int depth, int alpha, int beta, bool is_maximizing) +{ + // 妫鏌ュ綋鍓嶈惤瀛愭槸鍚﹁幏鑳 + if (check_win(x, y, player)) + { + return (player == AI) ? 1000000 + depth : -1000000 - depth; + } + + // 杈惧埌鎼滅储娣卞害鎴栧钩灞 + if (depth == 0 || step_count >= BOARD_SIZE * BOARD_SIZE) + { + return evaluate_pos(x, y, AI) - evaluate_pos(x, y, PLAYER); + } + + int best_score = is_maximizing ? -1000000 : 1000000; + + // 閬嶅巻鎵鏈夊彲鑳借惤瀛愪綅缃 + for (int i = 0; i < BOARD_SIZE; i++) + { + for (int j = 0; j < BOARD_SIZE; j++) + { + if (board[i][j] != EMPTY) + continue; + + // 妯℃嫙褰撳墠鐜╁钀藉瓙 + board[i][j] = player; + step_count++; + + // 閫掑綊鎼滅储(鍒囨崲鐜╁鍜屾悳绱㈡繁搴) + int current_score = dfs(i, j, (player == AI) ? PLAYER : AI, depth - 1, alpha, beta, !is_maximizing); + + // 鎾ら攢钀藉瓙 + board[i][j] = EMPTY; + step_count--; + + // 鏋佸ぇ鍊肩帺瀹(AI)閫昏緫 + if (is_maximizing) + { + best_score = (current_score > best_score) ? current_score : best_score; + alpha = (best_score > alpha) ? best_score : alpha; + // 伪鍓灊 + if (beta <= alpha) + { + break; + } + } + // 鏋佸皬鍊肩帺瀹(浜虹被)閫昏緫 + else + { + best_score = (current_score < best_score) ? current_score : best_score; + beta = (best_score < beta) ? best_score : beta; + // 尾鍓灊 + if (beta <= alpha) + { + break; + } + } + } + if ((is_maximizing && best_score >= beta) || (!is_maximizing && best_score <= alpha)) + { + break; // 鎻愬墠閫鍑哄灞傚惊鐜 + } + } + + return best_score; +} + +/** + * @brief AI鍐崇瓥涓诲嚱鏁帮紝浣跨敤璇勪及鍑芥暟鍜屾悳绱㈢畻娉曢夋嫨鏈浣宠惤瀛愪綅缃 + * @note 閲囩敤涓ら樁娈靛喅绛栭昏緫锛 + * 1. 闃插尽闃舵锛氭鏌ュ苟闃绘鐜╁鍗冲皢鑾疯儨鐨勪綅缃紙娲诲洓銆佸啿鍥涖佹椿涓夛級 + * 2. 杩涙敾闃舵锛氳嫢鏃犵揣鎬ラ槻寰¢渶姹傦紝浣跨敤DFS璇勪及閫夋嫨鏈浣宠繘鏀讳綅缃 + * @note 瀹炵幇缁嗚妭锛 + * - 浼樺厛澶勭悊鐜╁娲诲洓銆佸啿鍥涚瓑鍗遍櫓灞闈 + * - 姝ユ暟>10鏃剁缉灏忔悳绱㈣寖鍥村埌宸叉湁妫嬪瓙闄勮繎2鏍 + * - 浣跨敤涓績浣嶇疆浼樺厛绛栫暐 + */ +void ai_move(int depth) +{ + // 1. 棣栧厛妫鏌ユ槸鍚﹂渶瑕侀樆姝㈢帺瀹剁殑鍥涘瓙杩炴鎴栦笁瀛愭椿妫 + for (int i = 0; i < BOARD_SIZE; i++) + { + for (int j = 0; j < BOARD_SIZE; j++) + { + if (board[i][j] != EMPTY) + continue; + + // 妯℃嫙鐜╁鍦ㄦ浣嶇疆钀藉瓙 + board[i][j] = PLAYER; + bool need_block = false; + + // 妫鏌ュ洓涓柟鍚 + for (int k = 0; k < 4; k++) + { + DirInfo info = count_specific_direction(i, j, direction[k][0], direction[k][1], PLAYER); + + // 濡傛灉鐜╁鑳藉舰鎴愬洓瀛愯繛妫嬩笖鑷冲皯涓绔紑鏀 + if (info.continuous_chess >= 4 && (info.check_start || info.check_end)) + { + need_block = true; + break; + } + + // 濡傛灉鐜╁鑳藉舰鎴愪笁瀛愭椿妫嬩笖涓ょ寮鏀 + if (info.continuous_chess == 3 && info.check_start && info.check_end) + { + need_block = true; + break; + } + } + + board[i][j] = EMPTY; // 鎭㈠妫嬬洏 + + if (need_block) + { + // 蹇呴』鍦ㄦ浣嶇疆钀藉瓙闃绘 + board[i][j] = AI; + steps[step_count++] = (Step){AI, i, j}; + printf("AI钀藉瓙(%d, %d)\n", i + 1, j + 1); + return; + } + } + } + + // 2. 濡傛灉娌℃湁闇瑕佺珛鍗抽樆姝㈢殑鎯呭喌锛屽垯姝e父璇勪及 + int best_score = -1000000; + int best_x = -1, best_y = -1; + + // 閬嶅巻妫嬬洏鎵鏈夌┖浣 + for (int i = 0; i < BOARD_SIZE; i++) + { + for (int j = 0; j < BOARD_SIZE; j++) + { + if (board[i][j] != EMPTY) + continue; + + // 鍙冭檻宸叉湁妫嬪瓙闄勮繎(2鏍艰寖鍥村唴) + bool has_nearby_stone = false; + for (int di = -2; di <= 2; di++) + { + for (int dj = -2; dj <= 2; dj++) + { + int ni = i + di; + int nj = j + dj; + if (ni >= 0 && ni < BOARD_SIZE && + nj >= 0 && nj < BOARD_SIZE) + { + if (board[ni][nj] != EMPTY) + { + has_nearby_stone = true; + break; + } + } + } + if (has_nearby_stone) + break; + } + if (!has_nearby_stone && step_count > 10) + continue; + + // 妯℃嫙AI钀藉瓙 + board[i][j] = AI; + int current_score = dfs(i, j, PLAYER, depth, -1000000, 1000000, false); + board[i][j] = EMPTY; + + // 鏇存柊鏈浣充綅缃 + if (current_score > best_score) + { + best_score = current_score; + best_x = i; + best_y = j; + } + } + } + + // 鎵ц鏈浣宠惤瀛 + if (best_x != -1 && best_y != -1) + { + board[best_x][best_y] = AI; + steps[step_count++] = (Step){AI, best_x, best_y}; + printf("AI钀藉瓙(%d, %d)\n", best_x + 1, best_y + 1); + } +} \ No newline at end of file diff --git a/ai.h b/ai.h new file mode 100644 index 0000000..318a9cb --- /dev/null +++ b/ai.h @@ -0,0 +1,34 @@ +#ifndef AI_H +#define AI_H + +#include "gobang.h" + +/** + * @brief 璇勪及鐗瑰畾浣嶇疆瀵瑰綋鍓嶇帺瀹剁殑浠峰 + * @param x 琛屽潗鏍(0-base) + * @param y 鍒楀潗鏍(0-base) + * @param player 鐜╁鏍囪瘑(PLAYER/AI) + * @return int 浣嶇疆璇勪及鍒嗘暟(瓒婇珮瓒婂ソ) + */ +int evaluate_pos(int x, int y, int player); + +/** + * @brief 甯ξ-尾鍓灊鐨勬繁搴︿紭鍏堟悳绱(鏋佸皬鏋佸ぇ绠楁硶) + * @param x 褰撳墠琛屽潗鏍 + * @param y 褰撳墠鍒楀潗鏍 + * @param player 褰撳墠鐜╁ + * @param depth 鎼滅储娣卞害 + * @param alpha 伪鍊(褰撳墠鏈澶у) + * @param beta 尾鍊(褰撳墠鏈灏忓) + * @param is_maximizing 鏄惁涓烘瀬澶у寲鐜╁ + * @return int 鏈浣宠瘎浼板垎鏁 + */ +int dfs(int x, int y, int player, int depth, int alpha, int beta, bool is_maximizing); + +/** + * @brief AI钀藉瓙鍐崇瓥鍑芥暟 + * 浣跨敤璇勪及鍑芥暟鍜屾悳绱㈢畻娉曢夋嫨鏈浣宠惤瀛愪綅缃 + */ +void ai_move(int depth); + +#endif // AI_H \ No newline at end of file diff --git a/game_mode.c b/game_mode.c index b8950fc..ab1caac 100644 --- a/game_mode.c +++ b/game_mode.c @@ -1,4 +1,6 @@ +#include "game_mode.h" #include "gobang.h" +#include "ai.h" #include #include #include @@ -11,7 +13,7 @@ /** * @brief 浠庣敤鎴疯幏鍙栨暣鏁拌緭鍏 - * + * * @param prompt 鎻愮ず淇℃伅 * @param min 鏈灏忓 * @param max 鏈澶у @@ -47,48 +49,17 @@ int get_integer_input(const char *prompt, int min, int max) /** * @brief 澶勭悊鐜╁鍥炲悎 - * - * @param current_player - * @return true - * @return false + * + * @param current_player + * @return true + * @return false */ -bool handle_player_turn(int current_player) +bool parse_player_input(int *x, int *y) { - int x, y; char input[10]; - time_t start_time, end_time; - if (use_timer) - { - time(&start_time); - } - - if (current_player == 1) - { - printf("\n鐜╁, 璇疯緭鍏ヨ惤瀛愬潗鏍(琛 鍒楋紝1~%d)锛屾垨杈撳叆R/r鎮旀:", BOARD_SIZE); - } - else - { - printf("\n鐜╁%d, 璇疯緭鍏ヨ惤瀛愬潗鏍(琛 鍒楋紝1~%d)锛屾垨杈撳叆R/r鎮旀:", current_player, BOARD_SIZE); - } while (1) { - if (use_timer) - { - time(&end_time); - if (difftime(end_time, start_time) > time_limit) - { - if (current_player == 1) - { - printf("\n鐜╁瓒呮椂, 瀵规柟鑾疯儨锛乗n"); - } - else - { - printf("\n鐜╁%d瓒呮椂, 瀵规柟鑾疯儨锛乗n", current_player); - } - return false; // 瓒呮椂锛岃繑鍥瀎alse琛ㄧず鍥炲悎澶辫触 - } - } if (_kbhit()) { scanf("%s", input); @@ -97,36 +68,103 @@ bool handle_player_turn(int current_player) Sleep(100); // a small delay to prevent high CPU usage } - if (input[0] == 'r' || input[0] == 'R') + if (sscanf(input, "%d", x) == 1) { - int steps_to_undo; - printf("璇疯緭鍏ヨ鎮旀鐨勬鏁(AI浼氬悓鏍锋倲妫): "); - steps_to_undo = get_integer_input("", 1, step_count / 2); - int effective_steps = (current_player == PLAYER) ? steps_to_undo * 2 : steps_to_undo; - if (return_move(effective_steps)) + // Successfully parsed the first number, now parse the second + if (scanf("%d", y) != 1) { - printf("鎴愬姛鎮旀 %d 姝ワ紒\n", steps_to_undo); - print_board(); + // Check for special commands if second number is not available + if (*x == INPUT_UNDO) + { + int steps_to_undo; + printf("璇疯緭鍏ヨ鎮旀鐨勬鏁(鍙屾柟鍚勯涓姝): "); + 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; // Special command + } + else if (*x == INPUT_SAVE) + { + // ... handle save ... + return false; // Special command + } + else if (*x == INPUT_EXIT) + { + // ... handle exit ... + return false; // Special command + } + printf("鏃犳晥杈撳叆锛岃杈撳叆涓や釜鏁板瓧鍧愭爣銆"); + while (getchar() != '\n') + ; + return false; // Invalid input + } + } + else + { + // sscanf failed, check for 'r' or 'R' + if (input[0] == 'r' || input[0] == 'R') + { + int steps_to_undo; + printf("璇疯緭鍏ヨ鎮旀鐨勬鏁(鍙屾柟鍚勯涓姝): "); + 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; // Special command + } + printf("鏃犳晥杈撳叆锛岃杈撳叆鏁板瓧鍧愭爣鎴'r'鎮旀銆"); + return false; // Invalid input + } + return true; // Valid coordinates +} + +bool handle_player_turn(int current_player) +{ + int x, y; + time_t start_time, end_time; + if (use_timer) + { + time(&start_time); + } + + printf("\n鐜╁%d, 璇疯緭鍏ヨ惤瀛愬潗鏍(琛 鍒楋紝1~%d)锛屾垨杈撳叆R/r鎮旀:", current_player, BOARD_SIZE); + + while (1) + { + 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)) + { + break; // Valid input received } else { - printf("鏃犳硶鎮旀锛乗n"); + // Special command or invalid input handled, just continue the loop + return true; } - return true; // 鎮旀鎿嶄綔鍚庯紝鍥炲悎绠椾綔鎴愬姛锛屼絾涓嶈繘琛岃惤瀛 } - if (sscanf(input, "%d", &x) != 1) - { - printf("鏃犳晥杈撳叆锛岃杈撳叆鏁板瓧鍧愭爣銆"); - return true; // 杈撳叆鏃犳晥锛屼絾鍥炲悎缁х画 - } - if (scanf("%d", &y) != 1) - { - printf("鏃犳晥杈撳叆锛岃杈撳叆鏁板瓧鍧愭爣銆"); - while (getchar() != '\n') - ; - return true; // 杈撳叆鏃犳晥锛屼絾鍥炲悎缁х画 - } x--; y--; @@ -139,14 +177,7 @@ bool handle_player_turn(int current_player) if (check_win(x, y, current_player)) { - if (current_player == 1) - { - printf("\n鐜╁鑾疯儨锛乗n"); - } - else - { - printf("\n鐜╁%d鑾疯儨锛乗n", current_player); - } + printf("\n鐜╁%d鑾疯儨锛乗n", current_player); return false; // 娓告垙缁撴潫 } @@ -242,7 +273,7 @@ void run_pvp_game() // 鍙屼汉瀵规垬妯″紡 setup_board_size(); empty_board(); - int current_player = determine_first_player(PLAYER3, PLAYER4); + int current_player = determine_first_player(PLAYER1, PLAYER2); print_board(); while (1) @@ -261,7 +292,7 @@ void run_pvp_game() if (step_count > old_step_count) { - current_player = (current_player == PLAYER3) ? PLAYER4 : PLAYER3; + current_player = (current_player == PLAYER1) ? PLAYER2 : PLAYER1; } } printf("===== 娓告垙缁撴潫 =====\n"); @@ -307,7 +338,7 @@ void run_review_mode() { 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); @@ -321,7 +352,8 @@ void run_review_mode() printf("璇疯緭鍏ュ畬鏁存枃浠跺悕: "); scanf("%s", filename); int c; - while ((c = getchar()) != '\n' && c != EOF); + while ((c = getchar()) != '\n' && c != EOF) + ; int possible_choice = atoi(filename); if (possible_choice > 0 && possible_choice <= file_count) @@ -335,7 +367,8 @@ void run_review_mode() printf("鏈壘鍒颁换浣曞鐩樻枃浠讹紝璇疯緭鍏ュ鐩樻枃浠跺湴鍧: "); scanf("%s", filename); int c; - while ((c = getchar()) != '\n' && c != EOF); + while ((c = getchar()) != '\n' && c != EOF) + ; } int game_mode = load_game_from_file(filename); diff --git a/game_mode.h b/game_mode.h index 466e508..c83d665 100644 --- a/game_mode.h +++ b/game_mode.h @@ -3,7 +3,7 @@ * @author 鍒樿埅瀹(3364451258@qq.com銆15236416560@163.com銆乴hy3364451258@outlook.com) * @brief 浜斿瓙妫嬫父鎴忔鏋跺ご鏂囦欢 * @version 3.0 - * @date 2025-06-26 + * @date 2025-06-30 * * @copyright Copyright (c) 2025 * @@ -18,9 +18,14 @@ #include "gobang.h" +// 鐗规畩杈撳叆鍛戒护 +#define INPUT_UNDO -1 +#define INPUT_SAVE -2 +#define INPUT_EXIT -3 + /** * @brief 浠庣敤鎴疯幏鍙栨暣鏁拌緭鍏 - * + * * @param prompt 鎻愮ず淇℃伅 * @param min 鏈灏忓 * @param max 鏈澶у @@ -30,10 +35,18 @@ int get_integer_input(const char *prompt, int min, int max); /** * @brief 澶勭悊鐜╁鍥炲悎 - * - * @param current_player - * @return true - * @return false + * + * @param x 鐜╁杈撳叆鐨勬í鍧愭爣 + * @param y 鐜╁杈撳叆鐨勭旱鍧愭爣 + * @return true 杈撳叆鏈夋晥 + * @return false 杈撳叆鏃犳晥 + */ +bool parse_player_input(int *x, int *y); + +/** + * @brief 澶勭悊AI鍥炲悎 + * + * @param current_player 褰撳墠鐜╁ */ bool handle_player_turn(int current_player); diff --git a/gobang.c b/gobang.c index bdce2ba..999609d 100644 --- a/gobang.c +++ b/gobang.c @@ -1,14 +1,16 @@ #include "gobang.h" #include "game_mode.h" +#include "ai.h" #include #include #include // 鍏ㄥ眬鍙橀噺瀹氫箟 -int BOARD_SIZE = 15; // 瀹為檯浣跨敤鐨勬鐩樺昂瀵(榛樿15) -int board[MAX_BOARD_SIZE][MAX_BOARD_SIZE] = {0}; // 妫嬬洏鐘舵佸瓨鍌ㄦ暟缁(榛樿妫嬬洏鍏ㄧ┖涓0) -const int direction[4][2] = {{1, 0}, {0, 1}, {1, 1}, {1, -1}}; // 鍥涗釜鏂瑰悜锛氬悜涓嬨佸悜鍙炽佸彸涓嬨佸乏涓 +int BOARD_SIZE = 15; // 瀹為檯浣跨敤鐨勬鐩樺昂瀵(榛樿15) +int board[MAX_BOARD_SIZE][MAX_BOARD_SIZE] = {0}; // 妫嬬洏鐘舵佸瓨鍌ㄦ暟缁(榛樿妫嬬洏鍏ㄧ┖涓0) + Step steps[MAX_STEPS]; // 瀛樺偍鎵鏈夎惤瀛愭楠ょ殑鏁扮粍 +const int direction[4][2] = {{1, 0}, {0, 1}, {1, 1}, {1, -1}}; // 鍥涗釜鏂瑰悜锛氬悜涓嬨佸悜鍙炽佸彸涓嬨佸乏涓 int step_count = 0; // 褰撳墠姝ユ暟璁℃暟鍣 bool use_forbidden_moves = false; // 榛樿涓嶅惎鐢ㄧ鎵嬭鍒 int use_timer = 0; // 榛樿涓嶅惎鐢ㄨ鏃跺櫒 @@ -144,7 +146,7 @@ bool is_forbidden_move(int x, int y, int player) { return false; } - if (player != PLAYER && player != PLAYER3) + if (player != PLAYER && player != PLAYER1) { return false; } @@ -269,306 +271,6 @@ bool check_win(int x, int y, int player) return false; // 鍥涗釜鏂瑰悜閮芥病鏈変簲杩炵彔 } -/** - * @brief 璇勪及鐗瑰畾浣嶇疆瀵瑰綋鍓嶇帺瀹剁殑鎴樼暐浠峰 - * @param x 琛屽潗鏍(0-base) - * @param y 鍒楀潗鏍(0-base) - * @param player 鐜╁鏍囪瘑(PLAYER/AI) - * @return int 缁煎悎璇勪及鍒嗘暟(瓒婇珮琛ㄧず浣嶇疆瓒婂ソ) - * @note 璇勫垎鏍囧噯: - * - 娲诲洓:100000 鍐插洓:10000 姝诲洓:500 - * - 娲讳笁:5000 鐪犱笁:1000 姝讳笁:50 - * - 娲讳簩:500 鐪犱簩:100 姝讳簩:10 - * - 鍗曞瓙:50(寮鏀)/10(鍗婂紑鏀)/1(灏侀棴) - * - 涓績浣嶇疆鏈夐澶栧姞鎴 - */ -int evaluate_pos(int x, int y, int player) -{ - // 淇濆瓨鍘熷鍊肩敤浜庤繕鍘 - int original = board[x][y]; - // 妯℃嫙鍦ㄨ浣嶇疆钀藉瓙 - board[x][y] = player; - - int total_score = 0; // 鎬诲垎 - int line_scores[4] = {0}; // 鍥涗釜鏂瑰悜鐨勫緱鍒 - - // 閬嶅巻鍥涗釜鏂瑰悜杩涜璇勪及 - for (int i = 0; i < 4; i++) - { - int dx = direction[i][0], dy = direction[i][1]; - // 鑾峰彇褰撳墠鏂瑰悜涓婄殑妫嬪瀷淇℃伅 - DirInfo info = count_specific_direction(x, y, dx, dy, player); - - // 鐩存帴褰㈡垚浜旇繛鐝犱负蹇呰儨 - if (info.continuous_chess >= 5) - { - board[x][y] = original; // 杩樺師妫嬬洏 - return 1000000; // 杩斿洖鏈澶у垎 - } - - // 鏍规嵁杩炵画妫嬪瓙鏁拌瘎鍒 - switch (info.continuous_chess) - { - case 4: // 鍥涜繛鐝 - if (info.check_start && info.check_end) // 娲诲洓(涓ょ寮鏀) - line_scores[i] = 100000; - else if (info.check_start || info.check_end) // 鍐插洓(涓绔紑鏀) - line_scores[i] = 10000; - else // 姝诲洓(涓ょ灏侀棴) - line_scores[i] = 500; - break; - - case 3: // 涓夎繛鐝 - if (info.check_start && info.check_end) // 娲讳笁 - line_scores[i] = 5000; - else if (info.check_start || info.check_end) // 鐪犱笁 - line_scores[i] = 1000; - else // 姝讳笁 - line_scores[i] = 50; - break; - - case 2: // 浜岃繛鐝 - if (info.check_start && info.check_end) // 娲讳簩 - line_scores[i] = 500; - else if (info.check_start || info.check_end) // 鐪犱簩 - line_scores[i] = 100; - else // 姝讳簩 - line_scores[i] = 10; - break; - - case 1: // 鍗曞瓙 - if (info.check_start && info.check_end) // 寮鏀句綅缃 - line_scores[i] = 50; - else if (info.check_start || info.check_end) // 鍗婂紑鏀句綅缃 - line_scores[i] = 10; - else // 灏侀棴浣嶇疆 - line_scores[i] = 1; - break; - } - } - - // 璁$畻鎬诲垎锛堟渶楂樻柟鍚戝垎+鍏朵粬鏂瑰悜鍒嗗姞鏉冿級 - int max_score = 0; - int sum_score = 0; - for (int i = 0; i < 4; i++) - { - if (line_scores[i] > max_score) - max_score = line_scores[i]; - sum_score += line_scores[i]; - } - total_score = max_score * 10 + sum_score; // 涓绘柟鍚戞潈閲嶆洿楂 - - // 浣嶇疆濂栧姳锛氳秺闈犺繎涓績鍒嗘暟瓒婇珮 - int center_x = BOARD_SIZE / 2; - int center_y = BOARD_SIZE / 2; - int distance = abs(x - center_x) + abs(y - center_y); // 鏇煎搱椤胯窛绂 - int position_bonus = 50 * (BOARD_SIZE - distance); // 璺濈涓績瓒婅繎濂栧姳瓒婇珮 - - board[x][y] = original; // 杩樺師妫嬬洏鐘舵 - return total_score + position_bonus; // 杩斿洖鎬昏瘎浼板垎 -} - -/** - * @brief 甯ξ-尾鍓灊鐨勬繁搴︿紭鍏堟悳绱(鏋佸皬鏋佸ぇ绠楁硶瀹炵幇) - * @param x 褰撳墠琛屽潗鏍 - * @param y 褰撳墠鍒楀潗鏍 - * @param player 褰撳墠鐜╁ - * @param depth 鍓╀綑鎼滅储娣卞害 - * @param alpha 伪鍊(褰撳墠鏈澶у) - * @param beta 尾鍊(褰撳墠鏈灏忓) - * @param is_maximizing 鏄惁涓烘瀬澶у寲鐜╁(AI) - * @return int 鏈浣宠瘎浼板垎鏁 - * @note 绠楁硶娴佺▼: - * 1. 妫鏌ユ槸鍚﹁幏鑳滄垨杈惧埌鎼滅储娣卞害 - * 2. 閬嶅巻鎵鏈夊彲鑳借惤瀛愪綅缃 - * 3. 閫掑綊璇勪及姣忎釜浣嶇疆鐨勫垎鏁 - * 4. 鏍规嵁is_maximizing閫夋嫨鏈澶/鏈灏忓 - * 5. 浣跨敤伪-尾鍓灊浼樺寲鎼滅储杩囩▼ - */ -int dfs(int x, int y, int player, int depth, int alpha, int beta, bool is_maximizing) -{ - // 妫鏌ュ綋鍓嶈惤瀛愭槸鍚﹁幏鑳 - if (check_win(x, y, player)) - { - return (player == AI) ? 1000000 + depth : -1000000 - depth; - } - - // 杈惧埌鎼滅储娣卞害鎴栧钩灞 - if (depth == 0 || step_count >= BOARD_SIZE * BOARD_SIZE) - { - return evaluate_pos(x, y, AI) - evaluate_pos(x, y, PLAYER); - } - - int best_score = is_maximizing ? -1000000 : 1000000; - - // 閬嶅巻鎵鏈夊彲鑳借惤瀛愪綅缃 - for (int i = 0; i < BOARD_SIZE; i++) - { - for (int j = 0; j < BOARD_SIZE; j++) - { - if (board[i][j] != EMPTY) - continue; - - // 妯℃嫙褰撳墠鐜╁钀藉瓙 - board[i][j] = player; - step_count++; - - // 閫掑綊鎼滅储(鍒囨崲鐜╁鍜屾悳绱㈡繁搴) - int current_score = dfs(i, j, (player == AI) ? PLAYER : AI, depth - 1, alpha, beta, !is_maximizing); - - // 鎾ら攢钀藉瓙 - board[i][j] = EMPTY; - step_count--; - - // 鏋佸ぇ鍊肩帺瀹(AI)閫昏緫 - if (is_maximizing) - { - best_score = (current_score > best_score) ? current_score : best_score; - alpha = (best_score > alpha) ? best_score : alpha; - // 伪鍓灊 - if (beta <= alpha) - { - break; - } - } - // 鏋佸皬鍊肩帺瀹(浜虹被)閫昏緫 - else - { - best_score = (current_score < best_score) ? current_score : best_score; - beta = (best_score < beta) ? best_score : beta; - // 尾鍓灊 - if (beta <= alpha) - { - break; - } - } - } - if ((is_maximizing && best_score >= beta) || (!is_maximizing && best_score <= alpha)) - { - break; // 鎻愬墠閫鍑哄灞傚惊鐜 - } - } - - return best_score; -} - -/** - * @brief AI鍐崇瓥涓诲嚱鏁帮紝浣跨敤璇勪及鍑芥暟鍜屾悳绱㈢畻娉曢夋嫨鏈浣宠惤瀛愪綅缃 - * @note 閲囩敤涓ら樁娈靛喅绛栭昏緫锛 - * 1. 闃插尽闃舵锛氭鏌ュ苟闃绘鐜╁鍗冲皢鑾疯儨鐨勪綅缃紙娲诲洓銆佸啿鍥涖佹椿涓夛級 - * 2. 杩涙敾闃舵锛氳嫢鏃犵揣鎬ラ槻寰¢渶姹傦紝浣跨敤DFS璇勪及閫夋嫨鏈浣宠繘鏀讳綅缃 - * @note 瀹炵幇缁嗚妭锛 - * - 浼樺厛澶勭悊鐜╁娲诲洓銆佸啿鍥涚瓑鍗遍櫓灞闈 - * - 姝ユ暟>10鏃剁缉灏忔悳绱㈣寖鍥村埌宸叉湁妫嬪瓙闄勮繎2鏍 - * - 浣跨敤涓績浣嶇疆浼樺厛绛栫暐 - */ -void ai_move(int depth) -{ - // 1. 棣栧厛妫鏌ユ槸鍚﹂渶瑕侀樆姝㈢帺瀹剁殑鍥涘瓙杩炴鎴栦笁瀛愭椿妫 - for (int i = 0; i < BOARD_SIZE; i++) - { - for (int j = 0; j < BOARD_SIZE; j++) - { - if (board[i][j] != EMPTY) - continue; - - // 妯℃嫙鐜╁鍦ㄦ浣嶇疆钀藉瓙 - board[i][j] = PLAYER; - bool need_block = false; - - // 妫鏌ュ洓涓柟鍚 - for (int k = 0; k < 4; k++) - { - DirInfo info = count_specific_direction(i, j, direction[k][0], direction[k][1], PLAYER); - - // 濡傛灉鐜╁鑳藉舰鎴愬洓瀛愯繛妫嬩笖鑷冲皯涓绔紑鏀 - if (info.continuous_chess >= 4 && (info.check_start || info.check_end)) - { - need_block = true; - break; - } - - // 濡傛灉鐜╁鑳藉舰鎴愪笁瀛愭椿妫嬩笖涓ょ寮鏀 - if (info.continuous_chess == 3 && info.check_start && info.check_end) - { - need_block = true; - break; - } - } - - board[i][j] = EMPTY; // 鎭㈠妫嬬洏 - - if (need_block) - { - // 蹇呴』鍦ㄦ浣嶇疆钀藉瓙闃绘 - board[i][j] = AI; - steps[step_count++] = (Step){AI, i, j}; - printf("AI钀藉瓙(%d, %d)\n", i + 1, j + 1); - return; - } - } - } - - // 2. 濡傛灉娌℃湁闇瑕佺珛鍗抽樆姝㈢殑鎯呭喌锛屽垯姝e父璇勪及 - int best_score = -1000000; - int best_x = -1, best_y = -1; - - // 閬嶅巻妫嬬洏鎵鏈夌┖浣 - for (int i = 0; i < BOARD_SIZE; i++) - { - for (int j = 0; j < BOARD_SIZE; j++) - { - if (board[i][j] != EMPTY) - continue; - - // 鍙冭檻宸叉湁妫嬪瓙闄勮繎(2鏍艰寖鍥村唴) - bool has_nearby_stone = false; - for (int di = -2; di <= 2; di++) - { - for (int dj = -2; dj <= 2; dj++) - { - int ni = i + di; - int nj = j + dj; - if (ni >= 0 && ni < BOARD_SIZE && - nj >= 0 && nj < BOARD_SIZE) - { - if (board[ni][nj] != EMPTY) - { - has_nearby_stone = true; - break; - } - } - } - if (has_nearby_stone) - break; - } - if (!has_nearby_stone && step_count > 10) - continue; - - // 妯℃嫙AI钀藉瓙 - board[i][j] = AI; - int current_score = dfs(i, j, PLAYER, depth, -1000000, 1000000, false); - board[i][j] = EMPTY; - - // 鏇存柊鏈浣充綅缃 - if (current_score > best_score) - { - best_score = current_score; - best_x = i; - best_y = j; - } - } - } - - // 鎵ц鏈浣宠惤瀛 - if (best_x != -1 && best_y != -1) - { - board[best_x][best_y] = AI; - steps[step_count++] = (Step){AI, best_x, best_y}; - printf("AI钀藉瓙(%d, %d)\n", best_x + 1, best_y + 1); - } -} - /** * @brief 澶嶇洏娓告垙鍏ㄨ繃绋嬪苟灞曠ず璇勫垎 * @note 瀹炵幇娴佺▼: @@ -611,7 +313,7 @@ void review_process(int game_mode) // 鎵撳嵃褰撳墠姝ラ淇℃伅 // 鏍规嵁娓告垙妯″紡鏄剧ず涓嶅悓鐨勬爣棰樺拰鐜╁淇℃伅 if (game_mode == 1) - { + { // 浜烘満瀵规垬 printf("\n===== 浜斿瓙妫嬩汉鏈哄鎴(%dX%d妫嬬洏) =====", BOARD_SIZE, BOARD_SIZE); printf("\n 绗%d姝/%d姝: %s 钀藉瓙浜(%d, %d)\n", @@ -620,12 +322,12 @@ void review_process(int game_mode) s.x + 1, s.y + 1); } else - { + { // 鍙屼汉瀵规垬 printf("\n===== 浜斿瓙妫嬪弻浜哄鎴(%dX%d妫嬬洏) =====", BOARD_SIZE, BOARD_SIZE); printf("\n 绗%d姝/%d姝: %s 钀藉瓙浜(%d, %d)\n", i + 1, step_count, - (s.player == PLAYER3) ? "鐜╁1(榛戞)" : "鐜╁2(鐧芥)", + (s.player == PLAYER1) ? "鐜╁1(榛戞)" : "鐜╁2(鐧芥)", s.x + 1, s.y + 1); } @@ -640,9 +342,9 @@ void review_process(int game_mode) printf("%2d ", row + 1); // 琛屽彿 for (int col = 0; col < BOARD_SIZE; col++) { - if (temp_board[row][col] == PLAYER || temp_board[row][col] == PLAYER3) + if (temp_board[row][col] == PLAYER || temp_board[row][col] == PLAYER1) printf("x "); - else if (temp_board[row][col] == AI || temp_board[row][col] == PLAYER4) + else if (temp_board[row][col] == AI || temp_board[row][col] == PLAYER2) printf("鈼 "); else printf("路 "); @@ -668,10 +370,10 @@ void review_process(int game_mode) // 閬嶅巻鎵鏈夋鏁帮紝绱Н姣忎竴姝ョ殑寰楀垎 for (int i = 0; i < step_count; i++) { - if (steps[i].player == PLAYER || steps[i].player == PLAYER3) + if (steps[i].player == PLAYER || steps[i].player == PLAYER1) { player1_score += calculate_step_score(steps[i].x, steps[i].y, steps[i].player); - } + } else { player2_score += calculate_step_score(steps[i].x, steps[i].y, steps[i].player); @@ -688,7 +390,7 @@ void review_process(int game_mode) player1_score, (double)player1_score * 100.0 / sum_score); printf("AI寰楀垎: %d, 鍗犳瘮: %.2f%%\n", player2_score, (double)player2_score * 100.0 / sum_score); - } + } else { printf("鐜╁1(榛戞)寰楀垎: %d, 鍗犳瘮: %.2f%%\n", @@ -703,7 +405,7 @@ void review_process(int game_mode) { printf("鐜╁寰楀垎: %d\n", player1_score); printf("AI寰楀垎: %d\n", player2_score); - } + } else { printf("鐜╁1(榛戞)寰楀垎: %d\n", player1_score); @@ -752,7 +454,7 @@ void handle_save_record(int game_mode) { case 0: // 鎴愬姛 printf("\n娓告垙璁板綍宸叉垚鍔熶繚瀛樿嚦: %s\n", filename); - printf("鎮ㄥ彲浠ヤ娇鐢ㄤ互涓嬪懡浠よ繘琛屽鐩: .\\浜斿瓙妫.exe -l %s\n", filename); + printf("鎮ㄥ彲浠ヤ娇鐢ㄤ互涓嬪懡浠よ繘琛屽鐩: .\\gobang.exe -l %s\n", filename); break; case 1: // 鐩綍鍒涘缓澶辫触 printf("\n娓告垙璁板綍淇濆瓨澶辫触: 鏃犳硶鍒涘缓 'records' 鐩綍銆俓n"); @@ -775,7 +477,7 @@ void handle_save_record(int game_mode) /** * @brief 鎮旀鍔熻兘瀹炵幇 - * + * * @param steps_to_undo 瑕佹倲妫嬬殑姝ユ暟 * @return true 鎮旀鎴愬姛 * @return false 鎮旀澶辫触(姝ユ暟涓嶈冻) @@ -789,14 +491,16 @@ bool return_move(int steps_to_undo) for (int i = 0; i < steps_to_undo; i++) { - step_count--; - board[steps[step_count].x][steps[step_count].y] = EMPTY; + if (step_count > 0) + { + step_count--; + board[steps[step_count].x][steps[step_count].y] = EMPTY; + } } return true; } - /** * @brief 璇勪及鐜╁鍦ㄦ暣鐩樻灞涓殑琛ㄧ幇 * @param player 瑕佽瘎浼扮殑鐜╁(PLAYER/AI) diff --git a/gobang.exe b/gobang.exe index f32c0f5..1537c11 100644 Binary files a/gobang.exe and b/gobang.exe differ diff --git a/gobang.h b/gobang.h index 757ec02..4482189 100644 --- a/gobang.h +++ b/gobang.h @@ -3,7 +3,7 @@ * @author 鍒樿埅瀹(3364451258@qq.com銆15236416560@163.com銆乴hy3364451258@outlook.com) * @brief 浜斿瓙妫嬫父鎴忓ご鏂囦欢 * @version 3.0 - * @date 2025-06-26 + * @date 2025-06-30 * * @copyright Copyright (c) 2025 * @@ -41,8 +41,8 @@ */ #define PLAYER 1 // 鐜╁妫嬪瓙鏍囪瘑绗 #define AI 2 // AI妫嬪瓙鏍囪瘑绗 -#define PLAYER3 3 // 鐜╁3妫嬪瓙鏍囪瘑绗 -#define PLAYER4 4 // 鐜╁4妫嬪瓙鏍囪瘑绗 +#define PLAYER1 1 // 鐜╁1妫嬪瓙鏍囪瘑绗 +#define PLAYER2 2 // 鐜╁2妫嬪瓙鏍囪瘑绗 /** * @brief 绌轰綅缃爣璇嗙 @@ -63,6 +63,7 @@ extern int step_count; // 褰撳墠姝ユ暟璁℃暟鍣 extern bool use_forbidden_moves; // 鏄惁鍚敤绂佹墜瑙勫垯 extern int use_timer; // 鏄惁鍚敤璁℃椂鍣 extern int time_limit; // 鏃堕棿闄愬埗锛堢锛 +extern const int direction[4][2]; /** * @brief 钀藉瓙姝ラ璁板綍缁撴瀯浣 @@ -175,34 +176,6 @@ DirInfo count_specific_direction(int x, int y, int dx, int dy, int player); */ bool check_win(int x, int y, int player); -/** - * @brief 璇勪及鐗瑰畾浣嶇疆瀵瑰綋鍓嶇帺瀹剁殑浠峰 - * @param x 琛屽潗鏍(0-base) - * @param y 鍒楀潗鏍(0-base) - * @param player 鐜╁鏍囪瘑(PLAYER/AI) - * @return int 浣嶇疆璇勪及鍒嗘暟(瓒婇珮瓒婂ソ) - */ -int evaluate_pos(int x, int y, int player); - -/** - * @brief 甯ξ-尾鍓灊鐨勬繁搴︿紭鍏堟悳绱(鏋佸皬鏋佸ぇ绠楁硶) - * @param x 褰撳墠琛屽潗鏍 - * @param y 褰撳墠鍒楀潗鏍 - * @param player 褰撳墠鐜╁ - * @param depth 鎼滅储娣卞害 - * @param alpha 伪鍊(褰撳墠鏈澶у) - * @param beta 尾鍊(褰撳墠鏈灏忓) - * @param is_maximizing 鏄惁涓烘瀬澶у寲鐜╁ - * @return int 鏈浣宠瘎浼板垎鏁 - */ -int dfs(int x, int y, int player, int depth, int alpha, int beta, bool is_maximizing); - -/** - * @brief AI钀藉瓙鍐崇瓥鍑芥暟 - * 浣跨敤璇勪及鍑芥暟鍜屾悳绱㈢畻娉曢夋嫨鏈浣宠惤瀛愪綅缃 - */ -void ai_move(int depth); - /** * @brief 鎮旀鍔熻兘瀹炵幇 * @return true 鎮旀鎴愬姛 @@ -233,7 +206,6 @@ int evaluate_performance(int player); */ int calculate_step_score(int x, int y, int player); - /** * @brief 灏嗗綋鍓嶆父鎴忚褰曚繚瀛樺埌鏂囦欢 * @param filename 瑕佷繚瀛樼殑鏂囦欢鍚 diff --git a/浜斿瓙妫.c b/浜斿瓙妫.c index 7e509c7..0b36773 100644 --- a/浜斿瓙妫.c +++ b/浜斿瓙妫.c @@ -7,10 +7,10 @@ /** * @brief 灏嗘寚浠ゅ鍒跺埌powershell - * gcc 浜斿瓙妫.c gobang.c game_mode.c -o output/浜斿瓙妫.exe + * gcc 浜斿瓙妫.c gobang.c game_mode.c ai.c -o gobang.exe * gcc 涓虹紪璇戝櫒锛屼簲瀛愭.c gobang.c game_mode.c 涓烘簮鏂囦欢锛宱utput/涓鸿緭鍑虹洰褰 * @brief 灏嗘寚浠ゅ鍒跺埌powershell - * .\output\浜斿瓙妫.exe + * .\gobang.exe */ int main(int argc, char *argv[]) @@ -24,24 +24,32 @@ int main(int argc, char *argv[]) #endif // 閫夋嫨妯″紡 - printf("===== 浜斿瓙妫嬫父鎴 =====\n"); - printf("1. AI妯″紡\n"); - printf("2. 鐜╁姣旇禌\n"); - printf("3. 澶嶇洏妯″紡\n"); - int mode = get_integer_input("璇疯緭鍏ユā寮(1/2/3): ", 1, 3); + while(1) + { + printf("===== 浜斿瓙妫嬫父鎴 =====\n"); + printf("1. AI妯″紡\n"); + printf("2. 鐜╁姣旇禌\n"); + printf("3. 澶嶇洏妯″紡\n"); + printf("4. 閫鍑烘父鎴廫n"); + int mode = get_integer_input("璇疯緭鍏ユā寮(1/2/3/4): ", 1, 4); - if (mode == 1) - { - run_ai_game(); + if (mode == 1) + { + run_ai_game(); + } + else if (mode == 2) + { + run_pvp_game(); + } + else if (mode == 3) + { + run_review_mode(); + } + else if (mode == 4) + { + break; + } } - else if (mode == 2) - { - run_pvp_game(); - } - else if (mode == 3) - { - run_review_mode(); - } - + return 0; } \ No newline at end of file