赞
踩
目录
终于期末了,我们很难不用学过的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变量),做差就是游戏时间。
第三步:实现主页面和游戏记录,没什么技术含量,不解释了。
- #include<iostream>
- #include<vector>
- #include<algorithm>
- #include<iomanip>
- #include<ctime>
- #include<fstream>
- #define Jin '#'//代表未开启的区域
- #define Jia '+'//用于标记有雷
- using namespace std;//以下初始化二维数组的指针为全局变量
- char** gra = NULL;//该指针指向的二维数组存放游戏画面
- int** arr = NULL;//该指针指向的二维数组存放有雷(9)或无雷(10)两种情况
- int** ar = NULL;//该指针指向的二维数组存放有雷(9)或无雷时其周围九格区域的雷数
- void file(int m, unsigned int time)
- {
- ofstream ofs;
- ofs.open("BoomData.txt", ios::app);
- if (m == 0)
- ofs << "游戏失败,用时" << time << "秒" << endl;
- else
- ofs << "游戏成功,用时" << time << "秒" << endl;
- ofs.close();
- }
- int kopen(int x,int y)//快捷标记打开函数
- {
- void open(int x, int y);
- void open1(int x, int y);
- if (gra[x][y] == Jia)
- return 0;
- else
- {
- if (arr[x][y] == 9)
- return 1;//发现有雷
- else if (ar[x][y] == 0)//周围无雷时递归地开启周围的八格
- open(x, y);
- else
- open1(x, y);//周围有雷时只开启本格
- return 0;
- }
- }
- void open1(int x, int y)//遇到非0的函数实现,不允许开启的部分继续开启周围八格
- {
- gra[x][y] = ar[x][y] + 48;
- }
- void open(int x, int y)
- {
- gra[x][y] = ar[x][y] + 48;//生成数字,展示在屏幕上
- if (ar[x - 1][y] == 0 && gra[x - 1][y] == Jin)
- open(x - 1, y);
- if (ar[x][y - 1] == 0 && gra[x][y - 1] == Jin)
- open(x, y - 1);
- if (ar[x][y + 1] == 0 && gra[x][y + 1] == Jin)
- open(x, y + 1);
- if (ar[x + 1][y] == 0 && gra[x + 1][y] == Jin)
- open(x + 1, y);
- if (ar[x - 1][y - 1] == 0 && gra[x - 1][y - 1] == Jin)
- open(x - 1, y - 1);
- if (ar[x - 1][y + 1] == 0 && gra[x - 1][y + 1] == Jin)
- open(x - 1, y + 1);
- if (ar[x + 1][y - 1] == 0 && gra[x + 1][y - 1] == Jin)
- open(x + 1, y - 1);
- if (ar[x + 1][y + 1] == 0 && gra[x + 1][y + 1] == Jin)
- open(x + 1, y + 1);
- //遇到0时自动开启周围八格,并且开启的部分继续开启周围八格
- if (ar[x - 1][y] > 0 && ar[x - 1][y] < 9 && gra[x - 1][y] == Jin)
- open1(x - 1, y);
- if (ar[x][y - 1] > 0 && ar[x][y - 1] < 9 && gra[x][y - 1] == Jin)
- open1(x, y - 1);
- if (ar[x][y + 1] > 0 && ar[x][y + 1] < 9 && gra[x][y + 1] == Jin)
- open1(x, y + 1);
- if (ar[x + 1][y] > 0 && ar[x + 1][y] < 9 && gra[x + 1][y] == Jin)
- open1(x + 1, y);
- if (ar[x - 1][y - 1] > 0 && ar[x - 1][y - 1] < 9 && gra[x - 1][y - 1] == Jin)
- open1(x - 1, y - 1);
- if (ar[x - 1][y + 1] > 0 && ar[x - 1][y + 1] < 9 && gra[x - 1][y + 1] == Jin)
- open1(x - 1, y + 1);
- if (ar[x + 1][y - 1] > 0 && ar[x + 1][y - 1] < 9 && gra[x + 1][y - 1] == Jin)
- open1(x + 1, y - 1);
- if (ar[x + 1][y + 1] > 0 && ar[x + 1][y + 1] < 9 && gra[x + 1][y + 1] == Jin)
- open1(x + 1, y + 1);
- //遇到非0时自动开启周围八格,不允许开启的部分继续开启周围八格
- }
- void printgraph(int n)//用于打印游戏界面
- {
- system("cls");
- for (int i = 0; i <= n; i++)
- cout << setw(2) << setfill('0') << i << " ";
- cout << endl;
- for (int i = 1; i <= n; i++)
- {
- cout << setw(2) << setfill('0') << i << " ";
- for (int j = 1; j <= n; j++)
- {
- cout << gra[i][j] << " ";
- }
- if (i == 1)
- cout << " 操作'1'代表标记安全";
- if (i == 2)
- cout << " 操作'2'代表标记有雷";
- if (i == 3)
- cout << " 操作'3'取消标记有雷";
- if (i == 4)
- cout << " 操作'4'快捷标记安全(自动标记周围八格)";
- cout << endl;
- }
- cout << "请输入:(用空格隔开)" << endl;
- cout << "行 列 操作" << endl;
- }
- void game(int n, int boom)
- {
- srand((unsigned int)time(NULL));
- unsigned int gametimestart = (unsigned int)time(NULL);//记录游戏开始的时间
- cout << "游戏正在加载中,请等待" << endl;
- arr = new int*[n+2];
- for (int i = 0; i < n+2; i++)
- arr[i] = new int[n+2];//定义二维数组arr
- ar = new int* [n + 2];
- for (int i = 0; i < n + 2; i++)
- ar[i] = new int[n + 2];//定义二维数组ar
- for (int i = 0; i < n + 2; i++)
- {
- arr[0][i] = 10;
- arr[n + 1][i] = 10;
- arr[i][0] = 10;
- arr[i][n + 1] = 10;//初始化边缘无雷
- ar[0][i] = 10;
- ar[n + 1][i] = 10;//10表示无雷
- ar[i][0] = 10;
- ar[i][n + 1] = 10;
- }
- vector<int>v;
- v.resize(n * n, 10);
- for (vector<int>::iterator it = v.begin(); it < v.begin() + boom; it++)
- *it = 9;//9表示有雷
- random_shuffle(v.begin(),v.end());//随机生成n个位置夹杂boom个雷的排列
- for (int i = 0; i < n * n; i++)
- arr[i / n + 1][i % n + 1] = v[i];//将雷填充入二维数组arr
- for (int i = 1; i <= n; i++)
- {
- for (int j = 1; j <= n; j++)//遍历二维数组arr每个位置
- {
- if (arr[i][j] == 9)//如果是雷,遍历下一个位置
- ar[i][j] = 9;
- else
- {
- ar[i][j] = arr[i][j] + arr[i - 1][j - 1] + arr[i - 1][j] + arr[i - 1][j + 1]
- + arr[i][j - 1] + arr[i][j + 1] + arr[i + 1][j - 1] + arr[i + 1][j]
- + arr[i + 1][j + 1];
- ar[i][j] = 90 - ar[i][j];//如果不是雷,计算其周边八格雷的个数,并赋值给ar
- }
- }
- }
- gra = new char* [n + 2];
- for (int i = 0; i < n + 2; i++)
- gra[i] = new char[n + 2];//定义用于显示游戏页面的二维数组gra
- for (int i = 1; i <= n; i++)
- {
- for (int j = 1; j <= n; j++)
- {
- gra[i][j] = Jin;//初始化用Jin填充
- }
- }
- int x, y, z, m1 = 0,right=0;
- another:
- printgraph(n);
- cin >> x >> y >> z;//输入三数以操作
- if (!(x >= 1 && x <= n && y >= 1 && y <= n))//判断坐标是否合法
- {
- cout << "输入坐标错误" << endl;
- system("pause");
- goto another;
- }
- if (z == 1 && gra[x][y] == Jin)
- {
- if (ar[x][y] == 10)
- return;
- if (ar[x][y] == 9)
- {
- fail:
- system("cls");//此处游戏失败,显示所有的雷
- unsigned int gametimeend = (unsigned int)time(NULL);
- for (int i = 0; i <= n; i++)
- cout << setw(2) << setfill('0') << i << " ";
- cout << endl;
- for (int i = 1; i <= n; i++)
- {
- cout << setw(2) << setfill('0') << i << " ";
- for (int j = 1; j <= n; j++)
- {
- if (ar[i][j] == 9)
- cout << '*' << " ";
- else
- cout << ar[i][j] << " ";
- }
- cout << endl;
- }
- unsigned int gametime = gametimeend - gametimestart;
- cout << "你没了" << endl;
- cout << "本次游戏用时" << gametime << "秒" << endl;//输出游戏时间
- file(0, gametime);//游戏记录写入文件
- return;
- }
- else
- {
- gra[x][y] = ar[x][y] + 48;
- if (ar[x][y] == 0)
- {
- open(x, y);
- }
- }
- }
- else if (z == 2 && gra[x][y] == Jin)
- {
- gra[x][y] = Jia;
- m1++;
- right = (ar[x][y] == 9) ? (right + 1) : right;
- }
- else if (z == 3 && gra[x][y] == Jia)
- {
- gra[x][y] = Jin;
- m1--;
- right = (ar[x][y] == 9) ? (right - 1) : right;
- }
- else if (z == 4 && gra[x][y] != Jin && gra[x][y] != Jia)//快捷标记安全实现
- {
- int jnum=0;
- jnum = (gra[x - 1][y - 1] == Jia ? jnum + 1 : jnum);
- jnum = (gra[x - 1][y] == Jia ? jnum + 1 : jnum);
- jnum = (gra[x - 1][y + 1] == Jia ? jnum + 1 : jnum);
- jnum = (gra[x][y - 1] == Jia ? jnum + 1 : jnum);
- jnum = (gra[x][y + 1] == Jia ? jnum + 1 : jnum);
- jnum = (gra[x + 1][y - 1] == Jia ? jnum + 1 : jnum);
- jnum = (gra[x + 1][y] == Jia ? jnum + 1 : jnum);
- jnum = (gra[x + 1][y + 1] == Jia ? jnum + 1 : jnum);//统计周围标记有雷点个数
- if (jnum != ar[x][y])
- {
- cout << "不符合快捷标记条件,周围标记雷数与实际雷数不等" << endl;
- system("pause");
- }
- else
- {
- int failnum=0;//检查是否踩雷
- failnum += kopen(x - 1, y - 1);
- failnum += kopen(x - 1, y);
- failnum += kopen(x - 1, y + 1);
- failnum += kopen(x, y - 1);
- failnum += kopen(x, y + 1);
- failnum += kopen(x + 1, y - 1);
- failnum += kopen(x + 1, y);
- failnum += kopen(x + 1, y + 1);
- if (failnum != 0)
- goto fail;
- }
- }
- if (m1 == boom&&right==boom)//采用m1(标记点个数)和right(正确点个数)判断是否赢了
- {
- printgraph(n);
- cout << "你赢了" << endl;
- unsigned int gametimeend = (unsigned int)time(NULL);
- unsigned int gametime = gametimeend - gametimestart;//输出游戏时间
- cout << "本次游戏用时" << gametime << "秒" << endl;
- file(1, gametime);//游戏记录写入文件
- return;
- }
- goto another;
- }
- int main()
- {
- system("color 3F");//设置游戏界面颜色
- system("title 扫雷3.0");
- int choose, n, boom;
- home:
- system("cls");
- cout << "*******************" << endl;
- cout << "******扫雷游戏*****" << endl;
- cout << "版本号xxxxxxxxxxxxx" << endl;
- cout << "Copyright: CJL_sysu" << endl;
- cout << "****1、开始游戏****" << endl;
- cout << "****2、退出游戏****" << endl;
- cout << "****3、游戏记录****" << endl;
- cout << "*******************" << endl;
- cin >> choose;
- switch (choose)
- {
- case 1:
- {
- inp1:
- cout << "请输入雷区边长" << endl;
- cin >> n;
- if (n <= 3)
- {
- cout << "雷区边长不合法" << endl;
- goto inp1;
- }
- inp2:
- cout << "请输入地雷个数" << endl;
- cin >> boom;
- if (boom > n * n)
- {
- cout << "地雷数量过多" << endl;
- goto inp2;
- }
- game(n, boom);
- system("pause");
- goto home;
- }
- case 2:
- {
- break;
- }
- case 3:
- {
- ifstream ifs;
- ifs.open("BoomData.txt", ios::in);
- if (!ifs.is_open())
- {
- cout << "无历史记录" << endl;
- system("pause");
- goto home;
- }
- char buf[1024] = { 0 };
- while (ifs >> buf)
- cout << buf << endl;//按行读取
- ifs.close();
- system("pause");
- goto home;
- }
- default:
- goto home;
- }
- return 0;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。