c++控制台程序实现扫雷

  无聊写了个扫雷小游戏,输入非雷坐标(x,y),清除掉非雷的区域,剩下地雷。算法很简单的,关键是空白区域的处理,即如果输入的坐标四周不存在雷,则连通的空白区域自动清除。这个模型与计算机图形学中的区域填充相当类似。填充算法一般有扫描线填充,种子填充等等。在这里借鉴种子填充算法。实现如下:输入一个点,从左右两个方向遍历改点所处的水平线,遇到雷终止,得到一个x的区间,扫描该线的上方和下方的水平线,如果在该区间内发现有空白点,则以该点为种子,递归调用。

     附上代码。代码有点烂,程序还有小bug。不过大致的算法就是那么回事吧。小问题懒得改了。

 

// play.cpp : Defines the entry point for the console application.
//
/*
   如果认为(x,y)不是雷,输入坐标(x,y)清除,不可以标记雷。可以实现,只是操作起来会比较麻烦
   本程序的坐标系:
   |------>y
   |
   |
   |
   |
   ∨
   x

   '.':为清除的点;'*'地雷;空白(四周没有雷)用空格代替。
*/
#include "stdafx.h"
#include <time.h>
#include <stdlib.h>
#include <iostream>
using namespace std;

bool g_Llimet = false;
bool g_Rlimet = false;
int top_line = 0;
int bottom_line = 0;

struct coor
{
   int x;
        int y;
};

struct mask
{
 int x;
      int y;
   bool isshow;//是否展示
    bool isblank;//是否空白区域的点
};
      
int xx,yy;
int recursion = 0;
mask masks[500];
char mines[100][100];
#define DEFAULT_X 16
#define DEFAULT_Y 30
#define DEFAULT_MINESNUMBER 100
int COORDINATE_X = DEFAULT_X;
int COORDINATE_Y = DEFAULT_Y;
int  MINE_NUMBER = DEFAULT_MINESNUMBER;

void initialization()
{
     for(int a = 0;a<COORDINATE_X;a++)
   {  
            for(int b = 0;b<COORDINATE_Y;b++)
          {
                  mines[a][b] = '.';
                     masks[a*COORDINATE_Y+b].x = a;
                    masks[a*COORDINATE_Y+b].y = b;
                   masks[a*COORDINATE_Y+b].isshow = false; 
                  masks[a*COORDINATE_Y+b].isblank = false;               
                }
        }        
 srand(time(NULL));
        int cc=MINE_NUMBER,aa[1000],bb[1000],ii=0,jj=0;
       while(cc--)//生成随机地雷坐标
    {
             aa[++ii]=rand()%(0-COORDINATE_X);
              bb[++jj]=rand()%(0-COORDINATE_Y);
              mines[aa[ii]][bb[jj]] = '*';
                //masks[aa[ii]*y + bb[jj]].isshow = true;
          }
}

void SetMinesShow()
{
     for(int cc = 0;cc<500;cc++)
 {
         masks[cc].isshow = true;
      }
}

void FreshScrean()
{
    system("CLS");
       //printf("   ");
    for(int c = 0;c<=COORDINATE_Y;c++)
 {
         printf("%3d",c);
  }
  printf("\n");
      printf("\n");
  for(int i = 0;i<COORDINATE_X;i++)
        {  
         printf("%3d",i+1);
                for(int j = 0;j<COORDINATE_Y;j++)
              {
                      if(masks[i*COORDINATE_Y+j].isshow == true)
                 {
                         printf("%3c",mines[i][j]);
                        }
//                         else if(mines[i][j] == '*')
//                    {
//                           printf("%3c",'*');
//                                 
//                         }
                       else
                    {
                            printf("%3c",'.');
                   }
           }
           printf("\n");
               printf("\n");
   }   
}

