当前位置:   article > 正文

用C++实现扫雷(使用键盘操作的简易版)_c++扫雷

c++扫雷

目录

游戏效果如下:

游戏如何实现?

下面是完整的代码:


终于期末了,我们很难不用学过的C艹编程知识写一些小游戏打发时间(折磨自己),以下分享我无聊做的扫雷游戏

界面很简陋,只能用键盘操作,主要是我不会搭建窗口、不会实现鼠标操作(比不上大佬们),但游戏功能和操作都和经典扫雷一致。能够实现自定义雷区长度和雷数,存储游戏记录,游戏中可实现四种基本操作。

游戏效果如下:

开始界面:

游戏界面:

 

这里使用井号#表示未开启的区域,标记安全后区域会变成数字 ,有雷的标记为加号+,地雷的标记为星号*

游戏中的截图: 

 踩雷了,游戏结束:

 ‘1’标记安全,相当于经典扫雷的鼠标左键

‘2’标记有雷,‘3’取消标记有雷,相当于鼠标右键

‘4’快捷标记安全,相当于鼠标左右键齐按(作用于已经标记安全的位置,快速开启周围八格)

游戏如何实现?

第一步:构建游戏画面。首先根据输入的雷区大小axb,创建二维int数组arr,只存放有雷(9)或无雷(10)的情况,为了让雷随机出现,初始化的时候,先填满10,然后根据输入的雷的个数n创建长度为axb,前n个元素为9,其余元素为10的vector数组,用algorithm里面的random_shuffle函数可以随机打乱这个数组,然后把vector数组的元素依次填入arr,就能实现雷的随机生成。

需要注意,考虑到后面搜索周围八格的雷可能遇到边界无法搜索的情况,这里构建的arr数组会比雷区大小大一圈(例如4x5的雷区,创建的arr数组为6x7,第0行、第0列、第5行、第6列填充为10),为了方便坐标对应,后面的ar和gra也大一圈,但多出的一圈没有实际用途

再创建二维int数组ar,它的任务是在无雷的位置(即数值为10)计算周围八格的雷数,并填入对应的数字0-8

最后创建char数组gra,这个数组是被打印到屏幕的,最开始初始化全为#

第二步:实现游戏过程,每次操作都刷新屏幕重新输出,标记安全或快捷标记安全都根据数组ar先判断是否踩雷,如果ar该点的数字为0,说明周围八格无雷,为了优化游戏体验,我们需要自动帮忙打开周围的八格(这个靠递归函数就能实现),直到遇到数字或雷。

如果踩雷了,就输出雷的真实排布,判定胜利利用两个变量:玩家标记点的个数和标记点正确的个数(正确的意思是标记点正好有雷)都等于真正的雷数。

游戏还有计时功能,可以在游戏结束后输出本轮用时,利用time(NULL)函数分别记录游戏开始和结束的时间(两个unsigned int变量),做差就是游戏时间。

 

第三步:实现主页面和游戏记录,没什么技术含量,不解释了。

