本文实例为大家分享了C++控制台实现扫雷游戏的具体代码,供大家参考,具体内容如下
花了一下午写出来的控制台扫雷,主要通过修改和打印数组来实现。
主要的问题点:
1.在显示地图的过程中,既要显示数字,又要显示雷和符号,所以的用string类型的二维向量,vector<vector<string.>>;中间要利用ASCII码将int型的数字转化为字符串。
2.生成地图的时候,雷是随机的,我这里采用的做法是取余生成雷,举个例子,如果雷数是格子数的十分之一,那我遍历整个二维数组,在rand()%8 == 0时放置一颗雷,当放置10颗之后停止,这样可能会导致我的雷都偏前面一点,哈哈。
3.对于没有雷的格子,需要做一个遍历,统计周边的雷数,为了方便,实际地图要大一圈,实际的边长+2,边不作为地图,只为统计雷数时方便存在。
4.当点开一颗雷之后,如果数字是0,那么四周为0的数字也要被点亮,因此在这里使用递归实现dfs。
5.在每次进行一个格子操作之后,使用一个count计数,所有格子操作完后,游戏结束统计游戏结果,在此之前,踩到雷也会导致游戏结束。
附上游戏截图和代码
主函数
#include<vector>
#include<algorithm>
#include<functional>
#include<iostream>
#include<windows.h>
#include"gameManager.h"
#include"map.h"
using namespace std;
int main() {
GameManager* game = new GameManager();
while (true) {
int diff = game->difficultNumber();//玩家的难度选择参数
Map* m = new Map(diff);
m->initMap();
while (true) {
m->showMap();
int swicth;
cout << "1.踩雷" << endl;
cout << "2.插旗子" << endl;
cout << "3.取消插旗子" << endl;
cin >> swicth;
if (swicth == 1) {
//踩雷;如果踩到雷了返回1,没踩到返回0
if (game->stepOnMine(m)) break;
}
else if (swicth == 2) {
//插旗子
game->flagMine(m);
}
else if (swicth == 3) {
//取消插旗子
game->cancelFalgMine(m);
}
else {
cout << "您的输入有误!" << endl;
}
//判断格子是否被开完,开完了则取胜
if (m->gameOver()) {
cout << "恭喜你获得胜利!" << endl;
m->showMap();
break;
}
}
int over = 0;
cout << "1.回到主菜单" << endl;
cout << "other.退出游戏" << endl;
cin >> over;
if (over == 1) {
system("cls");
continue;
}
else break;
}
system("pause");
return 0;
}
map类
头文件
```cpp
#pragma once
#include<ctime>
#include <vector>
#include<string>
#include <iostream>
using namespace std;
class Map {
public:
Map(int);//根据难度构造地图
void initMap();//根据难度初始化地图
string aroudMineNum
(const vector<vector<string>>&, const int&, const int&) const;//判断某个坐标桌边的雷数
void showMap();//打印showMapArray数组
int dateUpMap(const int&, const int&);//如果返回值为1,继续,返回值为0表示结束,如果返回值为-1表示非法输入
int flag(const int&, const int&);//插旗子修改显示数组
int cancelFlag(const int&, const int&);//取消旗子时修改显示数组
bool gameOver();
private:
int mapCount;//格子用完的计数
int difficult;//难度
vector<vector<string>> map;//隐藏的雷表
vector<vector<string>> showMapArray;//公开的显示数组
};
源文件
#include"map.h"
Map::Map(int difficult) :
difficult(difficult),
mapCount(difficult* difficult)
{
}
//初始化地图数组
void Map::initMap()
{
//根据难度设置二维数组的大小以及雷的数量
int mineNumber = difficult * difficult * 10;//雷的数量
int size = 10 * difficult;//此处尺寸加2,四边都为零,这样方便统计没有雷的格子上的数据
srand(time(0));
//使用随机数设置雷的数量
for (int i = 0; i < size + 2; ++i) {
vector<string> temp;
for (int j = 0; j < size + 2; ++j) {
if (rand() % 8 == 0 && mineNumber != 0 && i != 0 && j != 0 && i != size - 1 && j != size - 1) {
temp.push_back("*");
--mineNumber;
}
else {
temp.push_back("0");
}
}
map.push_back(temp);
}
//此外还需要根据雷的位置和数量在其他位置上提示!
for (int i = 1; i < size - 1; ++i) {
for (int j = 1; j < size - 1; ++j) {
if (map[i][j] != "*") {
map[i][j] = aroudMineNum(map, i, j);
}
}
}
//初始化显示显示数组,注意!此数组要显示行列数,所以比上述数组多一行一列
for (int i = 0; i < size + 1; ++i) {
vector<string> temp;
for (int j = 0; j < size + 1; ++j) {
if (i == 0) {
string t;
if (j < 10) {
t.push_back(48);
t.push_back(j + 48);
}
else if (j < 20) {
t.push_back(49);
t.push_back(j + 38);
}
else if (j < 30) {
t.push_back(50);
t.push_back(j + 28);
}
else {
t.push_back('3');
t.push_back('0');
}
temp.push_back(t);
}
else if (j == 0) {
string t;
if (i < 10) {
t.push_back(48);
t.push_back(i + 48);
}
else if (i < 20) {
t.push_back(49);
t.push_back(i + 38);
}
else if (i < 30) {
t.push_back(50);
t.push_back(i + 28);
}
else {
t.push_back('3');
t.push_back('0');
}
temp.push_back(t);
}
else temp.push_back(" #");
}
showMapArray.push_back(temp);
}
}
//判断自身格子上的数字为多少
string Map::aroudMineNum(const vector<vector<string>>& map, const int& i, const int& j) const
{
int count = 0;
string ans;
for (int x = i - 1; x <= i + 1; ++x) {
for (int y = j - 1; y <= j + 1; ++y) {
if (map[x][y] == "*") {
++count;
}
}
}
ans.push_back(48);
ans.push_back(count + 48);
return ans;
}
//按照地图数组显示画面
void Map::showMap()
{
int sideLength = showMapArray.size();
for (int i = 0; i < sideLength; ++i) {
for (int j = 0; j < sideLength; ++j) {
cout << showMapArray[i][j] << " ";
}
cout << endl;
}
}
int Map::dateUpMap(const int& x, const int& y)
{
//判断xy的值只能在0-30之间difficult*10
if (x < 1 || x >= (difficult * 10) || y < 0 || y >= (difficult * 10)) return -1;
//判断坐标是否已经被翻开,若被翻开,则输入非法,返回-1
if (showMapArray[x][y] != " #") return -1;
//如果该点有雷,则把该点的雷翻出来,显示游戏失败
if (map[x][y] == "*") {
showMapArray[x][y] = " *";
return 0;
}
//如果该点的数字大于0,则只把单一数字翻出来
else if (map[x][y] != "00") {
string temp;
temp.append(map[x][y]);
showMapArray[x][y] = temp;
--mapCount;//格子数减少统计,当格子数为0时判断游戏胜利!
}
//如果该点的数字为0,则把附近为0的点全部翻出来,直到翻出数字为止
else {
if (showMapArray[x][y] != " Q") {
--mapCount;//格子数减少统计,当格子数为0时判断游戏胜利!
showMapArray[x][y] = "00";
}
if (showMapArray[x][y] == " Q" && map[x][y] == "*") {
showMapArray[x][y] = " *";
return -1;
}
for (int i = x - 1; i <= x + 1; ++i) {
for (int j = y - 1; j <= y + 1; ++j) {
if (!(i == x && j == y) && i > 0 && i < (difficult * 10) && j > 0 && j < (difficult * 10)) {
dateUpMap(i, j);
}
}
}
return 1;
}
}
int Map::flag(const int& x, const int& y)
{
if (showMapArray[x][y] != " #") return -1;
else {
--mapCount;//格子数减少统计,当格子数为0时判断游戏胜利!
showMapArray[x][y] = " Q";
}
return 0;
}
int Map::cancelFlag(const int& x, const int& y)
{
if (showMapArray[x][y] != " Q") return -1;
else {
++mapCount;//格子数增加统计,当格子数为0时判断游戏胜利!
showMapArray[x][y] = " #";
}
return 0;
}
bool Map::gameOver()
{
if (mapCount == 0) return true;
return false;
}
gameManager类
头文件
#pragma once
#include<iostream>
#include<windows.h>
#include"map.h"
using namespace std;
class GameManager {
public:
void showMenu();//显示主菜单
int difficultNumber();//选择难度
int stepOnMine(Map * m);//踩雷
int flagMine(Map* m);//插旗子
int cancelFalgMine(Map * m);//取消旗子
};
源文件
#include"gameManager.h"
#include"map.h"
void GameManager::showMenu()
{
cout << "***************主菜单***************" << endl;
cout << "************1.简单模式**************" << endl;
cout << "************2.中等模式**************" << endl;
cout << "************3.困难模式**************" << endl;
cout << "**********请输入你的选择************" << endl;
}
int GameManager::difficultNumber()
{
int diff = 0;
while (diff != 1 && diff != 2 && diff != 3) {
this->showMenu();
cin >> diff;
}
return diff;
}
int GameManager::stepOnMine(Map* m)
{
int x, y;
cout << "请输入你想排雷的坐标:" << endl;
cout << "x:" << endl;
cin >> x;
cout << "y:" << endl;
cin >> y;
int result = m->dateUpMap(x, y);
system("cls");
if (result == -1) {
cout << "您的输入有误,请重新输入!" << endl;
}
else if (result == 0) {
cout << "你踩到雷啦!" << endl;
Sleep(300);
cout << "游戏即将结束!" << endl;
Sleep(300);
cout << "5!" << endl;
Sleep(300);
cout << "4!" << endl;
Sleep(300);
cout << "3!" << endl;
Sleep(300);
cout << "2!" << endl;
Sleep(300);
cout << "1!" << endl;
m->showMap();
system("pause");
return 1;
}
return 0;
}
int GameManager::flagMine(Map* m)
{
//插旗子
int x, y;
cout << "请输入你想插旗子的坐标:" << endl;
cout << "x:" << endl;
cin >> x;
cout << "y:" << endl;
cin >> y;
int result = m->flag(x, y);
system("cls");
if (result == -1) {
cout << "此处不能插旗子!" << endl;
}
else
cout << "插旗子成功!" << endl;
return 0;
}
int GameManager::cancelFalgMine(Map* m)
{
int x, y;
cout << "请输入你想取消旗子的坐标:" << endl;
cout << "x:" << endl;
cin >> x;
cout << "y:" << endl;
cin >> y;
int result = m->cancelFlag(x, y);
system("cls");
if (result == -1) {
cout << "此处没有旗子可以取消!" << endl;
}
else {
cout << "取消旗子成功!" << endl;
}
return 0;
}