当前位置:首页 > 通信资讯 > 正文

c++ 扫雷游戏(扫雷小游戏c++代码设计)

本文为大家分享了C++实现扫雷小游戏的具体代码,供大家参考,具体内容如下

程序功能:

提供三种模式:初级、中级、高级

操作模式:wsad控制光标移动,空格键打开方块

提供扫雷地图的类

map.h

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #ifndef MAP_H_ #define MAP_H_ #define MAX_LENGTH 32 //可以提供的地图最大长度 #define MAX_WIDTH 18 //可以提供的地图最大宽度 #define UP_EDGE 1 //上边界 #define DOWN_EDGE _wid //下边界 #define LEFT_EDGE 1 //左边界 #define RIGHT_EDGE _lng //右边界 void gotoxy(int, int); //移动光标的接口函数 struct Position{ int x; int y; }; struct Info{ int n; //用于标记雷、数字、空格的属性 bool flag; //用于标记是否要打开方块 }; class Map{ private: int _lng, _wid; //长和宽 int _mines, _blanks; //雷数、未开启空格数目 Position _pos = {1, 1}; //光标位置 Info data[MAX_WIDTH][MAX_LENGTH]; //包含地图信息的矩阵 public: void AcceptCond(); //选择模式 void InitMap(); //初始化地图 void SetMine(); //布置地雷 void SetNumber(); //计算数字 void SetPosition(); //移动光标至指示区域 void ResetPosition(); //重置初始坐标 void ShowMap(); //显示地图 void ShowAll(); //显示全部地图,游戏失败时候调用 void OpenBlock(); //打开方块,即将 flag 值设置为 true,在 ShowMap() 中将打开方块 void FirstStep(); //预先处理游戏,防止第一步就触雷导致失败,这是无意义的 bool PlayGame(); //提供的游戏操作接口 bool Move(char); //移动光标,同时改变 _pos 的值用于指代目前要访问(打开)的方块 bool IfLose(); //游戏失败,则返回真 bool IfWin(); //游戏成功,则返回真 }; #endif

实现思路:

1.接收游戏模式参数,确定地图规模

2.初始化地图,值全部设置为 0,flag 全部设置为 false,表示未曾打开

3.根据用户操作,确定要打开的第一个空格的,然后再开始布雷,避免开局触雷结束,这样没什么意义。

4.布雷采用生成随机数的方法

5.根据地雷分布计算其他空格所对应的数字

6.通过PlayGame() 接口进行游戏操作

