Freak_Van 2015-11-29 08:32 采纳率: 50%
浏览 2041
已采纳

c语言扫雷算法有问题求助

自己写了个控制台的扫雷
输入坐标然后显示地图
但是输入某些坐标的时候卡住不动了 不知道是陷入死循环还是什么问题
求大神解答 已考虑无雷区自动翻开的死循环 可能是双击时陷入死循环 但看不出是不是这个问题 不知道怎么修改代码

#include
#include
#include
#include

#define len 20 //边数
int mine[len+2][len+2] = {0}; //+2是为了在计算周围一圈雷数时不必分四周顶点边界区域,不越界

int dispMine[len+2][len+2] = {0}; //记录当前格子状态:0为未点开、1为已点开、2为双击、3为插旗、4为周围一圈无雷自动翻开
int endindex = 0; //点击到地雷的结束标志
int mines = 0; //记录已排除的地雷数

void SetMine(int n) //布雷
{
srand(time(0));
int k, row, col;
if(n == 1) //初级难度
k = 25;
else if(n == 2) //中级难度
k = 50;
else //高级难度
k = 75;
mines = k;
while(k)
{
row = rand() % len + 1; //+1是为了将地雷分布在除四边以外的区域 显示地图时实际只显示中间部分 不显示四周
col = rand() % len + 1;
if(!mine[row][col])

{
mine[row][col] = 9;
k--;
}
}
}

void round(int mine[][len+2], int x, int y)
{
int k = 0; //地雷数
if(mine[x][y] == 9 && dispMine[x][y] != 3) //点击到地雷
endindex++;
else
{
if(mine[x][y+1] == 9) //计算周围一圈是否有雷
k++;
if(mine[x+1][y+1] == 9)
k++;
if(mine[x+1][y] == 9)
k++;
if(mine[x+1][y-1] == 9)
k++;
if(mine[x][y-1] == 9)
k++;
if(mine[x-1][y-1] == 9)
k++;
if(mine[x-1][y] == 9)
k++;
if(mine[x-1][y+1] == 9)
k++;
mine[x][y] = k; //记录当前位置地雷数
}

}

