发布时间:2026/8/26 15:38:59
第一个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/8/26 15:38:59

构建你的Agent框架

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

2026/8/26 15:38:59

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

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

2026/8/26 16:24:15

DM达梦数据库遇过的坑

最近在做信创环境的项目 ,原项目用的MySQL数据库,转到DM数据库中好多SQL都出现了问题,为方便以后开发,将遇到过的问题在这里做个记录,以后会不断更新。转换丢失警告 情形一: 出错原因:原SQL里使…

2026/8/26 16:24:15

移动软件开发实验1

移动软件开发实验1一、实验内容(一)安装开发工具(二)创建hello world小程序1.index.wxml2.index.wxss3.index.js(三)运行结果二、问题总结与体会(一)问题总结(二&#xf…

2026/8/26 16:19:12

OUC26夏移动软件开发-实验1

OUC26夏移动软件开发-实验1 姓名:马一诺 学号:项目内容姓名和学号马一诺本实验属于哪门课程中国海洋大学26夏《移动软件开发》实验名称实验1:热身运动GitHub源码链接https://github.com/1-qaz-2-wsx/ouc26-mobile-dev/tree/main/lab1博客链接…

2026/8/26 9:13:28

[光学原理与应用-521]:对光的错误理解与纠偏

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

2026/8/25 11:48:27

SIP通话转接原理与REFER方法实战解析

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

2026/8/25 16:56:43

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

2026/8/26 0:04:32

Python random 模块常用函数详解:从入门到实战

目录 1. 引言2. 准备工作3. 基础随机函数4. 序列相关函数5. 随机种子与复现6. 实战案例7. 注意事项8. 常见问题与排查9. 总结 1. 引言 摘要: 本文系统介绍 Python 标准库 random 模块中最常用的随机数生成函数。内容涵盖基础随机函数(random()、unifor…

2026/8/26 1:19:35

JSON总结

JSON概念 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,主要用于跟服务器进行交换数据。它基于ECMAScript的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C、C、C#、Java、JavaScr…

2026/8/26 1:19:35

保存连接sse 是什么原理,为什么不会一直请求

“保持连接”用的是 SSE(Server-Sent Events),本质是一个没有马上结束的 HTTP 请求。 过程是: 拷贝机发送一次请求: GET /api/code-sync/events服务器返回: Content-Type: text/event-stream但不关闭响应&…

2026/8/24 13:42:17

实测才敢推 AI论文网站 2026最新测评与推荐

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。一、综…

2026/8/24 18:13:48

2026必备!AI论文网站测评:最新推荐与深度对比

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

2026/8/25 1:08:14

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…