第一个C语言项目——AI辅助扫雷游戏实现

发布时间:2026/10/20 0:15:40

第一个C语言项目——AI辅助扫雷游戏实现 一、为什么选择扫雷作为第一个项目前段时间刚学完分支循环、数组和函数总觉得自己学得会用不出。于是决定动手做一个控制台版的扫雷——把学到的东西真正用起来。这篇博客记录的就是这个过程从控制台版本的实现到后来尝试用 AI 辅助做一个界面版本。不敢说是什么教程更像是一份学习路上的阶段性总结。二、控制台版本扫雷游戏的实现2.1 文件创建创建main.c、game.c、game.h文件。将项目的实现逻辑放入main.c文件游戏的功能放入game.c文件利用game.h头文件将两个源文件联系起来。2.2 菜单操作首先打印菜单我们可以使用一个函数封装打印菜单的操作。voidmenu(){printf(------------------\n);printf(------1.start-----\n);printf(------0.exit------\n);printf(------------------\n);}在main函数中调用menu运行结果如下接着使用scanf函数和switch函数根据用户输入的数字开始游戏或退出游戏。intchoose0;scanf(%d,choose);switch(choose){case1://game();printf(游戏中);break;case0:printf(退出游戏);break;default:printf(输入无效请重新输入);}game()函数还未定义故把game函数注释测试用户选择功能是否正常。运行结果如下用户可以正常选择。但我们发现无效输入时程序会直接退出而不是让用户重新输入用户结束游戏时程序也会直接退出不能选择是否继续玩。当程序开始运行时至少打印一次菜单所以使用do-while循环解决这个问题会是一个可行的办法。intchoose0;do{menu();//打印菜单//用户选择scanf(%d,choose);switch(choose){case1://game();printf(游戏中\n);printf(不过瘾可以再来一把哟\n);break;case0:printf(退出游戏\n);break;default:printf(输入无效请重新输入\n);}printf(\n);}while(choose);从上面的代码我们不难发现。输入的值不仅可以让程序进入相对应的分支还能控制循环条件。若选择0退出游戏的同时循环也会退出若选择1结束游戏时重新进入循环选择若无效输入choose为非零整数依然为真即可以重新进入循环。运行结果如下至此菜单操作功能完善。2.3 游戏功能实现接下来我们在game.c中实现游戏功能并在game.h中声明。2.3.1 棋盘创建在进行扫雷游戏时玩家不能看到雷的位置但游戏的进行需要雷的位置。因此我们需要创建两个棋盘。一个棋盘让玩家只能看见附近3*3的雷的个数另一个棋盘知道所有雷的位置。使用二维数组创建棋盘。棋盘棋盘的行列数默认为9且被定义为ROW和COL。并定义ROWS和COLS。#defineROW9#defineCOL9#defineROWSROW2#defineCOLSCOL2为什么要定义ROWS和COLS在创建数组时不能简单地创建如show[ROW][COL] … 假设数组长度这么设置会给游戏留下隐患。举个例子若玩家选择边缘处的坐标程序在判断周围是否有雷时会越界访问数组。正因如此可以这么创建数组:charshow[ROWS][COLS]{0};charplay[ROWS][COLS]{0};这么创建数组给数组留了缓冲区解决了越界访问数组的问题。2.3.2 初始化棋盘当创建好了棋盘之后就可以对棋盘进行初始化了。在show棋盘中可以用*表示未被翻开的格子在play棋盘中用字符‘1’表示有雷‘0’表示没雷。初始化如下voidinit_board(chararr[ROWS][COLS],chars){//遍历棋盘并写入指定字符for(inti0;iROWS;i){for(intj0;jCOLS;j){arr[i][j]s;}}}对所有数组元素初始化这样当边缘处格子被选择时程序扫描缓冲区时与扫描’0’无异。2.3.3 打印show棋盘打印show棋盘主体只需要两个for循环但棋盘展示不能只打印主体部分。为了让游戏更有可玩性可以参考如下打印方式voidprint_board(chararr[ROWS][COLS],intr,intc){//打印顶部数字且使用|分隔每个坐标方便查找坐标for(inti0;ic;i){printf(%d| ,i);}printf(\n);//打印棋盘主体部分for(inti1;ir;i){//打印每行前先打印一行-|-起到分隔作用与顶部对齐for(intk0;kc;k){printf(-|-);}printf(\n);printf(%d| ,i);//在每行前加上数字方便查找坐标for(intj1;jc;j){printf(%c| ,arr[i][j]);}printf(\n);}}将该打印方式封装成一个函数print_board。运行结果如下已经成功打印棋盘我们就可以进入下一步了。2.3.4 布置雷要想布置雷首先确定雷的个数。定义雷数默认10。#defineMINES10雷的个数确定之后我们不难想到利用循环和随机数生成10个随机坐标并布置在play棋盘中。voidset_mine(chararr[ROWS][COLS]){intcountMINES;while(count--){//生成两个1-9的随机数表示行列inta1rand()%9;//a表示所在行intb1rand()%9;//b表示所在列//printf(%d , a);arr[a][b]1;//对随机坐标写入1布置雷}}在main函数利用当前时间戳设置随机数种子srand((unsignedint)time(NULL));此时布置雷已经写好。要想知道是否布置成功可以打印play棋盘。运行结果如下:不难发现随机雷已经布置成功。当然也可以先布置雷后打印棋盘且更有条理。2.3.5 玩家扫雷过程框架当菜单初始化布置雷功能可以正常运行就可以开始处理游戏过程。游戏过程中玩家不断输入坐标进行多次排雷操作每次排雷成功立即执行下一次排雷直到被炸死或排雷完成。intcount0;printf(输入格式:行 列\n);printf(示例:3 4\n);while(1){//打印show棋盘print_board(show,ROW,COL);intr0;intc0;scanf(%d %d,r,c);//键盘输入坐标//判断输入坐标是否合法if(show[r][c]*rROWr0cCOLc0){//判断输入坐标是否为雷if(play[r][c]0){printf(排雷成功\n);}else{printf(你已被炸死\n);break;}}else{printf(非法输入排雷失败\n);}}把打印棋盘的功能放入了循环玩家每次排雷成功都能刷新棋盘。外层if判断输入坐标是否为非法输入。外层if判断输入坐标是否有雷。创建了一个count计数器方便之后通过计算排雷数判定游戏胜利。除游戏胜利以外进行功能测试2.3.6 扫描玩家输入坐标程序立即计算周围雷数并将“*”替换为周围雷个数。在替换之前需要先进行搜索计算。可以将这个过程封装成一个返回值为char的函数若将play数组以及玩家输入的坐标传入该函数即可计算周围的’1’的个数并返回。参考写法:charsearch_mine(chararr[ROWS][COLS],inta,intb){//a,b表示传入行列//sum变量存储附近总雷数charsum0;//计算附近3*3格子的雷数for(inti-1;i1;i){for(intj-1;j1;j){sumarr[ia][jb]-0;}}returnsum;}2.3.7 替换计算完整块区域的雷总数就可以将原本的*替换为雷的总数。不妨把这个过程封装成一个void函数。voidsweep_mine(charshow[ROWS][COLS],charplay[ROWS][COLS],inta,intb){charsumsearch_mine(play,a,b);show[a][b]0sum;}将show和play数组分别传入该函数的参数1参数2用sum接收返回的雷数并对show数组做修改。通过运行测试修改是否成功2.3.8 胜利判定前面已经创建了count计数器但还没有使用。要想判断玩家是否把雷全部排完此时就要用到计数器统计排雷次数即每次排雷成功count1当count达到上限游戏结束。在game函数判断是否有雷的if分支中可以新增一个if-else分支。参考代码如下//判断输入坐标是否为雷if(play[r][c]0){sweep_mine(show,play,r,c);count;printf(排雷成功\n);//判断是否排完雷if(countROW*COL-MINES){printf(你赢了游戏结束\n);break;}将地雷数MINES改成80测试一下胜利判定是否生效至此扫雷游戏的基础功能已全部实现。2.4 优化2.4.1 炸开一片实现了扫雷游戏的基础功能之后就可以运行使用。然而在使用的过程中我们发现每次游戏进行得太久。由于每次排雷只能选择选择一个格子且当某格子显示0时其周围的3*3区域完全没有必要手动翻开。所以修改sweep_mine函数当排雷位置周围无雷时自动向外扩张。voidsweep_mine(charshow[ROWS][COLS],charplay[ROWS][COLS],inta,intb){if(a1||a9||b1||b9||show[a][b]!*)return;charsumsearch_mine(play,a,b);show[a][b]0sum;count;if(show[a][b]0){for(inti-1;i1;i){for(intj-1;j1;j){sweep_mine(show,play,ai,bj);}}}}在此基础上把count设为全局变量,并删除在game函数中的count。修改后每次选择到周围雷数为0的格子对整块3*3区域重新调用sweep_mine函数。每次进入函数a,b被判断是否合法是否已经被排。在show棋盘每次*被修改为数字count1。不妨将MINES改为5运行测试炸开一片功能程序正常运行。2.4.2 细节优化每次排雷开始前屏幕会打印棋盘也就意味着每玩一次游戏会打印多个棋盘看着不够美观。所以可以每次扫完雷进行一次清屏操作。但随之而来的又是一个小问题清屏操作会把程序刚刚打印的“排雷成功”清除。所以我们可以在每次排雷结束时等待半秒进入清屏操作。只需在game函数的while循环末尾添加如下代码Sleep(500);system(cls);以上操作完成控制台版扫雷游戏彻底完成。三、界面版本扫雷游戏实现完成了控制台版本之后就可以尝试利用AI做出一个带界面扫雷游戏。以下操作使用deepseek最近发布的deepseek harness。选择deepseek V4 flash模型。发送ai提示词在尽量少改动代码的基础上使⽤raylib库将扫雷游戏改造成带界⾯的版本raylib我已经安装好了路径是C:\raylib\raylib-6.0_win64_msvc16ai实现运行四、结语控制台版靠硬写界面版靠 AI 搭骨架、自己填血肉。同样的功能开发周期从周压缩到天——这不是偷懒是把时间花在了真正该思考的地方。
延伸阅读

更多相关文章

2026/10/20 2:34:43

构建你的Agent框架

摘要:随着大语言模型(LLM)从“单一问答对话”向“自主执行复杂任务”演进,AI Agent(智能体)已成为当前 AI 应用落地的核心形态。很多开发者在探索 Agent 时,往往直接依赖 LangChain、CrewAI 或 …

2026/10/19 9:56:37

供应链合同管理的3个致命误区与系统化解决方案

做了多年供应链系统开发,我见过太多企业在合同管理上栽跟头。有意思的是,栽跟头的方式高度相似。同样的问题,在不同行业、不同规模的企业里反复出现。 我把最常见的三个误区写出来,不是为了让你们对号入座,而是希望做供…

2026/10/20 7:56:34

基于SpringBoot的保险保单分析系统开题答辩全流程指南

上个月我走完了一场开题答辩,题目是《基于SpringBoot的保险保单分析系统设计与实现》。从收到开题通知到答辩结束,前后准备了小一个月,中间踩了不少坑。今天把完整过程整理出来——标题里说的“全过程”不只是现场那十几分钟,而是…

2026/10/20 7:56:34

PHP+Excel通用课表查询系统v3.8:部署、查询逻辑与性能优化

简介:这份资源是面向Web开发初学者、计算机专业学生及毕业设计实践者的PHP课表查询系统源码包,基于PHP与Excel文件格式构建,用于高效管理和查询课程表信息,适用于学校、培训机构或个人学习计划管理场景。压缩包共19个文件&#xf…

2026/10/20 7:56:34

Oracle ASM命令行添加聚合磁盘实战:从语法到重平衡验证

干这行十来年,ASM磁盘组的管理几乎每周都会碰到。今天想聊聊“Oracle ASM 命令行方式添加聚合磁盘”这件事。很多人看到“聚合磁盘”会愣一下,因为Oracle官方文档里其实没有这个标准名词,它更多是实践里的说法:把多块物理裸盘交给…

2026/10/20 7:56:34

单目结构光三维重建:Matlab实现互补格雷码与多频外差相位展开

做结构光三维重建的,手里基本都攒过一套“投影仪相机”的实验台。这套代码就是把台上最核心的几个环节——条纹编码、图像采集、相位解算、相位展开、三角化重建——全部用Matlab串起来。项目同时实现了互补格雷码加四步相移、多频外差加四步相移两条相位展开路线&a…

2026/10/20 7:51:34

机器学习复习地图:从损失函数到评估指标的系统梳理

简介:《唐宇迪-机器学习课程资料》是一套面向机器学习初学者与进阶者的综合学习包,内容覆盖Python编程基础、常用库实战与主流算法理论,可帮助学习者从零搭建知识体系并掌握实际建模能力。整个资源以RAR压缩包形式发布,大小66.11M…

2026/10/19 18:06:35

金融AI落地指南:从调研报告到技术选型与工程实践

简介:这份PDF报告聚焦2025年金融服务业中国AI现状与趋势,面向金融科技从业者、AI战略规划人员及关注行业数字化转型的研究者,帮助读者把握生成式AI在银行、支付、交易等场景中的落地路径与投资方向。资源包内含1个PDF文件,大小约1…

2026/10/20 1:05:37

单片机C运行时从启动到多任务:中断安全与共享资源冲突

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:05:37

GCC编译四步详解:预处理、编译、汇编、链接实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:05:37

FIW线是什么?FEP注塑线与普通氟塑料线的区别及应用指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