Map类的实现

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 #include <cstdlib> #include <cstdio> #include <ctime> //提供时间函数 #include <conio.h> //提供getch() #include <windows.h> #include <iostream> #include "map.h" #define GOTO(pos) gotoxy(2 * (pos.x) - 1, (pos.y) - 1) //定义用于移动光标的 宏 //由于一个方块占 2 个格子,所以 pos.x 每加 1,则光标要移动 2 格 using std::cout; using std::cin; using std::endl; void gotoxy(int x, int y) { //移动光标的接口 COORD pos = { short(x), short(y) }; HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleCursorPosition(hOut, pos); } void Map::AcceptCond() { //接收游戏模式参数 cout << "Choose Mode" << endl; cout << "1 : Beginner" << endl; cout << "2 : Intermediate" << endl; cout << "3 : Expert" << endl << "Mode: "; char mode; cin >> mode; while (('1' != mode) && ('2' != mode) && ('3' != mode)) { //仅仅接受 1, 2, 3,其他字符跳过 cout << "Wrong Mode, Enter number again\n Mode: "; cin >> mode; } switch (mode) { case '1' : _lng = 8; _wid = 8; _mines = 10; break; case '2' : _lng = 16; _wid = 16; _mines = 40; break; default: _lng = 30; _wid = 16; _mines = 99; } _blanks = _lng * _wid - _mines; //计算空格数,用于判断是否赢,_blanks = 0 时判定赢 } void Map::InitMap() { //初始化地图,显示的地图下标从 1 - wid, 1 - _lng, 边界外面还有空格,用于计算空格对应数字的,边界相当于0 for (int i = 0; i < _wid + 2; i++) { for (int j = 0; j < _lng + 2; j++) { data[i][j].n = 0; data[i][j].flag = false; } } } void Map::SetMine() { int i, j; int m = _mines; srand(time(NULL)); while (m) { i = rand() % _wid + 1; j = rand() % _lng + 1; if ((-1 != data[i][j].n) && (j != _pos.x && i != _pos.y)) { //后面的条件用于避免用户第一个打开的空格处布置地雷 data[i][j].n = -1; m--; } } } void Map::SetNumber() { for (int i = 1; i <= _wid; i++) { for (int j = 1; j <= _lng; j++) { //依次检查周围的 8 个空格的雷数 if (-1 == data[i][j].n) continue; if (-1 == data[i-1][j-1].n) data[i][j].n++; if (-1 == data[i][j-1].n) data[i][j].n++; if (-1 == data[i+1][j-1].n) data[i][j].n++; if (-1 == data[i-1][j].n) data[i][j].n++; if (-1 == data[i+1][j].n) data[i][j].n++; if (-1 == data[i-1][j+1].n) data[i][j].n++; if (-1 == data[i][j+1].n) data[i][j].n++; if (-1 == data[i+1][j+1].n) data[i][j].n++; } } } void Map::SetPosition() { GOTO(_pos); } void Map::ResetPosition() { _pos.x = _pos.y = 1; } void Map::ShowMap() { system("cls"); //清屏 system("color 03"); //调整控制台显示颜色 SetConsoleOutputCP(437); //使方块能够正常显示 for (int i = 1; i <= _wid; i++) { cout << '|'; //左边界 for (int j = 1; j <= _lng; j++) { if (data[i][j].flag) { switch (data[i][j].n) { case 0 : cout << " "; break; //由于方块占两个格子,因此其他的输出,如空格、数字等也要占2个格子,对齐 default: cout << data[i][j].n << ' '; } } else printf("%c", 219); } cout << '|' << endl; //右边界 } gotoxy(0, _wid+2); //在地图下方输出坐标信息和空格数 printf("Position : (%d, %d)\n Blanks : %d", _pos.x, _pos.y, _blanks); GOTO(_pos); //归位到原先地图坐标对应的位置 } void Map::ShowAll() { //类似上面的ShowMap(),但在游戏失败时调用 system("cls"); system("color 03"); SetConsoleOutputCP(437); for (int i = 1; i <= _wid; i++) { cout << '|'; for (int j = 1; j <= _lng; j++) { switch (data[i][j].n) { case 0 : printf("%c", 219); break; case -1: if (i == _pos.y && j == _pos.x) cout << "X "; else cout << "* "; break; default: cout << data[i][j].n << ' '; } } cout << '|' << endl; } } #define SOLVE_IT(t) {stack[++top] = (t); data[(t).y][(t).x].flag = true; _blanks--;} #define FALSE_FLAG(t) !data[(t).y][(t).x].flag void Map::OpenBlock() { //用栈来将连着的空格区域遍历一遍,并将其 flag 值置为 true if (data[_pos.y][_pos.x].flag) return; //如果已经打开过就不需要再次打开,否则 _blanks--; 会多次执行,无法判断赢 Position stack[_lng * _wid << 1]; Position t; int top = 0; stack[top] = _pos; data[_pos.y][_pos.x].flag = true; _blanks--; while (top != -1) { t = stack[top--]; if (0 == data[t.y][t.x].n) { //如果该位置为 0 ,那么它周围的格子都要打开 t.y--; //判断上方三个格子 if (t.y >= UP_EDGE) { //如果上方三个格子 y 不越界 if (FALSE_FLAG(t)) SOLVE_IT(t) t.x--; if (t.x >= LEFT_EDGE && FALSE_FLAG(t)) SOLVE_IT(t) t.x += 2; if (t.x <= RIGHT_EDGE && FALSE_FLAG(t)) SOLVE_IT(t) t.x--; } t.y++; t.x--;//判断左右两个格子, 此时 t.y 复原 if (t.x >= LEFT_EDGE && FALSE_FLAG(t)) SOLVE_IT(t) t.x += 2; if (t.x <= RIGHT_EDGE && FALSE_FLAG(t)) SOLVE_IT(t) t.y++; //下方三个格子, 此时 t.x 是最右边的格子 if (t.y <= DOWN_EDGE) { //如果下方三个格子 y 不越界, 与上面判断基本相同 if (t.x <= RIGHT_EDGE && FALSE_FLAG(t)) SOLVE_IT(t) t.x--; if (FALSE_FLAG(t)) SOLVE_IT(t) t.x--; if (t.x >= LEFT_EDGE && FALSE_FLAG(t)) SOLVE_IT(t) } } } } void Map::FirstStep() { //函数结束后将改变 _pos,就是我们用的预先处理函数,防止第一步就触雷的 char op; do { op = getch(); while ((op != 'a') && (op != 's') && (op != 'd') && (op != 'w') && (op !=' ')) op = getch(); } while (Move(op)); } bool Map::Move(char op) { switch (op) { //通过不同的操作,改变坐标,然后再通过 GOTO宏 移动到该位置上 case ' ': return false; case 'w': if (UP_EDGE != _pos.y) _pos.y--; break; case 'a': if (LEFT_EDGE != _pos.x) _pos.x--; break; case 's': if (DOWN_EDGE != _pos.y) _pos.y++; break; default: if (RIGHT_EDGE != _pos.x) _pos.x++; } gotoxy(0, _wid + 2); printf("Position : (%d, %d)\n Blanks : %d", _pos.x, _pos.y, _blanks); GOTO(_pos); return true; } bool Map::IfLose() { return -1 == data[_pos.y][_pos.x].n; } bool Map::IfWin() { return 0 == _blanks; } bool Map::PlayGame() { char op; float start, end; while (!IfWin()) { do { op = getch(); while ((op != 'a') && (op != 's') && (op != 'd') && (op != 'w') && (op !=' ')) op = getch(); } while (Move(op)); if (IfLose()) { //触雷 ShowAll(); gotoxy (0, _wid + 3); return false; } else { OpenBlock();   //打开方块,实质上时将 flag 的值置为 true,接着 ShowMap()将可以显示该方块信息 ShowMap(); GOTO(_pos); } } gotoxy(0, _wid + 3); return true; }

