扫雷游戏课程设计报告

时间:2024.3.27

(一) 需求分析

题目

32、实现一个 N*M 的扫雷游戏

设计要求

能够实现一个 N*M 的扫雷游戏

a、能够打开一个方格(由于做的是静态显示,故在控制台上方格用‘—’代替),已打开的方格不能关闭

b、能够标记一个方格,标记方格的含义是对该方格有雷的预测(并不表示真的一定有雷)

c、能够给出游戏结果:输、赢

d、N和M可由玩家自己设置

系统功能需求分析

一个数字和一个雷(boom)。你可以打开(open)一个方格,如果你打开的是 一个boom,那么就失败;否则就会打开一个数字,该数字是位于[0,8]的一个整数,该数字表示其所有 邻居方格所包含的雷数,应用该信息可以帮助你扫雷。点击到了某区域发现其周围没有雷,那么显而易见应该点开周围的区域,拓展空白区域

(二)概要设计

由于知识储备不足,VC中的MFC应用程序又过于复杂,故退而求其次,不再采用动态显示和界面图形化,采用静态显示来实现扫雷游戏中的主要功能。

用键盘上的‘1’键代替鼠标左击,即打开一个方格查看其属性,已打开的方格不能在关闭;用键盘上的‘2’键代替鼠标右击,即标记一个方格,标记方格的含义是对该方格有雷的预测(并不表示真的一定有雷)

用键盘上的‘↑’‘↓’‘←’‘→’四个键来实现光标在控制台上的自由移动,

相当于用鼠标实现光标在图形界面的移动

游戏区域的高度与宽度及总雷数可由玩家自己设定

应题目要求设计了一个基类:Base和一个继承类:Game。

基类Base主要实现一些基本功能:游戏结束时输出游戏的结果:输赢;

返回控制台上光标的位置返回按下键时所对应的按键控制符

基类Base:

继承类Game是本程序的主要内容,也是实现扫雷游戏的关键部分。

主要实现的功能:初始化图形界面,把游戏区域在控制台上显示出来;利用随机函数进行随机布雷,以保证玩家每次玩游戏时雷的分布位置均不同;得到一个坐标位置周围的雷数,并把数值返回;在一个坐标点上(x,y)点击,在该位置上显示其周围的雷数或拓展空白区域或失败;如果一个坐标点的周围没有雷,则拓展空白区域,并递归拓展;其中saolei()函数是类Game里的关键函数体,用来判断玩家按下了哪个键,并作出相应反应(上下左右四个方向的移动,打开一个方格,标记一个方格),并判断游戏的输与赢

继承类Game:

(三)详细设计

核心算法:

(1)布雷函数:

初始化时把数组里的值全部置为0,然后利用srand(),rand()随机机制产生随机数,分别对列和行取模,便产生了雷的随机位置。但是布雷前,先要判断此随机位置是否已经布上了雷。

int Game::initpool(int width,int height,int num)

         {        poolWidth=width;

                   poolHeight=height;                   if(num<0||num>=width*height||width>GAME_MAX_HEIGHT||width<=0||height<=0||height>GAME_MAX_HEIGHT)                               return 1;

                            //初始是把游戏区域也即是数组里的值全都置为0

                            for(int y=0;y<=height+1;y++)

                            {for(int x=0;x<=width+1;x++)

                                     {pool[y][x]=0;}

                            }

                            //利用伪随机函数进行随机布雷,以保证每次点击游戏时雷的分布位置不同

                            srand(time(NULL));

                            while(num!=0){

                                     int x=rand()%width+1;

                                     int y=rand()%height+1;

                                     if(pool[y][x]==0){

                                               pool[y][x]=GMARK_BOOM;

                                               num--;//num为设置的总雷数}

                            }

                                     //初始化光标位置

               curX=1;curY=1;

                               MoveCursor();

                               return 0;

                            }

(2)打开方格,查看方格的属性

//在该位置上显示其周围的雷数或拓展空白区域或失败

int Game::tryopen(int x,int y){

         int m=0;

         if(pool[y][x] & GMARK_BOOM)m=-1;

                   else{

                            int count=shownum(x,y);

                            if(count==0)tuozhan(x,y);//拓展空白区域

                            else pool[y][x]=count;}

                                     return m; }

3)获得周围雷的数目