int CheckSingle(int x,int y,bool needcharge)
{
      bool bFind = false;
  int count = 0;
   coor coor_xy[9] =
       {{x-1,y-1},{x-1,y},{x-1,y+1},
   {x,y-1},{x,y},{x,y+1},
      {x+1,y-1},{x+1,y},{x+1,y+1}
    };
    
    for (int i = 0;i<9;i++)//取雷个数
        {
        if( coor_xy[i].x >=0 && coor_xy[i].x<COORDINATE_X
                        && coor_xy[i].y >=0 && coor_xy[i].y<COORDINATE_Y
                 && mines[coor_xy[i].x][coor_xy[i].y] == '*')
            {
            count ++;
                      bFind = true;
                        if(needcharge)
                  {
                            if(i == 3)g_Llimet = true;
                            if(i == 5)g_Rlimet = true;
                  }
          }
  }
  
   if((!bFind) && needcharge)//没有发现边上有雷,则该点是空白点,周围的点都该展示出来
 {
         for (int j = 0;j<9;j++)
           {
                   if( coor_xy[j].x >=0 && coor_xy[j].x<COORDINATE_X
                           && coor_xy[j].y >=0 && coor_xy[j].y<COORDINATE_Y
                            && mines[coor_xy[j].x][coor_xy[j].y] != '*')
                       {
                               masks[coor_xy[j].x*COORDINATE_Y+coor_xy[j].y].isshow = true;
                                masks[coor_xy[j].x*COORDINATE_Y+coor_xy[j].y].isblank = true;
                        }
                }
        }
        return count;
}
int ccc = 0;
void CheckLogic(int coor_x,int coor_y)
{
      int realCoor_x = coor_x -1;
    int realCoor_y = coor_y -1;
  int imin = realCoor_y;
   int imax = realCoor_y;
    int icount = 0;
    char num[2] = {'0'};
       // -- new test.
       if(coor_x ==xx && coor_y == yy && mines[realCoor_x][realCoor_y] != '*' )//选择的点无论如何展示出来
      {                                                                       //加上!= ‘*’的条件是递归可能会扫到该点,导致是雷也展示
          masks[realCoor_x*COORDINATE_Y+realCoor_y].isshow = true;   
        }
         --以下两个while遍历一行,一个往左,一个往右。
    while('0'==num[0] && realCoor_y - icount >=0)
  {
          sprintf(num,"%d",CheckSingle(realCoor_x,realCoor_y-icount,true));
          if('0'!=num[0] )
             {
                     icount ++;
                      if(mines[realCoor_x][realCoor_y-icount+1] != '*' && (mines[realCoor_x][realCoor_y-icount+1] <'0' || mines[realCoor_x][realCoor_y-icount+1] >'8'))
                              mines[realCoor_x][realCoor_y-icount+1] = num[0];
                   if(g_Llimet)
                        {
                                imin --;
                   }   
                    if( icount == 0 || g_Llimet || mines[realCoor_x][realCoor_y-icount+1] != '*')
                  {
                          masks[realCoor_x*COORDINATE_Y+(realCoor_y-icount)+1].isshow = true;
                    }
                    break;
               }
               else
            {
                    if(mines[realCoor_x][realCoor_y-icount] != '*' && mines[realCoor_x][realCoor_y-icount] == '.')
                           mines[realCoor_x][realCoor_y-icount] = ' ';
                       imin --;
                  icount ++;
           }
   }
   if(imin <0)imin=0;
    
             int temmp =icount;
                g_Llimet = false;
            icount = 1;
        num[0] = '0';
              while(('0'==num[0]) && temmp >=1 && realCoor_y+icount<=COORDINATE_Y)
             {
                     sprintf(num,"%d",CheckSingle(realCoor_x,realCoor_y+icount,true));
                     if('0'!=num[0]  )
                        {
                                if(mines[realCoor_x][realCoor_y+icount] != '*' && (mines[realCoor_x][realCoor_y+icount] <'0' || mines[realCoor_x][realCoor_y+icount] >'8'))
                                      mines[realCoor_x][realCoor_y+icount] = num[0];
                             if(!g_Rlimet)
                         {
                      imax ++;
                            }
                            if( g_Rlimet && mines[realCoor_x][realCoor_y+icount] != '*')
                           {
                                   masks[realCoor_x*COORDINATE_Y+(realCoor_y+icount)].isshow = true;
                               }
                               icount ++;
                                break;
                   }
                   else
                        {
                                if(mines[realCoor_x][realCoor_y+icount] != '*' && mines[realCoor_x][realCoor_y+icount] == '.')
                                       mines[realCoor_x][realCoor_y+icount] = ' ';
                           imax ++;
                              icount ++;
                       }
               }
               if(imax>COORDINATE_Y)imax = COORDINATE_Y;
                           
            g_Rlimet = false;
                temmp =icount;
             icount = 0;       
    // 以下递归调用处理空白区域,借鉴种子填充算法。
    /*分上下遍历所有行,如果发现有空白的点,以该点为种子,递归遍历 */
      for(int t = imin; t<= imax+1;t++ )
 {
         //往上
              if(realCoor_x-1>=0 && realCoor_x-1<xx-1 /*&&temmp>2*/
                         && masks[(realCoor_x-1-1)*COORDINATE_Y+t].isshow == false)
              {
                      sprintf(num,"%d",CheckSingle(realCoor_x-1,t,false));
                   if( masks[(realCoor_x-1)*COORDINATE_Y+t].isblank == true)CheckLogic(realCoor_x,t+1);

              }
              //往下
           if( realCoor_x+1<=COORDINATE_X-1 && realCoor_x+1>xx-1 /*&&temmp>2*/
                  && masks[(realCoor_x+1+1)*COORDINATE_Y+t].isshow == false)
               {
                       sprintf(num,"%d",CheckSingle(realCoor_x+1,t,false));
                    if(  masks[(realCoor_x+1)*COORDINATE_Y+t].isblank == true)CheckLogic(realCoor_x+1+1,t+1);
           }   
    }
    recursion ++;
  return;    
     //    
}

