服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - 用C语言实现简单扫雷游戏

用C语言实现简单扫雷游戏

2021-12-07 15:12我还是学习吧 C/C++

这篇文章主要为大家详细介绍了用C语言实现简单扫雷游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

前言

本文写的是用C语言实现扫雷,用递归实现周围一圈无雷时,自动继续判断下一圈是否有雷,直到四周有地雷的信息。

最终结果展示

初始游戏界面

用C语言实现简单扫雷游戏

四周无地雷继续向外展开,直到出现地雷信息

用C语言实现简单扫雷游戏

项目创建

本项目由test.c,game.c,game.h构成,其中test.c用于测试,存放main函数,game.c存放具体函数定义,game.h引用头文件、定义预定义符号以及存放函数声明。

项目构思及实现

1.main函数

预期程序运行时先出现选择界面,玩家输入1进入游戏,输入0退出游戏,一次游戏结束后,再次弹出选择界面,于是考虑do while循环

下面是main函数的代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int main()
{
 int input;
 srand((unsigned)time(NULL));
 do
 {
  menu();
  printf("请选择:>");
  scanf("%d", &input);
  switch (input)
  {
  case 1:
   game();
   break;
  case 0:
   printf("退出游戏\n");
   break;
  default:
   printf("选择错误,请重新选择!\n");
   break;
  }
 } while (input);
 
 return 0;
}

2.menu函数

?
1
2
3
4
5
6
7
void menu()
{
 printf("********************************\n");
 printf("***********  1.play  ***********\n");
 printf("***********  0.exit  ***********\n");
 printf("********************************\n");
}

3.game函数

game函数是本项目实现的关键,根据扫雷的游戏界面的特点想到用字符数组储存信息,布雷功能由随机数实现,考虑到雷区信息在一局游戏里一直不变,想到用一个数组保存布雷信息,一个数组用于保存扫雷信息并用于打印。最关键的是扫雷功能的实现。

game函数的构架

1.定义两个数组
2.初始化数组
3.布雷
4.扫雷

下面是game函数的代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void game()
{
 char mine[ROWS][COLS] = { 0 };//存放雷的信息
 char show[ROWS][COLS] = { 0 };//存放排雷提示信息
 
 InitBoard(mine, ROWS, COLS, '0');
 InitBoard(show, ROWS, COLS, '*');
 
 //布雷
 SetMine(mine, ROW, COL);
 //DisplayBoard(mine, ROW, COL);//测试用,待会儿删
 DisplayBoard(show, ROW, COL);
 
 //扫雷
 FindMine(mine, show, ROW, COL);
}

4.InitBoard函数

mine数组里,0代表无雷,因此初始化时全部置为字符0;
show数组先全部置为*,扫雷时根据周围地雷数量替换数组内容为对应的数字字符。
下面是数组初始化函数InitBoard的代码

?
1
2
3
4
5
6
7
8
9
10
11
12
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
 int i;
 for (i = 0; i < rows; i++)
 {
  int j;
  for (j = 0; j < cols; j++)
  {
   board[i][j] = set;
  }
 }
}

5.SetMine布置地雷函数

接下来是实现布雷函数SetMine,下面是代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void SetMine(char board[ROWS][COLS], int row, int col)
{
 int count = EASY_COUNT;
 while (count)
 {
  int x = rand() % row + 1;//x代表第几行
  int y = rand() % col + 1;//y代表第几列
  if (board[x][y] != '1')//不能在同一个地方重复放雷
  {
   board[x][y] = '1';
   count--;
  }
 }
}

6.DisplayBoard打印界面函数

布置好地雷后需要打印界面,为了便于玩家确定坐标,在边界打印了行标和列标,这一功能由DisplayBoard实现

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
 int i = 0;
 printf("--------------------------\n");
 for (i = 0; i <= 9; i++)
 {
  printf("%d ", i);
 }
 printf("\n");
 for (i = 1; i <= row; i++)
 {
  int j;
  printf("%d ", i);
  for (j = 1; j <= col; j++)
  {
   printf("%c ", board[i][j]);
  }
  printf("\n");
 }
 printf("-------------------------\n");
}

7.FindMine扫雷函数

