时间:2022-10-26 09:56:56 | 栏目:C代码 | 点击:次
本文实例为大家分享了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; }