void init()
{  

   int len = 0,weidth = 0;
       int iParam  = 0;
       cout<<"Please select : [1] Start game;[2] Setting"<<endl;           
      cin>>iParam;  
   switch(iParam)
      {
      case 1:
          {
                  initialization();
                  FreshScrean();
                     break;
                }                
 case 2:
             {
                     cout<<"Please input Length:"<<endl;
                       cin>>COORDINATE_X;
                      cout<<"Please input weidth:"<<endl;
                        cin>>COORDINATE_Y;
                       cout<<"Please input mine's number:"<<endl;
                    cin>>MINE_NUMBER;
                    initialization();
                    FreshScrean();
                       break;
          }
  default:
           {
                   initialization();
                   FreshScrean();
                      break;
         }         
  }
}

int main(int argc, char* argv[])
{
        init();
  while(true)
        {
                cout<<"Please input coordinate (x,y).recursion's time:"<<recursion<<endl;
                recursion = 0;
               scanf("%d,%d",&xx,&yy); 
          if(xx>COORDINATE_X || xx<0 || yy>COORDINATE_Y || yy<0)
         {
                 printf("coordinate error! Please input again!\n");
                        continue;
                }
                if(mines[xx-1][yy-1] == '*')
         {
                 SetMinesShow();
            FreshScrean();
                      printf("\n");
                  printf("You got a mine,asshole!\n");
                     printf("Please select : [1] Play again;[2] quit.\n");
                     int iParam = 0;
                     scanf("%d",&iParam);
                  if(iParam == 1)
                        {
                                init();
                          continue;
                  }
                  else exit(0);        
         }
        CheckLogic(xx,yy);
                FreshScrean();
   }
   return 0;
}

 <span style="FONT-SIZE: 10pt" dir="ltr"></span>
运行效果如下:
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值