主程序

mineweeper.cpp

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include <iostream> #include <cstdlib> #include <conio.h> #include <ctime> #include "map.h" using namespace std; int main() { Map game; float start, end; char ch; while (1) { game.AcceptCond(); //选择模式 game.InitMap(); //初始化 game.ShowMap(); //显示地图。 注:此时地图未生成完毕 game.FirstStep(); //预处理,防止第一步就触雷结束 game.SetMine(); //设置地雷 game.SetNumber(); //根据地雷分布计算数字 game.OpenBlock(); //打开开局预先想要打开的第一个空 start = clock(); game.ShowMap(); if (game.PlayGame()) { //根据PlayGame()接口的返回值判定输赢 cout << endl << "~ Congratulation ~\n ~ You Win ~" << endl; } else { cout << endl << "BOOM!!! ~ Game Over ~\n" << endl; } end = clock(); printf("\nTime : %.2f\n", (end - start) / CLK_TCK); //输出游戏所用时间 cout << endl << "Please enter 'q' to quit, or any other keys to continue" << endl; game.SetPosition(); //用于触雷失败时,将光标返回到触雷的位置,提示哪一步失败,同时触碰的雷也将显示为 ‘X' ch = getch(); if ('q' == ch) { // q 用于退出游戏 system("cls"); cout << "~ Bye ~" << endl; break; } else { game.ResetPosition(); system("cls"); } } system("pause"); return 0; }

游戏截图

c++ 扫雷游戏(扫雷小游戏c++代码设计)

c++ 扫雷游戏(扫雷小游戏c++代码设计)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/qq_35215641/article/details/80704045

如果您对该产品感兴趣,请填写办理(客服微信:xiaoxiongyidong)

为您推荐:

发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。