自制c++扫雷
2026-08-19 20:05:16
发布于:广东
#include<bits/stdc++.h>
#include<windows.h>
using namespace std;
typedef long long ll;
ll x,y;
bool cai = false;
char mp[9][9];
ll gm[9][9];
ll s = 10;//胜利条件
ll cnt = 71;//统计未翻开数量
ll ans;//统计地雷数量
ll js(ll x,ll y){//计算雷的数量
ll c = 0;
for(ll i = x - 1;i <= x + 1;i++){
for(ll j = y - 1;j <= y + 1;j++){
if(i >= 0 && i < 9 && j >= 0 && j < 9){
if(i == x && j == y) continue;// 跳过自己这个格子
if(gm[i][j] == -1){
c++;
}
}
}
}
return c;
}
void open(ll x,ll y){
if(x < 0 || x >= 9 || y < 0 || y >= 9)return;
if(mp[x][y] != '#')return;
if(gm[x][y] == -1)return;
ll c = js(x,y);
mp[x][y] = char(c + '0');
cnt--;
if(c == 0){
for(ll i = x - 1;i <= x + 1;i++){
for(ll j = y - 1;j <= y + 1;j++){
open(i,j);// 递归翻开周围格子
}
}
}
}
void drawMap(bool showmap) {
HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
system("cls");
if(showmap){
cout << " ";
for(ll i = 1;i <= 9;i++){
SetConsoleTextAttribute(h, FOREGROUND_BLUE | FOREGROUND_INTENSITY);
cout << i << ' ';
SetConsoleTextAttribute(h, 7);
}
cout << '\n';
for(ll i = 0;i < 9;i++){
SetConsoleTextAttribute(h, FOREGROUND_BLUE | FOREGROUND_INTENSITY);
cout << i + 1 << ' ';
SetConsoleTextAttribute(h, 7);
for(ll j = 0;j < 9;j++){
if(gm[i][j] == -1){
SetConsoleTextAttribute(h, FOREGROUND_RED | FOREGROUND_INTENSITY);
cout << "* ";
}else{
SetConsoleTextAttribute(h, FOREGROUND_GREEN | FOREGROUND_INTENSITY);
cout << char(js(i, j) + '0') << ' ';
}
}
cout << '\n';
}
}
else{
cout << " ";
for(ll i = 1;i <= 9;i++){
SetConsoleTextAttribute(h, FOREGROUND_BLUE | FOREGROUND_INTENSITY);
cout << i << ' ';
SetConsoleTextAttribute(h, 7);
}cout << '\n';
for(ll i = 0;i < 9;i++){
SetConsoleTextAttribute(h, FOREGROUND_BLUE | FOREGROUND_INTENSITY);
cout << i + 1 << ' ';
SetConsoleTextAttribute(h, 7);
for(ll j = 0;j < 9;j++){
if(mp[i][j] == 'F'){
SetConsoleTextAttribute(h, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
cout << mp[i][j] << ' ';
SetConsoleTextAttribute(h, 7);
}else if(mp[i][j] == '#'){
cout << mp[i][j] << ' ';
}else{
SetConsoleTextAttribute(h, FOREGROUND_GREEN | FOREGROUND_INTENSITY);
cout << mp[i][j] << ' ';
SetConsoleTextAttribute(h, 7);
}
}
cout << '\n';
}
cout << "请输入操作(0翻开 1插旗/拔旗) 行 列(1 ~ 9):";
}
}
int main(){
srand(time(0));
ll n = 10;
ll placed = 0;
while(placed < 10){//随机布雷
x = rand() % 9;
y = rand() % 9;
if(gm[x][y] != -1){
gm[x][y] = -1;
placed++;
}
}
for(ll i = 0;i < 9;i++){//同步地图
for(ll j = 0;j < 9;j++){
mp[i][j] = '#';
}
}
while(cnt){
ll op;
if(cai){
drawMap(true);
system("pause");
return 0;
}
drawMap(false);
cin >> op >> x >> y;
if(cin.fail()) {
cin.clear();
cin.ignore(1000, '\n');
cout << "输入格式有误,请输入数字!" << endl;
continue;
}
x -= 1;
y -= 1;
if(x < 0 || y < 0 || x > 8 || y > 8){
cout << "坐标超出范围,请输入1~9";
system("pause");
continue;
}
if(op != 0 && op != 1){
cout << "操作数只能是0或1";
system("pause");
continue;
}
if(op == 1){
if(mp[x][y] == '#'){
mp[x][y] = 'F';
}else if(mp[x][y] == 'F'){
mp[x][y] = '#';
}else{
cout << "这个格子已经翻开了,无法插旗";
system("pause");
}
}else{
if(gm[x][y] == -1 && mp[x][y] != 'F'){
cout << "你踩到地雷啦!";
system("pause");
cai = true;
}else if(mp[x][y] == 'F'){
cout << "此格子已被标记,无法翻开!";
system("pause");
} else {
open(x, y);
}
}
}
cout << "恭喜你,扫雷成功!";
return 0;
}
全部评论 7
不过还是有一些问题:
-
翻开已插旗的安全格子时没有提示
else { open(x, y); }如果
mp[x][y]=='F'且它不是雷,open()会因为if(mp[x][y] != '#') return;直接返回,玩家看不到“已标记,无法翻开”的提示。你只对“插旗的雷格”做了提示,逻辑不一致。
应先统一判断:
if(mp[x][y] == 'F'){ cout << "此格子已被标记,无法翻开!"; system("pause"); continue; } -
cnt = 71写死,和雷数强耦合ll cnt = 71;9×9 共 81 格,10 个雷,所以现在 71 恰好正确。但一旦修改雷数,胜利判断就错。
而且你已经写了:
ll n = 10;却没有使用它。建议:
const int SIZE = 9; const int MINE = 10; cnt = SIZE * SIZE - MINE; -
变量
n实际完全没用ll n = 10;后面却仍然:
while(placed < 10)应改成:
while(placed < n)
3天前 来自 浙江
1-
可以新加两个变量n和m,用来调扫雷大小
不然9*9太小了2天前 来自 广东
0dddd
2天前 来自 广东
0对对对
2天前 来自 广东
0
3天前 来自 浙江
0可以可以
3天前 来自 浙江
0我发现你的代码主要是以下几点问题:
-
插旗后的地雷仍然可以被“翻开”并触雷
if(gm[x][y] == -1){ cout << "你踩到地雷啦!"; }这里没有先判断
mp[x][y] == 'F'。因此对一个已经插旗的地雷执行0,仍会直接判定踩雷。建议翻开前先判断:if(mp[x][y] == 'F') continue; -
失败后没有显示最终雷区
踩雷后只是提示“你踩到地雷啦”,随后退出程序,没有把所有地雷显示出来。不是逻辑错误,但扫雷游戏通常会在失败后揭示雷的位置。 -
存在多个未使用变量
ll s = 10; ll ans; ll n = 10;这三个变量实际没有参与程序逻辑,可以删除。
-
cai的处理较多余
现在是:cai = true;然后下一轮:
if(cai)return 0;可以在踩雷后直接
return 0;或break;,代码更简洁。 -
system("cls")和system("pause")只适用于 Windows
如果在 Linux、macOS 或部分在线评测环境运行,会失效。因此程序的平台兼容性较差。 -
没有处理非法输入导致的
cin失败
如果用户输入:abccin >> op >> x >> y会进入失败状态,之后可能一直无法正常读取输入。若只是自己运行小游戏,影响不大;若想做得完整,应检测cin.fail()。
4天前 来自 浙江
0感谢提醒,拼死修改中
4天前 来自 广东
1
-



























有帮助,赞一个