接下来是最关键的扫雷函数FineMine的实现,设计思路是根据数组mine判断用户输入坐标处是否有雷,有雷则游戏结束;无雷,则通过一个GetMineCount函数确定该位置周围8个位置有几个雷,根据返回结果,把show数组内容换成相应数字字符。同时,需要定义一个变量win来确定游戏是否结束,每确定一个位置无雷win加一,当win=总格子数-地雷数时,退出游戏。

需要注意的是,用户的输入需要在一定区域内,这里用if语句不难实现。

下面是代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
 int x = 0;
 int y = 0;
 int win = 0;
 while (win < row*col-EASY_COUNT)
 {
  printf("请输入要排查的坐标:>");
  scanf("%d %d", &x, &y);
  if (x >= 1 && x <= row && y >= 1 && y <= col)
  {
   if (mine[x][y] == '1')
   {
    printf("很遗憾,你被炸死了\n");
    DisplayBoard(mine, ROW, COL);
    break;
   }
   else//为提升游戏效率,这一部分可以改进
   {
    int count = GetMineCount(mine, x, y);
    show[x][y] = count + '0';
    DisplayBoard(show, ROW, COL);
    win++;
   }
  }
  else
  {
   printf("坐标非法,请重新输入\n");
  }
 }
 if (win == row * col - EASY_COUNT)
 {
  printf("恭喜,排雷成功\n");
  DisplayBoard(mine, ROW, COL);
 }
}

8.GetMineCount数地雷函数

接下来只要实现GetMineCount就可以实现扫雷的基本功能了
需要注意的是,mine数组里原先放的是字符0(代表无地雷)和字符1(代表有地雷),想到得到地雷的个数,这里的做法是先把周围8个数组的内容相加,再减去8个字符'0'即可。
但这时我们发现,当扫雷位置在边界时,会发生数组越界的情况,所以我们采用了定义数组比游戏区域大一圈的做法。
这里游戏界面设计成9*9。当然,由于各功能之间相互独立,只要在game.h中改变ROWS和COLS的值便可实现更大的游戏界面。

所以数组mine和show都是11*11的数组(show的作用主要是用来打印,设计成9*9也无妨,但为了与mine对应,这里设计成一样大)。

下面是GetMineCount的代码

?
1
2
3
4
5
6
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
 return (mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1] +
  mine[x][y - 1] + mine[x][y + 1] +
  mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] - 8 * '0');
}

9.Unfold展开函数

有了以上代码,扫雷已经可以玩了,但是每次只能扫一个雷,我们期望当一个位置周围八个位置都无地雷时,自动判断这八个位置的周围八个位置的地雷信息,这个功能用一个Unfold函数递归实现
需要注意的是,为了避免出现无限递归的情况,需要对扫过雷的位置做出标记,于是考虑把扫过雷的位置换成空格。
另一个去要注意的点是,为了避免数组越界,递归之前还要对坐标进行判断
这时,由于每次扫出无地雷位置的数量不确定,所以把win的地址传给函数,每确定一个位置win+1。

Unfold的递归条件:

  • 四周无地雷
  • 坐标不越界
  • 该位置没有判断过

     

下面是代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
void Unfold(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y,int *win)
{
 if (show[x][y] =='*')
 {
  *win+=1;
  int count = GetMineCount(mine, x, y);
  if (count == 0)
  {
   show[x][y] = ' ';
   if(((x-1)>=1)&&((x-1)<=9)&&((y-1)>=1)&&((y-1)<=9))
    Unfold(mine, show, x - 1, y - 1,win);
   if(((x - 1) >= 1) && ((x - 1) <= 9)&&(y>=1)&&(y<=9))
    Unfold(mine, show, x - 1, y,win);
   if(((x - 1) >= 1) && ((x - 1) <= 9)&&((y+1)>=1)&&((y+1)<=9))
    Unfold(mine, show, x - 1, y + 1,win);
   if((x>=1)&&(x<=9)&& ((y - 1) >= 1) && ((y - 1) <= 9))
    Unfold(mine, show, x, y - 1,win);
   if((x >= 1) && (x <= 9)&& ((y + 1) >= 1) && ((y + 1) <= 9))
    Unfold(mine, show, x, y + 1,win);
   if(((x+1)>=1)&&((x+1)<=9)&& ((y - 1) >= 1) && ((y - 1) <= 9))
    Unfold(mine, show, x + 1, y - 1,win);
   if(((x + 1) >= 1) && ((x + 1) <= 9)&& (y >= 1) && (y <= 9))
    Unfold(mine, show, x + 1, y,win);
   if(((x + 1) >= 1) && ((x + 1) <= 9)&& ((y + 1) >= 1) && ((y + 1) <= 9))
    Unfold(mine, show, x + 1, y + 1,win);
  }
  else
  {
   show[x][y] = count + '0';
   return;
  }
 }
}