扫描其周围的所有相邻方格,记录雷数,并把值返回;扫描前要选择合理的起始点

 int Game::shownum(int x,int y){

                                     int count=0;

                                     for(int Y=-1;Y<=1;Y++)

                                              for(int X=-1;X<=1;X++){

                                                        if(pool[y+Y][x+X]&GMARK_BOOM)

                                                                 count++;}

                                               return count; }

4)展拓空白区域

展拓原因:当玩家点击的方块周围无雷时,此方块会被绘为空白,此时没有必要让玩家将其周围一一点开,应直接打开展拓条件:周围雷数为零

函数int tuozhan(intx,inty)

参数:x,y所点击的方块位置

算法:递归

递归结束条件:某一个方块不需要拓展就是因为其周围的雷数不是零

int Game::tuozhan(int x,int y){

                                     if((x>0&&x<=poolWidth)&&(y>0&&y<=poolHeight)&&(pool[y][x]==0)){                                                                int count=shownum(x,y);

                                               if(count==0){

                                                        pool[y][x]=GMARK_EMPTY;

                                                        for(int Y=-1;Y<=1;Y++)

                                                                  for(int X=-1;X<=1;X++)

                                                                  {tuozhan(x+X,y+Y);}

                                               }

                                               else pool[y][x]=count;}

                                     return 0;}

(5)在控制台上把扫雷区域显示出来

在还未按键时,调用huatu()函数把游戏界面在控制台上显示出来,即全部显示为方格。以后每按键一次。刷新一次界面

int Game::huatu(int n=0)

                            {for(int y=1;y<=poolHeight;y++)

                                     {Base::GotoXY(1,y);

                                               for(int x=1;x<=poolWidth;x++)

                                               {if(pool[y][x]==0)

                                                                 putchar('.');

                                                        else if(pool[y][x]==GMARK_EMPTY)

                                                                 putchar(' ');

                                                        else if(pool[y][x]>0 && pool[y][x]<=8)

                                                        putchar('0'+pool[y][x]);

                                                        else if(n==0 && (pool[y][x]& GMARK_MARK) )

                                                                 putchar('#');

                                                        else if(pool[y][x]& GMARK_BOOM)

                                                        {if(n!=0)putchar('*');

                                                                 else  putchar('.');}

                                               }

                                     }                                   

                                     return 0;}

6)判断是否胜利

判断游戏是否胜利的条件在saolei()函数体内,在主函数里调用saolei()进行循环,直到戏赢了或输了才退出循环,并在控制台上输出结果;游戏赢了返回1,按下ESC键退出游戏返回-1,记为输,扫到雷也是返回-1

判断是否赢了游戏:按下键‘1’后,对整个游戏区域进行检测,如果检测不到值为0的方格,即所有的雷已被扫出,则返回1,游戏胜利;按下ESC键退出游戏和扫到雷均为输,返回-1

if(Key == KEY_1 )//判断是否赢了游戏

        { int y=1;

            for(;y<=poolHeight;++y)

            { int x=1;

                for(;x<=poolWidth; ++x)

                {if(pool[y][x]==0)break;

                }

                if(x<=poolWidth) break; }

            if(! (y<=poolHeight))

            { m = 1;

            }

        }

(四)调试分析及测试

(1)由玩家设置游戏区域的高度与宽度,并设置总雷数

按下回车键后界面如下:

 按下键‘1’开始扫雷,扫雷过程部分界面如下:

…………

游戏输时显示的结果:

(2)直接按下ESC键时输掉游戏:

然后按下回车键后,直接按下ESC键,结果如下:

(3)为了使快速赢得游戏,减少雷的数目:

游戏运行过程部分界面如下:

按下键‘2’对怀疑有雷的区域进行标记

游戏胜利时显示的界面:

(五)源程序

附录源程序:

#include<iostream>

#include<iostream.h>

#include<ctime>//包含伪随机数发生函数

#include<windows.h>//包含返回一个字符在控制台屏幕上坐标的文件

#include<conio.h>//包含getch()库函数:从控制台读取一个字符,但不显示在屏幕上

//#define 定义的一些宏变量

//键盘上上、下、左、右四个键及一些按键对应的ASCII编码

#define KEY_UP    0xE048 

#define KEY_DOWN  0xE050

#define KEY_LEFT  0xE04B