void open(int mine[][len+2], int x, int y) //翻开
{
if(mine[x][y] == 9) //点击到雷直接返回
return;
if(dispMine[x][y] == 3) //输入坐标位置为插旗的位置
return;
if(mine[x][y] == 0) //无雷区自动翻开
{
dispMine[x][y] = 4; //无雷区标志为4
if(x != 1 && y != 1) //考虑各个特殊位置的坐标
{
round(mine, x-1, y-1);
if(!mine[x-1][y-1] && dispMine[x-1][y-1] != 4) //若无雷自动翻开区域里又有无雷区 继续自动翻开 为了防止死循环
open(mine, x-1, y-1); //要标志已翻开的
else if(mine[x-1][y-1] && !dispMine[x-1][y-1]) //若是周围一周有雷的,则直接显示,标志为1
dispMine[x-1][y-1] = 1;
}
if(x != 1 && y != len)
{
round(mine, x-1, y+1);
if(!mine[x-1][y+1] && dispMine[x-1][y+1] != 4)
open(mine, x-1, y+1);
else if(mine[x-1][y+1] && !dispMine[x-1][y+1])
dispMine[x-1][y+1] = 1;
}
if(x != len && y != 1)
{
round(mine, x+1, y-1);
if(!mine[x+1][y-1] && dispMine[x+1][y-1] != 4)
open(mine, x+1, y-1);
else if(mine[x+1][y-1] && !dispMine[x+1][y-1])
dispMine[x+1][y-1] = 1;
}
if(x != len && y != len)
{
round(mine, x+1, y+1);
if(!mine[x+1][y+1] && dispMine[x+1][y+1] != 4)
open(mine, x+1, y+1);
else if(mine[x+1][y+1] && !dispMine[x+1][y+1])
dispMine[x+1][y+1] = 1;
}
if(x != 1)
{
round(mine, x-1, y);
if(!mine[x-1][y] && dispMine[x-1][y] != 4)
open(mine, x-1, y);
else if(mine[x-1][y] && !dispMine[x-1][y])
dispMine[x-1][y] = 1;
}
if(x != len)
{
round(mine, x+1, y);
if(!mine[x+1][y] && dispMine[x+1][y] != 4)
open(mine, x+1, y);
else if(mine[x+1][y] && !dispMine[x+1][y])
dispMine[x+1][y] = 1;
}
if(y != 1)
{
round(mine, x, y-1);
if(!mine[x][y-1] && dispMine[x][y-1] != 4)
open(mine, x, y-1);
else if(mine[x][y-1] && !dispMine[x][y-1])
dispMine[x][y-1] = 1;
}
if(y != len)
{
round(mine, x, y+1);
if(!mine[x][y+1] && dispMine[x][y+1] != 4)
open(mine, x, y+1);
else if(mine[x][y+1] && !dispMine[x][y+1])
dispMine[x][y+1] = 1;
}
}
if(dispMine[x][y] = 2) //如果双击
{
dispMine[x][y] = 1; //置为已点击防止死循环
int flag = 0; //记录周围一周插旗数
if(dispMine[x-1][y] == 3) //若周围有旗子,flag++
flag++;
if(dispMine[x-1][y+1] == 3)
flag++;
if(dispMine[x][y+1] == 3)
flag++;
if(dispMine[x+1][y+1] == 3)
flag++;
if(dispMine[x+1][y] == 3)
flag++;
if(dispMine[x+1][y-1] == 3)
flag++;
if(dispMine[x][y-1] == 3)
flag++;
if(dispMine[x-1][y-1] == 3)
flag++;
if(mine[x][y] == flag) //双击的当前位置插旗数与该位置地雷数相同时自动翻开周围一圈未点击的位置
{
if(y != len && dispMine[x][y+1] == 0) //考虑各个特殊位置防止越界以及是否为未翻开位置
{
round(mine, x, y+1);
dispMine[x][y+1] = 1;
if(!mine[x][y+1]) //若翻开为无雷区则递归调用
open(mine, x, y+1);
}
if(x != len && y != len && dispMine[x+1][y+1] == 0)
{
round(mine, x+1, y+1);
dispMine[x+1][y+1] = 1;
if(!mine[x+1][y+1])
open(mine, x+1, y+1);
}
if(x != len && dispMine[x+1][y] == 0)
{
round(mine, x+1, y);
dispMine[x+1][y] = 1;
if(!mine[x+1][y])
open(mine, x+1, y);
}
if(x != len && y != 1 && dispMine[x+1][y-1] == 0)
{
round(mine, x+1, y-1);
dispMine[x+1][y-1] = 1;
if(!mine[x+1][y-1])
open(mine, x+1, y-1);
}
if(y != 1 && dispMine[x][y-1] == 0)
{
round(mine, x, y-1);
dispMine[x][y-1] = 1;
if(!mine[x][y-1])
open(mine, x, y-1);
}
if(x != 1 && y != 1 && dispMine[x-1][y-1] == 0)
{
round(mine, x-1, y-1);
dispMine[x-1][y-1] = 1;
if(!mine[x-1][y-1])
open(mine, x-1, y-1);
}
if(x != 1 && dispMine[x-1][y] == 0)
{
round(mine, x-1, y);
dispMine[x-1][y] = 1;
if(!mine[x-1][y])
open(mine, x-1, y);
}
if(x != 1 && y != len && dispMine[x-1][y+1] == 0)
{
round(mine, x-1, y+1);
dispMine[x-1][y+1] = 1;
if(!mine[x-1][y+1])
open(mine, x-1, y+1);
}
}
}

}

void chaqi(int x, int y) //插旗
{
if(dispMine[x][y] == 3) //已经插旗的位置再次插旗视为取消插旗
{
dispMine[x][y] = 0; //置为0表示未点击区域
return;
}
else if(dispMine[x][y]) //若该位置已点开则不改变
return;
dispMine[x][y] = 3; //插旗标志为3

}