FindMine也需要做出相应改变

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
 int x = 0;
 int y = 0;
 int win = 0;
 while (win < row*col-EASY_COUNT)
 {
  printf("请输入要排查的坐标:>");
  scanf("%d %d", &x, &y);
  if (x >= 1 && x <= row && y >= 1 && y <= col)
  {
   if (mine[x][y] == '1')
   {
    printf("很遗憾,你被炸死了\n");
    DisplayBoard(mine, ROW, COL);
    break;
   }
   else
   {
    Unfold(mine, show, x, y,&win);
    DisplayBoard(show, ROW, COL);
   }
  }
  else
  {
   printf("坐标非法,请重新输入\n");
  }
 }
 if (win == row * col - EASY_COUNT)
 {
  printf("恭喜,排雷成功\n");
  DisplayBoard(mine, ROW, COL);
 }
}

代码整合

test.c

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
 
void menu()
{
 printf("********************************\n");
 printf("***********  1.play  ***********\n");
 printf("***********  0.exit  ***********\n");
 printf("********************************\n");
}
 
void game()
{
 char mine[ROWS][COLS] = { 0 };//存放雷的信息
 char show[ROWS][COLS] = { 0 };//存放排雷提示信息
 
 InitBoard(mine, ROWS, COLS, '0');
 InitBoard(show, ROWS, COLS, '*');
 
 //布雷
 SetMine(mine, ROW, COL);
 //DisplayBoard(mine, ROW, COL);//测试用,待会儿删
 DisplayBoard(show, ROW, COL);
 
 //扫雷
 FindMine(mine, show, ROW, COL);
}
 
int main()
{
 int input;
 srand((unsigned)time(NULL));
 do
 {
  menu();
  printf("请选择:>");
  scanf("%d", &input);
  switch (input)
  {
  case 1:
   game();
   break;
  case 0:
   printf("退出游戏\n");
   break;
  default:
   printf("选择错误,请重新选择!\n");
   break;
  }
 } while (input);
 
 return 0;
}

game.c

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
 
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
 int i;
 for (i = 0; i < rows; i++)
 {
  int j;
  for (j = 0; j < cols; j++)
  {
   board[i][j] = set;
  }
 }
}
 
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
 int i = 0;
 printf("--------------------------\n");
 for (i = 0; i <= 9; i++)
 {
  printf("%d ", i);
 }
 printf("\n");
 for (i = 1; i <= row; i++)
 {
  int j;
  printf("%d ", i);
  for (j = 1; j <= col; j++)
  {
   printf("%c ", board[i][j]);
  }
  printf("\n");
 }
 printf("-------------------------\n");
}
 
void SetMine(char board[ROWS][COLS], int row, int col)
{
 int count = EASY_COUNT;
 while (count)
 {
  int x = rand() % row + 1;//x代表第几行
  int y = rand() % col + 1;//y代表第几列
  if (board[x][y] != '1')//不能在同一个地方重复放雷
  {
   board[x][y] = '1';
   count--;
  }
 }
}
 
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
 return (mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1] +
  mine[x][y - 1] + mine[x][y + 1] +
  mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] - 8 * '0');
}
 
