Limit-fly 发表于 2018-7-23 21:16

C++扫雷小游戏源码

上次发过一个俄罗斯方块的游戏源码,由于是通过Easy X实现的,但是很多和我一样的新手,一开始不知道Easy X是什么,到时源码拿过去之后,运行报错,我这次发的扫雷,
也是通过Easy X实现,Easy X是很多和我一样的新手在学习的时候用到的一个绘图工具,毕竟都不想天天对着一个黑漆漆的控制台,所以今天我发扫雷的源码的时候,会附赠上
Easy X的安装程序。
同样这个扫雷的小游戏是很多和我一样新手学习中所制作的一个小项目,仅当练手,大佬肯定有用win32实现的,QT实现的,但是小萌新现在还不会这么高端,仅限新手!


源码附上
#include<stdio.h>
#include<graphics.h>
#include<time.h>

#define N 20               //20*20的游戏地图
#define M 25               //每个区域边长为25

HWND hWnd;               //窗口句柄
int win;                   //记录翻开的个数,用来判断输赢

//函数声明
void game();                                 //开始游戏
void drawmap(int map[], IMAGE* img);//绘制地图
int play(int map[]);                  //玩游戏,主要是鼠标操作
void swap(int map[], int x, int y);   //翻开0,翻开一片

int main()
{
    while (1)
    {
      game();
      if (MessageBox(hWnd, L"再玩一局?", L"退出", MB_RETRYCANCEL) == IDCANCEL)
      {
      break;
      }
    }
    closegraph();
    return 0;
}


void game()
{
    //创建窗口
    initgraph(M * N, M * N);
    //生成一个扫雷地图 20*20
    //周围一圈作为辅助,防止数组越界
    int map = { 0 };
    int m, n, i, j;
    //随机数种子
    srand((unsigned)time(NULL));
    //埋雷
    for (n = 0; n < 2 * N;)//循环多少次就埋下几个雷
    {
      i = rand() % N + 1;//生成1-N之间的随机数
      j = rand() % N + 1;//作为数组下标
      //判断这里是否是空地,如果有雷,就重新选择区域埋雷
      if (map == 0)
      {
            map = -1;//用-1表示地雷
            n++;
         }
    }
    //埋数字
    for (i = 1; i <= N; i++)
    {
      for (j = 1; j <= N; j++)
      {
            if (map != -1)               //判断这里是不是雷
            {
                for (m = i - 1; m <= i + 1; m++) //扫描当前位置的周围区域
                {
                  for (n = j - 1; n <= j + 1; n++)
                  {
                        if (map == -1)
                        {
                            map++;          //找到一个周围是雷的位置,当前位置就加1
                                             //有几个雷,数组元素的值就为几
                        }
                  }
                }
            }
      }
    }

    //画图 将数组转换为扫雷图
    IMAGE img;
    //加载图片
    loadimage(&img, L"0.jpg", M, M);
    loadimage(&img, L"1.jpg", M, M);
    loadimage(&img, L"2.jpg", M, M);
    loadimage(&img, L"3.jpg", M, M);
    loadimage(&img, L"4.jpg", M, M);
    loadimage(&img, L"5.jpg", M, M);
    loadimage(&img, L"6.jpg", M, M);
    loadimage(&img, L"7.jpg", M, M);
    loadimage(&img, L"8.jpg", M, M);
    loadimage(&img, L"雷.jpg", M, M);
    loadimage(&img, L"地图.jpg", M, M);
    loadimage(&img, L"标记.jpg", M, M);

    hWnd = GetHWnd();//Messagebox窗口置前
    win = 0;//重置胜利条件
    while (1)
    {
      drawmap(map, img);
      if (play(map) == 9)
      {
            //表示点开了一个雷
            drawmap(map, img);
            MessageBox(hWnd, L"炸弹来咯", L"BOOM", MB_OK);
            return;
      }
      //游戏是否继续 胜利条件 点开了所有非雷区域
      if (win == N*M - 2*N)
      {
            drawmap(map, img);
            MessageBox(hWnd, L"你赢了", L"WELL PLAYED", MB_OK);
            break;
      }
    }
}


