话不多说,先给出完整代码~~~
#include <iostream>
#include <sstream>
#include <ctime>
#include <limits>
#define MAX 100
#define NUM 9
#define BOOM 99
using namespace std;
int len = 10, wid = 10;
int allay_Number[MAX][MAX] = {0};
int allay_Click[MAX][MAX] = {0};
char a[] = "-";
// 初始化游戏数据
void initGame() {
// 重置雷区和点击状态数组
for (int i = 0; i < MAX; i++) {
for (int j = 0; j < MAX; j++) {
allay_Number[i][j] = 0;
allay_Click[i][j] = 0;
}
}
// 重新生成地雷
srand((unsigned int)time(NULL));
int x, y;
for (int i = 0; i < NUM; i++) {
x = rand() % 9 + 1;
y = rand() % 9 + 1;
if (allay_Number[y][x] == BOOM)
i--;
else
allay_Number[y][x] = BOOM;
}
// 重新计算数字
for (int i = 1; i <= 10; i++)
for (int j = 1; j <= 10; j++)
if (allay_Number[i][j] == BOOM) {
if (allay_Number[i - 1][j - 1] != BOOM)
allay_Number[i - 1][j - 1]++;
if (allay_Number[i - 1][j] != BOOM)
allay_Number[i - 1][j]++;
if (allay_Number[i - 1][j + 1] != BOOM)
allay_Number[i - 1][j + 1]++;
if (allay_Number[i][j - 1] != BOOM)
allay_Number[i][j - 1]++;
if (allay_Number[i][j + 1] != BOOM)
allay_Number[i][j + 1]++;
if (allay_Number[i + 1][j - 1] != BOOM)
allay_Number[i + 1][j - 1]++;
if (allay_Number[i + 1][j] != BOOM)
allay_Number[i + 1][j]++;
if (allay_Number[i + 1][j + 1] != BOOM)
allay_Number[i + 1][j + 1]++;
}
}
void createboom() {
srand((unsigned int)time(NULL));
int x, y;
for (int i = 0; i < NUM; i++) {
x = rand() % 9 + 1;
y = rand() % 9 + 1;
if (allay_Number[y][x] == BOOM)
i--;
else
allay_Number[y][x] = BOOM;
}
}
void createnum() {
for (int i = 1; i <= 10; i++)
for (int j = 1; j <= 10; j++)
if (allay_Number[i][j] == BOOM) {
if (allay_Number[i - 1][j - 1] != BOOM)
allay_Number[i - 1][j - 1]++;
if (allay_Number[i - 1][j] != BOOM)
allay_Number[i - 1][j]++;
if (allay_Number[i - 1][j + 1] != BOOM)
allay_Number[i - 1][j + 1]++;
if (allay_Number[i][j - 1] != BOOM)
allay_Number[i][j - 1]++;
if (allay_Number[i][j + 1] != BOOM)
allay_Number[i][j + 1]++;
if (allay_Number[i + 1][j - 1] != BOOM)
allay_Number[i + 1][j - 1]++;
if (allay_Number[i + 1][j] != BOOM)
allay_Number[i + 1][j]++;
if (allay_Number[i + 1][j + 1] != BOOM)
allay_Number[i + 1][j + 1]++;
}
}
void print() {
for (int i = 0; i < len; i++) {
cout << i << " ";
for (int j = 1; j <= wid - 1; j++) {
if (i == 0)
cout << j << " ";
else if (allay_Click[i][j] == 0)
cout << a[0] << " ";
else
cout << allay_Number[i][j] << " ";
}
cout << '\n';
}
}
int main() {
char restart;
do {
system("color F0");
cout << "共有9颗雷!\n";
cout << endl;
// 初始化游戏
initGame();
int x, y;
int times = 0, flag = 0;
while (1) {
cout << '\n';
cout << "雷区如下:\n";
print();
cout << '\n';
cout << "请输入要检查的位置的横纵坐标(1-9):\n";
string input;
getline(cin, input);
stringstream ss(input);
int numRead = 0;
while (ss >> x) {
numRead++;
if (numRead == 1) {
y = x;
} else if (numRead > 2) {
break;
}
}
// 检查是否输入了恰好两个整数
if (numRead != 2 || x <= 0 || x >= 10 || y <= 0 || y >= 10 || allay_Click[y][x] == 1) {
cout << '\n';
if (numRead != 2) {
cout << "输入无效,请输入两个整数!\n";
} else {
cout << "请检验将被检查的位置是否合法!\n";
}
continue;
}
cout << '\n';
if (allay_Number[y][x] == BOOM) {
system("color C7");
cout << '\a' << "失败!您被雷炸死了~~\n";
break;
} else {
allay_Click[y][x] = 1;
times++;
}
if (times == 72) {
flag = 1;
break;
}
}
if (flag == 1) {
print();
cout << "\a恭喜您获胜!\n";
system("color A7");
}
cout << "按'r'键重新开始游戏,按其他键退出:\n ";
cin >> restart;
// 清除输入缓冲区
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << '\n';
} while (restart == 'r' || restart == 'R');
return 0;
}一、引言
扫雷游戏作为一款经典的单人益智游戏,自诞生以来便广受欢迎。它不仅考验玩家的逻辑思维能力,还能帮助我们理解和掌握编程中的许多核心概念。本文将带领大家一步步用 C++ 实现一个完整的扫雷游戏,从基础设计到高级功能优化,让你全面掌握扫雷游戏的开发过程。
二、游戏设计与数据结构
2.1 游戏基本规则
扫雷游戏的规则很简单:在一个 9 × 9 的网格中,随机分布着 9 个地雷。玩家需要通过点击格子来揭开它们,如果点击到地雷,游戏失败;如果格子周围没有地雷,将会自动展开周围的格子;如果格子周围有地雷,则会显示周围地雷的数量。当玩家揭开所有非地雷格子时,游戏胜利。
2.2 数据结构设计
在 C++ 中实现扫雷游戏,我们需要设计合适的数据结构来存储游戏状态。主要使用两个二维数组:
int allay_Number[MAX][MAX] = {0}; // 存储每个格子的状态(地雷或数字)
int allay_Click[MAX][MAX] = {0}; // 存储格子是否被点击的状态
其中,allay_Number数组中,0 表示空格子,99(定义为 BOOM)表示地雷,其他数字表示周围地雷的数量。allay_Click数组中,0 表示未点击,1 表示已点击。
三、核心功能实现
3.1 初始化游戏
游戏开始时,我们需要初始化游戏数据,包括重置数组、随机生成地雷和计算每个格子周围的地雷数。
// 初始化游戏数据
void initGame() {
// 重置雷区和点击状态数组
for (int i = 0; i < MAX; i++) {
for (int j = 0; j < MAX; j++) {
allay_Number[i][j] = 0;
allay_Click[i][j] = 0;
}
}
// 重新生成地雷
srand((unsigned int)time(NULL));
int x, y;
for (int i = 0; i < NUM; i++) {
x = rand() % 9 + 1;
y = rand() % 9 + 1;
if (allay_Number[y][x] == BOOM)
i--;
else
allay_Number[y][x] = BOOM;
}
// 重新计算数字
for (int i = 1; i <= 10; i++)
for (int j = 1; j <= 10; j++)
if (allay_Number[i][j] == BOOM) {
// 检查周围8个方向的格子
if (allay_Number[i - 1][j - 1] != BOOM)
allay_Number[i - 1][j - 1]++;
if (allay_Number[i - 1][j] != BOOM)
allay_Number[i - 1][j]++;
// 其他6个方向的检查...
}
}3.2 显示游戏界面
使用print()函数显示当前游戏界面,未点击的格子显示为-,已点击的格子显示其数字或地雷。
void print() {
for (int i = 0; i < len; i++) {
cout << i << " ";
for (int j = 1; j <= wid - 1; j++) {
if (i == 0)
cout << j << " "; // 显示列号
else if (allay_Click[i][j] == 0)
cout << a[0] << " "; // 未点击的格子
else
cout << allay_Number[i][j] << " "; // 已点击的格子
}
cout << '\n';
}
}3.3 处理用户输入
在主函数中,我们需要处理用户的输入,并根据输入更新游戏状态。
int main() {
char restart;
do {
// 初始化游戏
initGame();
int x, y;
int times = 0, flag = 0;
while (1) {
// 显示游戏界面
print();
cout << "请输入要检查的位置的横纵坐标(1-9):\n";
// 读取用户输入并验证
string input;
getline(cin, input);
stringstream ss(input);
int numRead = 0;
while (ss >> x) {
numRead++;
if (numRead == 1) {
y = x;
} else if (numRead > 2) {
break;
}
}
// 验证输入是否合法
if (numRead != 2 || x <= 0 || x >= 10 || y <= 0 || y >= 10 || allay_Click[y][x] == 1) {
cout << "输入无效,请重新输入!\n";
continue;
}
// 处理用户点击
if (allay_Number[y][x] == BOOM) {
cout << "失败!您被雷炸死了~~\n";
break;
} else {
allay_Click[y][x] = 1;
times++;
}
// 检查游戏是否胜利
if (times == 72) { // 72 = 10*10 - 9 - 19(边界格子)
flag = 1;
break;
}
}
// 显示游戏结果
if (flag == 1) {
print();
cout << "恭喜您获胜!\n";
}
// 询问是否重新开始
cout << "按'r'键重新开始游戏,按其他键退出:\n ";
cin >> restart;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
} while (restart == 'r' || restart == 'R');
return 0;
}四、输入验证与错误处理
在游戏中,用户输入的合法性非常重要。我们使用字符串流来确保用户输入恰好两个整数,并处理各种异常情况。
string input;
getline(cin, input);
stringstream ss(input);
int numRead = 0;
while (ss >> x) {
numRead++;
if (numRead == 1) {
y = x;
} else if (numRead > 2) {
break;
}
}
// 检查输入是否合法
if (numRead != 2 || x <= 0 || x >= 10 || y <= 0 || y >= 10 || allay_Click[y][x] == 1) {
cout << "输入无效,请重新输入!\n";
continue;
}五、游戏体验优化
5.1 自动展开空白区域
在实际的扫雷游戏中,当点击到周围没有地雷的格子时,会自动展开周围的格子。我们可以通过递归或迭代的方式实现这一功能。
5.2 标记地雷功能
可以添加标记地雷的功能,让玩家能够标记他们认为是地雷的格子,提高游戏体验。
5.3 界面美化
使用控制台颜色和符号美化游戏界面,例如使用不同的颜色显示不同的数字,或者使用特殊字符表示地雷和旗帜。
六、总结与扩展
通过本文的学习,我们掌握了如何用 C++ 实现一个完整的扫雷游戏。从数据结构设计到核心功能实现,再到输入验证和游戏体验优化,我们一步步构建了一个功能完善的游戏。
当然,这个扫雷游戏还有很多可以扩展的地方,例如:
- 添加难度级别选择(初级、中级、高级)
- 实现计时器和最佳成绩记录
- 添加图形界面,使用图形库如 SFML 或 Qt
- 优化算法,提高游戏性能
通过不断地学习和实践,你可以进一步完善这个扫雷游戏,同时也能提高自己的 C++ 编程水平。希望本文能为你提供一个良好的起点,让你在编程的道路上越走越远。
做了几十年的项目 总结最好的
好
好
好
好
好