原创!字符版扫雷 控制台程序源代码,欢迎拍砖...

VC6 + XP/Vista 调试成功

这是我自己写的一个字符版扫雷的控制台程序(有些功能还比较欠缺)...

编程不久,第一次写这么多的代码,有些注释以及变量命名不合规范,还望指出交流..

也有朋友指出这个代码更像是C风格的而不是C++的,对于C++风格我确实了解不多,希望大家能来信指出

我的邮件地址是liliflashfly(at)gmail.com,你的意见将是我前进的动力,谢谢!

相关工程(VC6版)可以在CSDN的资源http://download.csdn.net/source/799581上下载....

思路请见

 

说明文档:

 

初始化

 

 

得到边界n,m,

              建立数组mine_count,全部初始化为0(作为后台数据界面,-1表示地雷,非负数表示周围的地雷数)

              建立字符数组mine_state,全部初始化为'#',表示还未探索

                              挖出的地雷数dig_num=0,游戏结束mine_end=false,游戏胜利mine_win=false

得到地雷值mine_num,建立循环,利用随机函数,产生mine_num个坐标(越界和地雷覆盖(bool IsMine)判断),

并且每个坐标周围的坐标地雷值(mine_count)自增一次(通过MineCountPP(y,x)函数)

并且这些地雷坐标保存到结构体(x,y)数组Mine_Location[mine_count].

 

 

界面

0 1 2 3 4 5 6 7 8 9 10

1 # # # # # # # # # #

2 # # # 1 # # # # # #

3 # # # 2 # # # # # #

4 # # # # # # # # # #

5 # # 1 # # # # # # #

6 # # 1 P # # # # # #

7 # # # # # # # # # #

8 # # # # # # # # # #

9 # # # # # # # # # #

10# # # # # # # # # #

你还有8个地雷没有挖出。。。

 

开始游戏

 

输入一次坐标,返回一次全局状态(mine_state)

状态:

未探索:             '#'

已探索:    mine_state[x][y]!='#'

  周围有地雷:相应数字,如 '6'

  插旗(挖雷成功):     笑脸图案,char值为2

  空的:          ' '

  地雷:          'O'

         判断错误:        'X'

         爆炸点:         '_'

 

输入方式

s y x  (step到某个坐标(x,y),即确定那里没有地雷)

d y x (dig某个坐标(x,y),即确定那里有地雷,插旗)

输入后先执行x--,y--,再判断是否越界和mine_state是否为'#',否则提示出错。

 

坐标输入后判断

 

 

1、s输入,是地雷(mine_count==-1)

                   此坐标mine_state'_',

                   遍历Mine_Location[],使剩下的未探索的地雷click=truemine_state'*'(通过fail()函数)

 

  d输入,不是地雷(mine_count!=-1)

                   此坐标mine_state'X',

                   遍历Mine_Location[],使剩下的未探索的地雷click=truemine_state'*'(通过fail()函数)

 

然后游戏结束(mine_end=true),输出mine_state

 

2、s输入,不是地雷(mine_count!=-1)

  mine_count>0

                   mine_state[y][x]=mine_count+'0';

         mine_count==0

                   mine_state[y][x]=' ';

                   回溯第归直到mine_count>0 或者 到了边界