//画图
void drawmap(int map[], IMAGE *img)
{
    for (int i = 1; i <= N; i++)
    {
      for (int j = 1; j <= N; j++)
      {
            //右键标记数组元素值+30
            if (map >= 20)
            {
                //标记部分额外处理
                putimage(M * (i - 1), M * (j - 1), &img);
                continue;
            }
            switch (map)
            {
                case 9:
                  putimage(M * (i - 1), M * (j - 1), &img);//雷 -1为雷
                  break;
                case 10:
                  putimage(M * (i - 1), M * (j - 1), &img); //点击之后的取值9~19
                  break;
                case 11:
                  putimage(M * (i - 1), M * (j - 1), &img);
                  break;
                case 12:
                  putimage(M * (i - 1), M * (j - 1), &img);
                  break;
                case 13:
                  putimage(M * (i - 1), M * (j - 1), &img);
                  break;
                case 14:
                  putimage(M * (i - 1), M * (j - 1), &img);
                  break;
                case 15:
                  putimage(M * (i - 1), M * (j - 1), &img);
                  break;
                case 16:
                  putimage(M * (i - 1), M * (j - 1), &img);
                  break;
                case 17:
                  putimage(M * (i - 1), M * (j - 1), &img);
                  break;
                case 18:
                  putimage(M * (i - 1), M * (j - 1), &img);
                  break;
                default:
                  putimage(M * (i - 1), M * (j - 1), &img); //初始化都为空(-1~8)标记为空
                  break;
            }
      }
    }
}



int play(int map[])
{
    MOUSEMSG msg;                                     //获取鼠标位置
    while (1)
    {
      msg = GetMouseMsg();                        //获取鼠标消息
      switch (msg.uMsg)                           //判断当前鼠标消息
      {
            case WM_LBUTTONDOWN:                        //左键点开
                                                      //>9表示已经点开或者标记,不能再再点击
                if (map >9)
                {
                  continue;
                }
                //=0翻开一片
                if (map == 0)
                {
                  swap(map, msg.x / M + 1, msg.y / M + 1);
                }
                //翻到数字或者雷,直接翻开
                else
                {
                  map += 10;
                  win++;
                }
                return map;
            break;
      case WM_RBUTTONDOWN:                           //右键标记,取消标记
                                                   //没有翻开的标记,+30
            if (map<9)
            {
                map += 30;
            }
            //标记了的,取消标记
            else if (map >= 20)
            {
                map -= 30;
            }
            //点击翻开区域无效
            else
            {
                continue;
            }
            return 0;
            break;

      }
    }
}

void swap(int map[], int x, int y)
{
    map = 10;                                 //点到0,先翻开点击的位置
    win++;
    int i, j;
    //遍历点击点周围区域
    for (i = x - 1; i <= x + 1; i++)
    {
      for (j = y - 1; j <= y + 1; j++)
      {
            if (i >= 1 && i <= N && j >= 1 && j <= N) //判断是否越界
            {
                if (map<9)                      //没有翻开
                {
                  if (map == 0)               //=0
                  {
                        swap(map, i, j);            //如果没翻开并且为空就递归
                  }
                  else                              //否则直接翻开
                  {
                        map += 10;
                        win++;
                  }
                }
            }
      }
    }
    return;
}

以上是全部源代码!
下面的是扫雷的素材以及Easy X图形库工具。




山野村夫-陈墨 发表于 2019-7-1 22:52

if (map >9)
                {
                  continue;
                }
好!
但是,map是STL关键字,这样命名不太好,我觉得。

Limit-fly 发表于 2018-7-23 21:49

夜晚528 发表于 2018-7-23 21:40
这个应该怎么学   零基础

你需要一本书,从开始最基础的变量开始,循环语句,其次结构体,函数,指针,在学数据结构等,很多多,你会发现开始学了,这个事学无止境的,慢慢加油吧!

STRIVE_Oriana 发表于 2018-7-23 21:30

好滴先get等以后再尝试研读一下谢大佬

c0co123 发表于 2018-7-23 21:39

先MARK后学

夜晚528 发表于 2018-7-23 21:40

这个应该怎么学   零基础

金陵北少 发表于 2018-7-23 21:52

mark      

hhh3h 发表于 2018-7-23 22:08

哈哈,我拿来看看谢谢了

linuxprobe 发表于 2018-7-23 22:09

扫雷游戏这种代码只能是练练手。

gunxsword 发表于 2018-7-23 22:32

写的不错,感谢分享!

zzyx 发表于 2018-7-23 23:06

mark下先!
页: [1] 2 3 4
查看完整版本: C++扫雷小游戏源码