void disp(int x, int y) //显示地图
{
cout<<" ";
for(int k = 1; k < len+1; k++)
cout<<setw(2)<<k;
cout<<endl;
if(mine[x][y] == 9 && dispMine[x][y] != 3) //如果点到地雷
{
for(int i = 1; i < len+1; i++)
{

cout<<setw(2)<<i;
for(int j = 1; j < len+1; j++)
{
if(dispMine[i][j] == 3) //插旗的地方显示为■
cout<<"■";
else if(mine[i][j] == 9) //有雷的地方显示为*
cout<<" *";

else if(dispMine[i][j]) //无雷区显示数字
cout<<" "<<mine[i][j];
else //未翻开的地方显示为□
cout<<"□";
}
cout<<endl;
}
return;
}

for(int i = 1; i < len+1; i++)           //没有点击到地雷
{   
    cout<<setw(2)<<i;
    for(int j = 1; j < len+1; j++)
    {
        if(dispMine[i][j] == 3)
            cout<<"■";
        else if(dispMine[i][j])
            cout<<" "<<mine[i][j];
        else
            cout<<"□";
    }
    cout<<endl;
}
return;

}

bool win(int mines) //判断胜利条件
{
bool win = false; //默认为没有取得胜利
int noFlag = 0, yesFlag = 0, halfFlag = 0; //noFlag记录未翻开的格子数 yesFlag、halfFlag记录插旗数且该位置有雷 noClip
for(int i = 1; i < len+1; i++)
for(int j = 1; j < len+1; j++)
{

        if(dispMine[i][j] == 0 )         //未翻开位置
            noFlag++;
        if(dispMine[i][j] == 3 && mine[i][j] == 9)        //插旗位置正确
        {
            yesFlag++;
            halfFlag++;
        }
    }
if(noFlag == mines || (yesFlag == mines && !noFlag) || halfFlag == len*len - noFlag) //未翻开的格子数等于地雷数 插旗数等于地雷数 
    win = true;                                                                //插旗与未翻开格子数等于地雷数
return win;   

}
void main()
{
int x = 0, y = 0;
cout<<"请选择游戏难度,1.初级 2.中级 3.高级:";
int rank = 0;
while(1)
{
cin>>rank;
if(rank < 1 || rank > 3)
cout<<"输入有误,请重新输入:";
else
{
system("CLS");
break;
}
}
SetMine(rank);
disp(x, y);
while(1)
{
cout<<"1.点击 2.插旗 3.双击"< cout int n;
while(1)
{
cin>>n;
cin>>x>>y;
if(n < 1 || n > 3)
{
cout<<"输入有误,请重新输入:";
continue;
}
else if(x < 1 || x > 20 || y < 1 || y > 20)
{
cout<<"输入有误,请重新输入:";
continue;
}
break;
}

    if(n == 1 || n == 3)
    {
        if(n == 3 && dispMine[x][y] == 3)
            continue;
        round(mine, x, y);
        if(dispMine[x][y] < 2)
            dispMine[x][y]++;       
        open(mine, x, y);

    }
    else if(n == 2)
        chaqi(x, y);

    system("CLS");
    disp(x, y);
    if(endindex)
    {
        cout<<"你输了!"<<endl;
        break;
    }   
    if(win(mines))
    {
        cout<<"你赢了!"<<endl;
        break;
    }
}

}

  • 写回答

4条回答 默认 最新

  • ysuwood 2015-11-29 09:02
    关注

    程序很长,基本没人会给你调试找错误的。会花费很长时间。
    建议你自己学会调试程序,掌握设置断点,查看变量,单步执行等手段。
    怀疑是哪里出了问题,就单步执行去试试。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

悬赏问题

  • ¥15 Odoo17操作下面代码的模块时出现没有'读取'来访问
  • ¥50 .net core 并发调用接口问题
  • ¥15 网上各种方法试过了,pip还是无法使用
  • ¥15 用verilog实现tanh函数和softplus函数
  • ¥15 Hadoop集群部署启动Hadoop时碰到问题
  • ¥15 求京东批量付款能替代天诚
  • ¥15 slaris 系统断电后,重新开机后一直自动重启
  • ¥15 QTableWidget重绘程序崩溃
  • ¥15 谁能帮我看看这拒稿理由啥意思啊阿啊
  • ¥15 关于vue2中methods使用call修改this指向的问题