#define KEY_RIGHT 0xE04D

#define KEY_ESC   0x001B

#define KEY_1     '1'

#define KEY_2     '2'

//设置游戏区域的最大长度与高度

#define GAME_MAX_WIDTH  100

#define GAME_MAX_HEIGHT 100

//游戏初始时在控制台上输出的游戏提示

#define GAMETITLE "ArrowKey:MoveCursor    KEY1:Open     Key2:Mark"

//当游戏结束时输出的字符

#define GAMEWIN   "Congratulations! You Win! Thank you for playing!\n"

#define GAMEOVER  "Sorry,you lose! thank you for playing!\n "

#define GAMEEND   "Press ESC to exit\n"

//基类

// Base class

class Base{

 public:

        static int Output(const char*);

        static int GotoXY(int, int);

        static int GetKey();  

};

    int Base::GetKey()//等待按下键,并返回所对应的按键控制符

 {         int nkey=getch(),nk=0;

        if(nkey>=128||nkey==0)nk=getch();//等待你按下任意键后,把该键字符所对应的ASCII符付给nk后,在执行下面语句

        return nk>0?nkey*256+nk:nkey;

    }  

    int Base::GotoXY(int x, int y)//取得控制台上光标的坐标位置并返回

    {

        COORD cd;

        cd.X = x;cd.Y = y;

        return SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),cd);

    }

   

    int Base::Output(const char* pstr)//在当前位置上输出一串字符

    {

        for(;*pstr;pstr++)putchar(*pstr);//函数向标准输出设备输出一个变量的字符形式         

        return 0;

    }

//继承

class Game:public Base

{  

    private:

        int curX,curY;

        int poolWidth,poolHeight;//雷区间的总高度与宽度,相当与height

        int pool[GAME_MAX_HEIGHT+2][GAME_MAX_WIDTH+2];

    public:

        Game():curX(0),curY(0){poolWidth=poolHeight=0;}

         int initpool(int,int,int);//初始化游戏区域,设置游戏区域的高度与宽度,并设置总雷数

                   int MoveCursor(){return Base::GotoXY(curX,curY);}

                   int huatu(int);//在控制台上把扫雷区域显示出来

                   int shownum(int,int);//得到一个坐标位置周围的雷数,并把数值返回

                   int tryopen(int,int);//在一个坐标点上(x,y)点击,在该位置上显示其周围的雷数或拓展空白区域或失败

                   int saolei();             

    private:

        int tuozhan(int, int);//如果一个坐标点的周围没有雷,则拓展空白区域,并递归拓展   

    private:

        const static int GMARK_BOOM;

        const static int GMARK_EMPTY;

        const static int GMARK_MARK;

};

 const int Game::GMARK_BOOM =  0x10; //*所对应的ASCII编码 ,用*表示地雷  

 const int Game::GMARK_EMPTY=  0x100;//空白所对应的ASCII编码

 const int Game::GMARK_MARK =  0x200;//#所对应的ASCII编码,用#表示作标记