下面是完整的代码:

  1. #include<iostream>
  2. #include<vector>
  3. #include<algorithm>
  4. #include<iomanip>
  5. #include<ctime>
  6. #include<fstream>
  7. #define Jin '#'//代表未开启的区域
  8. #define Jia '+'//用于标记有雷
  9. using namespace std;//以下初始化二维数组的指针为全局变量
  10. char** gra = NULL;//该指针指向的二维数组存放游戏画面
  11. int** arr = NULL;//该指针指向的二维数组存放有雷(9)或无雷(10)两种情况
  12. int** ar = NULL;//该指针指向的二维数组存放有雷(9)或无雷时其周围九格区域的雷数
  13. void file(int m, unsigned int time)
  14. {
  15. ofstream ofs;
  16. ofs.open("BoomData.txt", ios::app);
  17. if (m == 0)
  18. ofs << "游戏失败,用时" << time << "秒" << endl;
  19. else
  20. ofs << "游戏成功,用时" << time << "秒" << endl;
  21. ofs.close();
  22. }
  23. int kopen(int x,int y)//快捷标记打开函数
  24. {
  25. void open(int x, int y);
  26. void open1(int x, int y);
  27. if (gra[x][y] == Jia)
  28. return 0;
  29. else
  30. {
  31. if (arr[x][y] == 9)
  32. return 1;//发现有雷
  33. else if (ar[x][y] == 0)//周围无雷时递归地开启周围的八格
  34. open(x, y);
  35. else
  36. open1(x, y);//周围有雷时只开启本格
  37. return 0;
  38. }
  39. }
  40. void open1(int x, int y)//遇到非0的函数实现,不允许开启的部分继续开启周围八格
  41. {
  42. gra[x][y] = ar[x][y] + 48;
  43. }
  44. void open(int x, int y)
  45. {
  46. gra[x][y] = ar[x][y] + 48;//生成数字,展示在屏幕上
  47. if (ar[x - 1][y] == 0 && gra[x - 1][y] == Jin)
  48. open(x - 1, y);
  49. if (ar[x][y - 1] == 0 && gra[x][y - 1] == Jin)
  50. open(x, y - 1);
  51. if (ar[x][y + 1] == 0 && gra[x][y + 1] == Jin)
  52. open(x, y + 1);
  53. if (ar[x + 1][y] == 0 && gra[x + 1][y] == Jin)
  54. open(x + 1, y);
  55. if (ar[x - 1][y - 1] == 0 && gra[x - 1][y - 1] == Jin)
  56. open(x - 1, y - 1);
  57. if (ar[x - 1][y + 1] == 0 && gra[x - 1][y + 1] == Jin)
  58. open(x - 1, y + 1);
  59. if (ar[x + 1][y - 1] == 0 && gra[x + 1][y - 1] == Jin)
  60. open(x + 1, y - 1);
  61. if (ar[x + 1][y + 1] == 0 && gra[x + 1][y + 1] == Jin)
  62. open(x + 1, y + 1);
  63. //遇到0时自动开启周围八格,并且开启的部分继续开启周围八格
  64. if (ar[x - 1][y] > 0 && ar[x - 1][y] < 9 && gra[x - 1][y] == Jin)
  65. open1(x - 1, y);
  66. if (ar[x][y - 1] > 0 && ar[x][y - 1] < 9 && gra[x][y - 1] == Jin)
  67. open1(x, y - 1);
  68. if (ar[x][y + 1] > 0 && ar[x][y + 1] < 9 && gra[x][y + 1] == Jin)
  69. open1(x, y + 1);
  70. if (ar[x + 1][y] > 0 && ar[x + 1][y] < 9 && gra[x + 1][y] == Jin)
  71. open1(x + 1, y);
  72. if (ar[x - 1][y - 1] > 0 && ar[x - 1][y - 1] < 9 && gra[x - 1][y - 1] == Jin)
  73. open1(x - 1, y - 1);
  74. if (ar[x - 1][y + 1] > 0 && ar[x - 1][y + 1] < 9 && gra[x - 1][y + 1] == Jin)
  75. open1(x - 1, y + 1);
  76. if (ar[x + 1][y - 1] > 0 && ar[x + 1][y - 1] < 9 && gra[x + 1][y - 1] == Jin)
  77. open1(x + 1, y - 1);
  78. if (ar[x + 1][y + 1] > 0 && ar[x + 1][y + 1] < 9 && gra[x + 1][y + 1] == Jin)
  79. open1(x + 1, y + 1);
  80. //遇到非0时自动开启周围八格,不允许开启的部分继续开启周围八格
  81. }
  82. void printgraph(int n)//用于打印游戏界面
  83. {
  84. system("cls");
  85. for (int i = 0; i <= n; i++)
  86. cout << setw(2) << setfill('0') << i << " ";
  87. cout << endl;
  88. for (int i = 1; i <= n; i++)
  89. {
  90. cout << setw(2) << setfill('0') << i << " ";
  91. for (int j = 1; j <= n; j++)
  92. {
  93. cout << gra[i][j] << " ";
  94. }
  95. if (i == 1)
  96. cout << " 操作'1'代表标记安全";
  97. if (i == 2)
  98. cout << " 操作'2'代表标记有雷";
  99. if (i == 3)
  100. cout << " 操作'3'取消标记有雷";
  101. if (i == 4)
  102. cout << " 操作'4'快捷标记安全(自动标记周围八格)";
  103. cout << endl;
  104. }
  105. cout << "请输入:(用空格隔开)" << endl;
  106. cout << "行 列 操作" << endl;
  107. }
  108. void game(int n, int boom)
  109. {
  110. srand((unsigned int)time(NULL));
  111. unsigned int gametimestart = (unsigned int)time(NULL);//记录游戏开始的时间
  112. cout << "游戏正在加载中,请等待" << endl;
  113. arr = new int*[n+2];
  114. for (int i = 0; i < n+2; i++)
  115. arr[i] = new int[n+2];//定义二维数组arr
  116. ar = new int* [n + 2];
  117. for (int i = 0; i < n + 2; i++)
  118. ar[i] = new int[n + 2];//定义二维数组ar
  119. for (int i = 0; i < n + 2; i++)
  120. {
  121. arr[0][i] = 10;
  122. arr[n + 1][i] = 10;
  123. arr[i][0] = 10;
  124. arr[i][n + 1] = 10;//初始化边缘无雷
  125. ar[0][i] = 10;
  126. ar[n + 1][i] = 10;//10表示无雷
  127. ar[i][0] = 10;
  128. ar[i][n + 1] = 10;
  129. }
  130. vector<int>v;
  131. v.resize(n * n, 10);
  132. for (vector<int>::iterator it = v.begin(); it < v.begin() + boom; it++)
  133. *it = 9;//9表示有雷
  134. random_shuffle(v.begin(),v.end());//随机生成n个位置夹杂boom个雷的排列
  135. for (int i = 0; i < n * n; i++)
  136. arr[i / n + 1][i % n + 1] = v[i];//将雷填充入二维数组arr
  137. for (int i = 1; i <= n; i++)
  138. {
  139. for (int j = 1; j <= n; j++)//遍历二维数组arr每个位置
  140. {
  141. if (arr[i][j] == 9)//如果是雷,遍历下一个位置
  142. ar[i][j] = 9;
  143. else
  144. {
  145. ar[i][j] = arr[i][j] + arr[i - 1][j - 1] + arr[i - 1][j] + arr[i - 1][j + 1]
  146. + arr[i][j - 1] + arr[i][j + 1] + arr[i + 1][j - 1] + arr[i + 1][j]
  147. + arr[i + 1][j + 1];
  148. ar[i][j] = 90 - ar[i][j];//如果不是雷,计算其周边八格雷的个数,并赋值给ar
  149. }
  150. }
  151. }
  152. gra = new char* [n + 2];
  153. for (int i = 0; i < n + 2; i++)
  154. gra[i] = new char[n + 2];//定义用于显示游戏页面的二维数组gra
  155. for (int i = 1; i <= n; i++)
  156. {
  157. for (int j = 1; j <= n; j++)
  158. {
  159. gra[i][j] = Jin;//初始化用Jin填充
  160. }
  161. }
  162. int x, y, z, m1 = 0,right=0;
  163. another:
  164. printgraph(n);
  165. cin >> x >> y >> z;//输入三数以操作
  166. if (!(x >= 1 && x <= n && y >= 1 && y <= n))//判断坐标是否合法
  167. {
  168. cout << "输入坐标错误" << endl;
  169. system("pause");
  170. goto another;
  171. }
  172. if (z == 1 && gra[x][y] == Jin)
  173. {
  174. if (ar[x][y] == 10)
  175. return;
  176. if (ar[x][y] == 9)
  177. {
  178. fail:
  179. system("cls");//此处游戏失败,显示所有的雷
  180. unsigned int gametimeend = (unsigned int)time(NULL);
  181. for (int i = 0; i <= n; i++)
  182. cout << setw(2) << setfill('0') << i << " ";
  183. cout << endl;
  184. for (int i = 1; i <= n; i++)
  185. {
  186. cout << setw(2) << setfill('0') << i << " ";
  187. for (int j = 1; j <= n; j++)
  188. {
  189. if (ar[i][j] == 9)
  190. cout << '*' << " ";
  191. else
  192. cout << ar[i][j] << " ";
  193. }
  194. cout << endl;
  195. }
  196. unsigned int gametime = gametimeend - gametimestart;
  197. cout << "你没了" << endl;
  198. cout << "本次游戏用时" << gametime << "秒" << endl;//输出游戏时间
  199. file(0, gametime);//游戏记录写入文件
  200. return;
  201. }
  202. else
  203. {
  204. gra[x][y] = ar[x][y] + 48;
  205. if (ar[x][y] == 0)
  206. {
  207. open(x, y);
  208. }
  209. }
  210. }
  211. else if (z == 2 && gra[x][y] == Jin)
  212. {
  213. gra[x][y] = Jia;
  214. m1++;
  215. right = (ar[x][y] == 9) ? (right + 1) : right;
  216. }
  217. else if (z == 3 && gra[x][y] == Jia)
  218. {
  219. gra[x][y] = Jin;
  220. m1--;
  221. right = (ar[x][y] == 9) ? (right - 1) : right;
  222. }
  223. else if (z == 4 && gra[x][y] != Jin && gra[x][y] != Jia)//快捷标记安全实现
  224. {
  225. int jnum=0;
  226. jnum = (gra[x - 1][y - 1] == Jia ? jnum + 1 : jnum);
  227. jnum = (gra[x - 1][y] == Jia ? jnum + 1 : jnum);
  228. jnum = (gra[x - 1][y + 1] == Jia ? jnum + 1 : jnum);
  229. jnum = (gra[x][y - 1] == Jia ? jnum + 1 : jnum);
  230. jnum = (gra[x][y + 1] == Jia ? jnum + 1 : jnum);
  231. jnum = (gra[x + 1][y - 1] == Jia ? jnum + 1 : jnum);
  232. jnum = (gra[x + 1][y] == Jia ? jnum + 1 : jnum);
  233. jnum = (gra[x + 1][y + 1] == Jia ? jnum + 1 : jnum);//统计周围标记有雷点个数
  234. if (jnum != ar[x][y])
  235. {
  236. cout << "不符合快捷标记条件,周围标记雷数与实际雷数不等" << endl;
  237. system("pause");
  238. }
  239. else
  240. {
  241. int failnum=0;//检查是否踩雷
  242. failnum += kopen(x - 1, y - 1);
  243. failnum += kopen(x - 1, y);
  244. failnum += kopen(x - 1, y + 1);
  245. failnum += kopen(x, y - 1);
  246. failnum += kopen(x, y + 1);
  247. failnum += kopen(x + 1, y - 1);
  248. failnum += kopen(x + 1, y);
  249. failnum += kopen(x + 1, y + 1);
  250. if (failnum != 0)
  251. goto fail;
  252. }
  253. }
  254. if (m1 == boom&&right==boom)//采用m1(标记点个数)和right(正确点个数)判断是否赢了
  255. {
  256. printgraph(n);
  257. cout << "你赢了" << endl;
  258. unsigned int gametimeend = (unsigned int)time(NULL);
  259. unsigned int gametime = gametimeend - gametimestart;//输出游戏时间
  260. cout << "本次游戏用时" << gametime << "秒" << endl;
  261. file(1, gametime);//游戏记录写入文件
  262. return;
  263. }
  264. goto another;
  265. }
  266. int main()
  267. {
  268. system("color 3F");//设置游戏界面颜色
  269. system("title 扫雷3.0");
  270. int choose, n, boom;
  271. home:
  272. system("cls");
  273. cout << "*******************" << endl;
  274. cout << "******扫雷游戏*****" << endl;
  275. cout << "版本号xxxxxxxxxxxxx" << endl;
  276. cout << "Copyright: CJL_sysu" << endl;
  277. cout << "****1、开始游戏****" << endl;
  278. cout << "****2、退出游戏****" << endl;
  279. cout << "****3、游戏记录****" << endl;
  280. cout << "*******************" << endl;
  281. cin >> choose;
  282. switch (choose)
  283. {
  284. case 1:
  285. {
  286. inp1:
  287. cout << "请输入雷区边长" << endl;
  288. cin >> n;
  289. if (n <= 3)
  290. {
  291. cout << "雷区边长不合法" << endl;
  292. goto inp1;
  293. }
  294. inp2:
  295. cout << "请输入地雷个数" << endl;
  296. cin >> boom;
  297. if (boom > n * n)
  298. {
  299. cout << "地雷数量过多" << endl;
  300. goto inp2;
  301. }
  302. game(n, boom);
  303. system("pause");
  304. goto home;
  305. }
  306. case 2:
  307. {
  308. break;
  309. }
  310. case 3:
  311. {
  312. ifstream ifs;
  313. ifs.open("BoomData.txt", ios::in);
  314. if (!ifs.is_open())
  315. {
  316. cout << "无历史记录" << endl;
  317. system("pause");
  318. goto home;
  319. }
  320. char buf[1024] = { 0 };
  321. while (ifs >> buf)
  322. cout << buf << endl;//按行读取
  323. ifs.close();
  324. system("pause");
  325. goto home;
  326. }
  327. default:
  328. goto home;
  329. }
  330. return 0;
  331. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/90896
推荐阅读
相关标签
  

闽ICP备14008679号