void Unfold(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y,int *win)
{
 if (show[x][y] =='*')
 {
  *win+=1;
  int count = GetMineCount(mine, x, y);
  if (count == 0)
  {
   show[x][y] = ' ';
   if(((x-1)>=1)&&((x-1)<=9)&&((y-1)>=1)&&((y-1)<=9))
    Unfold(mine, show, x - 1, y - 1,win);
   if(((x - 1) >= 1) && ((x - 1) <= 9)&&(y>=1)&&(y<=9))
    Unfold(mine, show, x - 1, y,win);
   if(((x - 1) >= 1) && ((x - 1) <= 9)&&((y+1)>=1)&&((y+1)<=9))
    Unfold(mine, show, x - 1, y + 1,win);
   if((x>=1)&&(x<=9)&& ((y - 1) >= 1) && ((y - 1) <= 9))
    Unfold(mine, show, x, y - 1,win);
   if((x >= 1) && (x <= 9)&& ((y + 1) >= 1) && ((y + 1) <= 9))
    Unfold(mine, show, x, y + 1,win);
   if(((x+1)>=1)&&((x+1)<=9)&& ((y - 1) >= 1) && ((y - 1) <= 9))
    Unfold(mine, show, x + 1, y - 1,win);
   if(((x + 1) >= 1) && ((x + 1) <= 9)&& (y >= 1) && (y <= 9))
    Unfold(mine, show, x + 1, y,win);
   if(((x + 1) >= 1) && ((x + 1) <= 9)&& ((y + 1) >= 1) && ((y + 1) <= 9))
    Unfold(mine, show, x + 1, y + 1,win);
  }
  else
  {
   show[x][y] = count + '0';
   return;
  }
 }
}
 
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
 int x = 0;
 int y = 0;
 int win = 0;
 while (win < row*col-EASY_COUNT)
 {
  printf("请输入要排查的坐标:>");
  scanf("%d %d", &x, &y);
  if (x >= 1 && x <= row && y >= 1 && y <= col)
  {
   if (mine[x][y] == '1')
   {
    printf("很遗憾,你被炸死了\n");
    DisplayBoard(mine, ROW, COL);
    break;
   }
   else
   {
    //int count = GetMineCount(mine, x, y);
    //show[x][y] = count + '0';
    //DisplayBoard(show, ROW, COL);
    //win++;
    
    Unfold(mine, show, x, y,&win);
    DisplayBoard(show, ROW, COL);
   }
  }
  else
  {
   printf("坐标非法,请重新输入\n");
  }
 }
 if (win == row * col - EASY_COUNT)
 {
  printf("恭喜,排雷成功\n");
  DisplayBoard(mine, ROW, COL);
 }
}

game.h

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
 
#define ROW 9
#define COL 9
#define ROWS 11
#define COLS 11
#define EASY_COUNT 10
 
void InitBoard(char board[ROWS][COLS],int row,int col,char set);
void DisplayBoard(char board[ROWS][COLS], int row, int col);
void SetMine(char board[ROWS][COLS], int row, int col);
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
void Unfold(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y);

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/m0_56611833/article/details/119188506

延伸 · 阅读

精彩推荐
  • C/C++关于C语言中E-R图的详解

    关于C语言中E-R图的详解

    今天小编就为大家分享一篇关于关于C语言中E-R图的详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看...

    Struggler095962021-07-12
  • C/C++C语言main函数的三种形式实例详解

    C语言main函数的三种形式实例详解

    这篇文章主要介绍了 C语言main函数的三种形式实例详解的相关资料,需要的朋友可以参考下...

    ieearth6912021-05-16
  • C/C++OpenCV实现拼接图像的简单方法

    OpenCV实现拼接图像的简单方法

    这篇文章主要为大家详细介绍了OpenCV实现拼接图像的简单方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    iteye_183805102021-07-29
  • C/C++c/c++内存分配大小实例讲解

    c/c++内存分配大小实例讲解

    在本篇文章里小编给大家整理了一篇关于c/c++内存分配大小实例讲解内容,有需要的朋友们可以跟着学习参考下。...

    jihite5172022-02-22
  • C/C++c/c++实现获取域名的IP地址

    c/c++实现获取域名的IP地址

    本文给大家汇总介绍了使用c/c++实现获取域名的IP地址的几种方法以及这些方法的核心函数gethostbyname的详细用法,非常的实用,有需要的小伙伴可以参考下...

    C++教程网10262021-03-16
  • C/C++深入C++拷贝构造函数的总结详解

    深入C++拷贝构造函数的总结详解

    本篇文章是对C++中拷贝构造函数进行了总结与介绍。需要的朋友参考下...

    C++教程网5182020-11-30
  • C/C++C语言实现双人五子棋游戏

    C语言实现双人五子棋游戏

    这篇文章主要为大家详细介绍了C语言实现双人五子棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    两片空白7312021-11-12
  • C/C++使用C++制作简单的web服务器(续)

    使用C++制作简单的web服务器(续)

    本文承接上文《使用C++制作简单的web服务器》,把web服务器做的功能稍微强大些,主要增加的功能是从文件中读取网页并返回给客户端,而不是把网页代码...

    C++教程网5492021-02-22