int Game::initpool(int width,int height,int num)

                   {        poolWidth=width;

                            poolHeight=height;                   if(num<0||num>=width*height||width>GAME_MAX_HEIGHT||width<=0||height<=0||height>GAME_MAX_HEIGHT)                               return 1;

                            //初始是把游戏区域也即是数组里的值全都置为0

                            for(int y=0;y<=height+1;y++)

                            {

                                     for(int x=0;x<=width+1;x++)

                                     {

                                               pool[y][x]=0;

                                     }

                            }

                            //利用伪随机函数进行随机布雷,以保证每次点击游戏时雷的分布位置不同

                            srand(time(NULL));

                            while(num!=0){

                                     int x=rand()%width+1;

                                     int y=rand()%height+1;

                                     if(pool[y][x]==0){

                                               pool[y][x]=GMARK_BOOM;

                                               num--;//num为设置的总雷数}

                            }

                                     //初始化光标位置

               curX=1;curY=1;

                               MoveCursor();

                               return 0;

                            }

  //在控制台上把扫雷区域显示出来

    int Game::huatu(int n=0)

                            {

                                     for(int y=1;y<=poolHeight;y++)

                                     {

                                               Base::GotoXY(1,y);

                                               for(int x=1;x<=poolWidth;x++)

                                               {

                                                        if(pool[y][x]==0)

                                                                 putchar('.');

                                                        else if(pool[y][x]==GMARK_EMPTY)

                                                                 putchar(' ');

                                                        else if(pool[y][x]>0 && pool[y][x]<=8)

                                                        putchar('0'+pool[y][x]);

                                                        else if(n==0 && (pool[y][x]& GMARK_MARK) )

                                                                 putchar('#');

                                                        else if(pool[y][x]& GMARK_BOOM)

                                                        {

                                                                 if(n!=0)putchar('*');

                                                                 else

                                                                 putchar('.');

                                                        }

                                               }

                                     }                                   

                                     return 0;

                                     }

  

    //得到一个坐标位置周围的雷数,并把数值返回

      int Game::shownum(int x,int y){

                                     int count=0;

                                     for(int Y=-1;Y<=1;Y++)

                                               for(int X=-1;X<=1;X++){

                                                        if(pool[y+Y][x+X]&GMARK_BOOM)

                                                                 count++;}

                                               return count;

           }

    //在一个坐标点上(x,y)点击,在该位置上显示其周围的雷数或拓展空白区域或失败

                            int Game::tryopen(int x,int y){

                                     int m=0;

                                     if(pool[y][x] & GMARK_BOOM)m=-1;

                                     else{

                                               int count=shownum(x,y);

                                               if(count==0)tuozhan(x,y);//拓展空白区域

                                               else pool[y][x]=count;

                                     }

                                     return m;

                            }

//如果一个坐标点的周围没有雷,则拓展空白区域,并递归拓展

   int Game::tuozhan(int x,int y){

                                     if((x>0&&x<=poolWidth)&&(y>0&&y<=poolHeight)&&(pool[y][x]==0)){                                   

                                               int count=shownum(x,y);

                                               if(count==0){

                                                        pool[y][x]=GMARK_EMPTY;

                                                        for(int Y=-1;Y<=1;Y++)

                                                                 for(int X=-1;X<=1;X++)

                                                                 {tuozhan(x+X,y+Y);}

                                               }

                                               else pool[y][x]=count;

                                     }

                                     return 0;

                                     } 

    int Game::saolei()//游戏赢了返回1,按下ESC键退出游戏返回-1,记为输,扫到雷也是返回-1

    {

        int Key = Base::GetKey();

        int m = 0, nArrow = 0;

        switch (Key)

        {

            case KEY_UP:

            {

                if(curY>1)curY--;

                nArrow=1;

            }break;

            case KEY_DOWN:

            {  if(curY<poolHeight)curY++;

                nArrow=1;

            }break;

            case KEY_LEFT:

            {   if(curX>1)curX--;

                nArrow=1;

            }break;

            case KEY_RIGHT:

            {

                if(curX<poolWidth)curX++;

                nArrow=1;

            }break;

            case KEY_1:

            {

                m = tryopen(curX, curY);

            }break;

            case KEY_2:

            {

                if((pool[curY][curX]

                    & ~(GMARK_MARK|GMARK_BOOM))==0)

                {

                    pool[curY][curX] ^= GMARK_MARK;

                }

            }break;

          

            case KEY_ESC:

            {

                m =-1;

            }break;

        }

                    

        if(Key == KEY_1 )//判断是否赢了游戏

        {

            int y=1;

            for(;y<=poolHeight;++y)

            {

                int x=1;

                for(;x<=poolWidth; ++x)

                {

                    if(pool[y][x]==0)break;

                }

                if(x<=poolWidth) break;

            }

            if(! (y<=poolHeight))

            {

                m = 1;

            }

        }

        if(nArrow==0)

        {

           huatu();////如果按下了key_1,key_2键,则显示扫雷结果

         }

        MoveCursor();

        return m;

    }

        

      void main(){

                                     int x,y,b;//定义扫雷区域的高与宽,并设置游戏中得总雷数

                cout<<"宽度:";

                                     cin>>x;                       

                                     cout<<"高度:";

                                     cin>>y;                                

                                     cout<<"总雷数:";

                                     cin>>b;             

                                     int n;

                                     Game A;//定义类对象

                                     Base::GotoXY(0,0);

                                     Base::Output(GAMETITLE);

                                     A.initpool(x,y,b);

                                     A.huatu();

                                     A.MoveCursor();

                                     while((n=A.saolei())==0)

                                               ;//扫雷游戏进行

                                     //扫雷游戏结束时在控制台输出的结果

                                     A.huatu(1);//无论游戏成功与失败,均在屏幕上显示所有雷的位置

                     Base::Output("\n");

                                     if(n==1)

                      Base::Output(GAMEWIN);                      

                                     else

                                     {

                                      Base::Output(GAMEOVER);

                                     }

                                       Base::Output(GAMEEND);

           while(Base::GetKey()!=KEY_ESC);//按下ESC键退出游戏                  

            }

更多相关推荐:
扫雷课程设计报告

湖南文理学院课程设计报告课程名称:计算机课程扫地雷设计院系:电气与信息工程学院专业班级:通信09102班学生姓名:XX指导教师:完成时间:20XX.9.27扫地雷游戏设计综述在计算机逐步渗入社会生活各个层面的今…

扫雷游戏程序设计课程设计报告

课程设计设计题目学生姓名学专业班级20xx年11月5日合肥工业大学课程设计任务书一设计任务1鼠标左击排雷右击插小旗打问号2方格里面的数字表示方格周围的雷数3能够显示未标记雷数和游戏用时4雷区上面的小脸可以变化显...

Vb扫雷课程设计报告

Vb扫雷课程设计报告姓名班级学号难度知识点控件数组绘图菜单文本文件的读写多模块程序设计资源文件的使用1题目扫雷是windows下的经典小游戏如下图所示一个由M行N列小方格组成的雷区影藏着K颗地雷MN和K可以事先...

扫雷课程设计报告

C语言程序设计报告课程名称计算机课程扫雷设计院系建筑工程学院专业班级土木1102班成员姓名黄枭威王晓伟宋浩余彬李凯凯李婷婷张娣朱月梅子指导教师赵先完成时间20xx66报告成绩扫雷游戏设计综述在计算机逐步渗入社会...

C语言课程设计报告 扫雷

程序课程设计基础课程设计扫雷游戏院系计算机科学技术学院计算机科学与技术师范班级师计091设计者徐群杨松徐春辉杨雷刘安然学号3224312504指导教师黄绍义20xx年12月25日1目录1概述311研究的背景及意...

扫雷课程设计报告

大学课程设计院系名称计算机科学与工程学院班级学生姓名学号时间20xx0714课程设计题目扫雷游戏主要函数publicvoidDrawShellCPaintDCampdcvoidDrawMineCPaintDCa...

扫雷课程设计报告

扫雷游戏课程设计报告学学生姓名指导教师时间信息科学与工程学院计算机科学与技术程序设计实训扫雷游戏唐杰邹竞20xx年12月湖南涉外经济学院信息科学与工程学院摘要在计算机逐步渗入社会生活各个层面的今天计算机已经成为...

java_扫雷游戏课程设计报告

Java课程设计报告姓名学号院系班级专业1设计内容及要求11扫雷游戏的基本要求Windows20xxXP系统提供的扫雷游戏是一个很有趣的游戏本章的课程设计使用Java语言编写一个与其类似的扫雷游戏具体要求如下1...

扫雷游戏-课程设计报告

JAVA课程设计题目扫雷游戏院系计算机信息工程学院专业网络工程班级13级网络工程1班学生姓名方琴刘莉虹程子卿薛中意设计时间20xx年8月指导教师万中英提交日期20xx年10月8日摘要扫雷是一款大众类的益智小游戏...

JAVA课程设计扫雷(含代码)

Java程序课程设计任务书1设计内容及要求11扫雷游戏的基本要求Windows20xxXP系统提供的扫雷游戏是一个很有趣的游戏本章的课程设计使用Java语言编写一个与其类似的扫雷游戏具体要求如下1选择级别后将出...

JAVA_课程设计报告

JAVA程序设计课程设计报告设计题目学院名称专业班级姓名学号1目录一需求分析3二概要设计3三详细设计331数据库设计332模块及窗体设计3321数据库模块设计3322用户登录识别模块5323用户信息管理模块61...

软件课程设计报告

中南民族大学软件课程设计报告电子信息工程09级题目学生吴雪学号指导教师王锦程电子工程0907100220xx年4月25日简易网络聊天系统摘要计算机网络通信技术已经深入我们的生活并给我们即使通信带来了很大的方随着...

扫雷课程设计报告(23篇)