3、d输入,是地雷(mine_count==-1)

         mine_state[y][x]='P';

         dig_num++;

         if(dig_num==mine_num)

                   输出,胜利,结束(mine_end=true)

  1. //类Mine的头文件 minectrl.h
  2. #ifndef _MINE_CTRL_
  3. #define _MINE_CTRL_
  4. #include "iostream"
  5. #include "iomanip"
  6. #include "string"
  7. #include "ctime"
  8. #include "cstdlib"
  9. using namespace std;
  10. struct Mine_coordinate{
  11.     int x,y;
  12. };
  13. class Mine 
  14. {
  15.     friend void Run(Mine *oMine);
  16. public:
  17.     Mine(void){};
  18.     Mine(int x,int y,int MineNum);       //带参构造函数,随机生成扫雷坐标,形成后台数据界面
  19.     virtual ~Mine(void);
  20. private:
  21. //功能函数
  22.     //每局游戏的初始化函数
  23.     void MineCountPP(int y,int x);       //对地雷坐标周围一圈中没有越界且不是地雷的坐标进行自增,因为增加了一个地雷
  24.     void GetXY(int *x,int *y);           //获得两个不越界的随机值
  25.     void Help(void);                     //帮助坐标
  26.     //每局游戏进行时的函数
  27.     void Screen_Out(void);               //游戏界面函数,显示游戏状况
  28.     void Operate(void);                  //主要操作函数,用于处理游戏时玩家的输入
  29.     void Deal_blank(int x,int y);        //回溯函数,解决到达一个周围无地雷的坐标的情况
  30.     bool Mine::IsInputOk(char &ch,int &x,int &y);  //判断坐标输入是否合法
  31.     //每局游戏的结束状态判断函数
  32.     void Fail(void);                     //游戏失败时将未发现的地雷标注出来
  33.     bool GoOn(void);                     //判断是否继续游戏
  34.     bool Win(void);                      //判断是否胜利
  35. //数据
  36.     char **mine_state;                   //每个坐标的状态,游戏的实时显示界面
  37.     int **mine_count;                    //每个坐标周围的地雷数,游戏的后台数据界面
  38.     int dig_num,mine_num;                //挖出地雷数,地雷的数量
  39.     int X,Y;//保存边界
  40.     bool mine_end,mine_win;              //判断游戏是否结束,判断是否胜利
  41.     Mine_coordinate *Mine_Location;      //用于建立一个记录地雷位置的数组
  42. };
  43. #endif

 

  1. //类Mine的实现文件 minectrl.cpp
  2. #include "minectrl.h"
  3. Mine::Mine(int y,int x,int MineNum):X(x),Y(y),mine_num(MineNum){
  4.     int i(0);
  5.     mine_state=new char*[Y];
  6.     mine_count=new int* [Y];
  7.     srand((unsigned)time(NULL));                   //随机的初始,现在的时间作为随机种子
  8.     //生成并初始化两个二维数组
  9.     for(;i<Y;i++){
  10.         mine_state[i]=new char[X];
  11.         mine_count[i]=new int[X];
  12.         memset(mine_state[i],'#',X*sizeof(char));  //初始化:游戏界面,因为字符型只有一字节,所以能用memset()
  13.         memset(mine_count[i], 0 ,X*sizeof(int) );  //初始化:后台数据界面,-1 表示地雷,自然数 表示四周一圈的格子里地雷的数量
  14.     }
  15.     dig_num=0;                                     //初始化:已挖了的地雷数量。
  16.     mine_end=mine_win=false;                       //初始化:游戏结束与胜利均设为否
  17.     Mine_Location=new Mine_coordinate[mine_num];   //建立一个记录地雷位置的数组。
  18.     
  19.     //开始随机生成地雷坐标,
  20.     for(i=0;i<mine_num;i++){
  21.         int x(0),y(0);
  22.         GetXY(&x,&y);                              //获得两个不越界的随机值
  23.         while(mine_count[y][x]==-1)                //如果坐标已经有地雷了,则重新找
  24.             GetXY(&x,&y);
  25.         mine_count[y][x]=-1;                       //标注此地有地雷
  26.         MineCountPP(x,y);                          //使其周围数字加1
  27.         Mine_Location[i].y=y;                      //坐标记录到地雷位置数组里面
  28.         Mine_Location[i].x=x;
  29.     }
  30.     
  31. }
  32. void Mine::GetXY(int *x,int *y){
  33.     *x=(rand()%X);          //生成[0,X-1]的随机数
  34.     *y=(rand()%Y);          //生成[0,Y-1]的随机数
  35. }
  36. //对地雷坐标周围一圈中没有越界且不是地雷的坐标进行自增,因为增加了一个地雷
  37. void Mine::MineCountPP(int x,int y){
  38.     int i,j;
  39.     for(i=-1;i<2;i++)
  40.         for(j=-1;j<2;j++)
  41.             if(y+i>-1 && y+i<Y && x+j>-1 && x+j<X) //自增的时候进行边界之类的判断
  42.                 if(mine_count[y+i][x+j]!=-1)       //确保记录的地方不是另一个地雷
  43.                     mine_count[y+i][x+j]++;
  44. }
  45. bool Mine::IsInputOk(char &ch,int &x,int &y){
  46.     bool ok=true;
  47.     if(!(cin>>ch>>x>>y) || (ch!='s'&&ch!='d') ){   //输入不合规范 坐标输成了字母||命令是除s、d以外的字符 
  48.         ok=false;
  49.         cin.clear();                               //清除输入流的错误状态,避免死循环
  50.     }
  51.     while(cin.get()!='/n');
  52.     system("cls");
  53.     cout<<ch<<" "<<x<<" "<<y<<endl;
  54.     x--;y--;
  55.     return ok;
  56. }
  57. void Mine::Operate(void){
  58.     int x,y;                             //坐标
  59.     char s;                              //命令字符(s or d)
  60.     if( IsInputOk(s,x,y) &&              //关于命令的输入 兼 输入是否合法的判断
  61.         -1<x && x<X && -1<y && y<Y &&    //关于边界的判断
  62.         mine_state[y][x]=='#'){          //关于位置是否探索过的判断
  63.         
  64.         if(s=='s'){//执行“踩”操作,即认为此处无雷
  65.             if(mine_count[y][x]==-1){    //踩到雷了
  66.                  mine_state[y][x]='_';   //将爆炸点标记出来
  67.                  Fail();                 //将未发现的雷标记出来.
  68.                  mine_end=true;          //游戏结束
  69.             }else{                       //没有踩到雷
  70.                  if(mine_count[y][x]>0)  //此坐标周围有雷
  71.                      mine_state[y][x]='0'+mine_count[y][x];
  72.                  else{                   //此坐标周围没有地雷,需要向八个方向扩展直至找到边界或者有地雷的地方
  73.                      Deal_blank(x,y);    //回溯第归
  74.                  }
  75.              }
  76.         }
  77.         else//s=='d',执行“挖”操作。即认为此处有雷
  78.             
  79.             if(mine_count[y][x]!=-1){    //此处无雷
  80.                  mine_state[y][x]='X';
  81.                  Fail();                 //将未发现的雷标记出来.
  82.                  mine_end=true;          //游戏结束
  83.             }else{                       //挖到雷了
  84.                 mine_state[y][x]=2;      //显示一个笑脸字符,即表示成功
  85.                 dig_num++;               //已挖雷数量增加1
  86.                 if(dig_num==mine_num){   //雷挖完了
  87.                     mine_end=true;       //结束
  88.                     mine_win=true;       //胜利
  89.                 }
  90.              }
  91.         }
  92.     }else{               //非法输入提示
  93.         cout<<"错误输入,重试!"<<endl;
  94.     }
  95.     Screen_Out();        //显示此时扫雷情况
  96. }
  97. //游戏以失败结束的时候 将未发现的地雷全部用'O'显示出来
  98. void Mine::Fail(void)
  99. {
  100.     for(int i(0);i<mine_num;i++){//遍历地雷位置数组,看哪些还是'#'(未探索),则显示为'O'
  101.         if(mine_state[Mine_Location[i].y][Mine_Location[i].x]=='#')
  102.             mine_state[Mine_Location[i].y][Mine_Location[i].x]='O';
  103.     }
  104. }
  105. bool Mine::GoOn(void)
  106. {
  107.     return !mine_end;
  108. }
  109. bool Mine::Win(void)
  110. {
  111.     return mine_win;
  112. }
  113. //游戏界面函数,显示游戏状况
  114. void Mine::Screen_Out(){
  115.     int i,j;
  116.     cout<<" 0|";
  117.     for(i=1;i<=X;i++)
  118.         cout<<setw(2)<<i%10;  //因为同1行的各#有一空格,两位数的话坐标显示得很拥挤,所以 横坐标 取个位数
  119.         //printf("%2d",i%10);
  120.     cout<<endl;
  121.     for(i=0;i<2*X+3;i++)
  122.         cout<<'-';
  123.     puts("");
  124.     for(i=0;i<Y;i++){
  125.         cout<<setw(2)<<i+1<<"|";
  126.         //printf("%2d|",i+1);
  127.         for(j=0;j<X;j++)
  128.             cout<<" "<<mine_state[i][j];
  129.         cout<<endl;
  130.     }
  131.     if(!mine_end){            //如果游戏未结束
  132.         cout<<"剩余地雷:"<<mine_num-dig_num<<"个"<<endl<<endl;
  133.         cout<<"如果认为(x,y)坐标没有地雷请输入/"s x y/""<<endl;
  134.         cout<<"如果认为(x,y)坐标  有地雷请输入/"d x y/""<<endl;
  135.     }
  136.     /*for(i=0;i<Y;i++)
  137.     {
  138.         for(j=0;j<X;j++)
  139.             printf("%3d",mine_count[i][j]);
  140.         puts("");
  141.     }后台数据界面*/
  142. }
  143. void Mine::Deal_blank(int x,int y){
  144.     if(-1<x && x<X && -1<y && y<Y && mine_state[y][x]=='#'){//先判断是否越界,再判断是否仍是未探索区域
  145.         if(mine_count[y][x]==0){//继续回溯
  146.             mine_state[y][x]=' ';
  147.             int xShift[]={-1,-1,-1,0,0,1,1,1};
  148.             int yShift[]={-1,0,1,-1,1,-1,0,1};
  149.             for(int i=0;i<8;i++){
  150.                 Deal_blank(x+xShift[i],y+yShift[i]);
  151.             }
  152.         }else{
  153.             mine_state[y][x]='0'+mine_count[y][x];
  154.         }
  155.     }
  156. }
  157. void Mine::Help(void){
  158.     cout<<"此游戏是扫雷的翻版(还欠缺一些功能,不过可以玩了...)"<<endl;
  159.     cout<<"#表示还没有被探索"<<endl;
  160.     cout<<(char)2<<"表示此地雷被挖除"<<endl;
  161.     cout<<"O表示此地雷没有被发现"<<endl;
  162.     cout<<"_表示踩到地雷了,失败"<<endl;
  163.     cout<<"X表示此处没有地雷,失败"<<endl;
  164.     cout<<"操作方法:"<<endl;
  165.     cout<<"如果认为(x,y)坐标没有地雷请输入/"s x y/",如s 3 5"<<endl;
  166.     cout<<"如果认为(x,y)坐标  有地雷请输入/"d x y/",如d 6 3"<<endl;
  167.     cout<<"回车键继续..."<<endl;
  168.     while(cin.get()!='/n');         //使屏幕等待,并消去可能出现的多余字符
  169. }
  170. Mine::~Mine(void){
  171.     int i(0);
  172.     for(;i<Y;i++)
  173.     {
  174.         delete [] mine_state[i];
  175.         delete [] mine_count[i];
  176.     }
  177.     delete [] mine_state;
  178.     delete [] mine_count;
  179.     delete [] Mine_Location;
  180. }
  181. void Run(Mine *oMine){
  182.     int x=9,y=9,MineNum=10;         //值可以修改,做个自定义,但鉴于是字符版的,界面有限,最好不用改了
  183.     char ask;
  184.     bool ContinueMine=true;         //用于判断是否再玩一局
  185.     while(ContinueMine){
  186.         system("cls");              //清屏函数
  187.         oMine=new Mine(y,x,MineNum);//初始类
  188.         oMine->Help();              //显示操作说明
  189.         system("cls");              //清屏函数
  190.         oMine->Screen_Out();        //显示此时扫雷情况,这里是初始界面
  191.         while(oMine->GoOn()){       //GoOn()函数判断是否继续
  192.             oMine->Operate();
  193.         }
  194.         if(oMine->Win())            //Win()函数判断是否胜利
  195.             cout<<endl<<"You Win!"<<endl;
  196.         else
  197.             cout<<endl<<"You lose..."<<endl;
  198.         delete oMine;
  199.         cout<<"再来?(Y/N)";
  200.         ask=cin.get();
  201.         if(ask!='y' && ask!='Y')  ContinueMine=false;
  202.         if(ask=='/n')  cin.putback(ask);
  203.         while(cin.get()!='/n') ;    //消除多余的字符及回车
  204.     }
  205.     cout<<"ByeBye..."<<endl;
  206. }
  1. //主文件 main.cpp
  2. #include "minectrl.h"
  3. int main(){
  4.     Mine *oMine=NULL;
  5.     Run(oMine);
  6.     return 0;
  7. }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值