项目创建及其代码分类

test.c - 游戏逻辑代码编写

game.h - 游戏函数声明,符号定义,头文件的包含

game.c - 游戏函数代码实现

主函数和菜单函数

test.c中编写主函数代码

使用do while循环

调用menu函数

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 = 0;
do
{
menu();
printf("请选择:>");
scanf("%d",&input);
switch (input)
{
case 1:
printf("开始扫雷游戏\n");
printf("游戏需要输入坐标(如:1 2)\n");
game();//扫雷游戏
break;
case 0:
printf("退出游戏");
break;
default:
printf("选择错误,请重新选择");
break;
}
} while (input);
return 0;
}

在主函数上面定义并实现menu函数

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

头文件

在头文件game.h中引入我们需要的C语言头文件

1
2
#include <stdio.h>
#include <string.h>

然后在其他源文件下引用该文件即可

1
#include "game.h"

这样就不用频繁的在各个源文件中引入C语言头文件了

编写游戏逻辑代码

确认需求

要做一个扫雷的小游戏,首先需要定义一个9*9雷区也就是先创建出一个二维的数组

然后初始化雷区(数组),并打印输出

而布置雷,我们可以使用随机数了布置雷

然后就是排查雷,我们需要让它在点击后显示周围的雷的数量,这可以使用循环遍历的方法

那么会出现一个问题,如果我们的雷在边缘位,在遍历时会遍历到数组大小之外的地方,导致越界

我们可以创建两个二维数组,一个用于存放布置好的雷,一个用于存放排查出的雷的信息

然后把这两个二维数组的行和列都改为11,这样就不用担心越界的问题

创建二维数组和初始化雷区

我们在主函数上面定义了game函数

然后根据需求,创建出两个二维数组,然后初始化雷区

1
2
3
4
5
void game()
{
char mine[ROWS][COLS];//存放布置好的雷
char show[ROWS][COLS];//存放排查出的雷的信息,用于打印
}

然后我们在头文件中用define定义常量行和列

这里可以分别定义两个,一个是整个数组的行列,一个是需要显示出来的行列

1
2
3
4
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2

然后调用InitBoard初始化雷区,两个数组都要初始化

1
2
3
4
5
6
7
8
void game()
{
char mine[ROWS][COLS];//存放布置好的雷
char show[ROWS][COLS];//存放排查出的雷的信息,用于打印
//初始化雷区
InitBoard(mine, ROWS, COLS,'0');//初始化为全是 0
InitBoard(show, ROWS, COLS,'*');//初始化为全是 *
}

头文件声明函数

1
2
3
//声明函数
//初始化雷区
void InitBoard(char board[ROWS][COLS], int rows, int cols,char set);

game.c中实现函数

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 = 0;
int j = 0;
for ( i = 0; i < rows; i++)
{
for ( j = 0; j < cols; j++)
{
board[i][j] = set;//把数组全部初始化为传过来的set字符
}
}
}

打印雷区

然后我们需要打印雷区,方便玩家查看

首先调用DisPlayBoard函数打印雷区

1
2
3
4
5
6
7
8
9
10
void game()
{
char mine[ROWS][COLS];//存放布置好的雷
char show[ROWS][COLS];//存放排查出的雷的信息,用于打印
//初始化雷区
InitBoard(mine, ROWS, COLS,'0');//初始化为全是 0
InitBoard(show, ROWS, COLS,'*');//初始化为全是 *
//打印雷区
DisPlayBoard(show, ROW, COL);//传过去的是11*11的数组,而行和列我们只要9*9的即可
}

头文件声明函数

1
2
//打印雷区
void DisPlayBoard(char board[ROWS][COLS], int row, int col);

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
//打印雷区
void DisPlayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("------扫雷游戏------\n");
//打印行数
for ( i = 0; i <= row; i++)
{
printf("%d ",i);
}
printf("\n");
for (i = 1; i <=row; i++)
{
printf("%d ",i);//打印列数
for (j = 1; j <=col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("------扫雷游戏------\n");
}

布置雷

我们需要使用随机数来随机布置雷的位置

在主函数中使用srand()

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
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:>");
scanf("%d",&input);
switch (input)
{
case 1:
printf("开始扫雷游戏\n");
printf("游戏需要输入坐标(如:1 2)\n");
game();//扫雷游戏
break;
case 0:
printf("退出游戏");
break;
default:
printf("选择错误,请重新选择");
break;
}
} while (input);
return 0;
}

然后在game函数中调用SetMine函数

1
2
3
4
5
6
7
8
9
10
11
12
void game()
{
char mine[ROWS][COLS];//存放布置好的雷
char show[ROWS][COLS];//存放排查出的雷的信息,用于打印
//初始化雷区
InitBoard(mine, ROWS, COLS,'0');//初始化为全是 0
InitBoard(show, ROWS, COLS,'*');//初始化为全是 *
//打印雷区
DisPlayBoard(show, ROW, COL);//传过去的是11*11的数组,而行和列我们只要9*9的即可
//布置雷
SetMine(mine, ROW, COL);
}

声明函数

1
2
//布置雷
void SetMine(char board[ROWS][COLS], int row, int col);

game.c中实现函数

这里需要使用 % 来随机生成下标,但是下标不能为0和10,否则就超出了该显示的位置

让数组元素为 1 代表有雷,0就是没有雷

把雷的总数用define定义,写在头文件中

1
#define BOOM 10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//布置雷
void SetMine(char mine[ROWS][COLS], int row, int col)
{
//布置10个雷
int count = BOOM;
while (count)
{
//随机生成下标
int x = rand() % row+1;
int y = rand() % col+1;
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;
}
}
}

不要忘记了引用库函数所需的头文件

1
2
#include <time.h>
#include <stdlib.h>

排查雷

game函数中调用FindMine函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void game()
{
char mine[ROWS][COLS];//存放布置好的雷
char show[ROWS][COLS];//存放排查出的雷的信息,用于打印
//初始化雷区
InitBoard(mine, ROWS, COLS,'0');//初始化为全是 0
InitBoard(show, ROWS, COLS,'*');//初始化为全是 *
//打印雷区
DisPlayBoard(show, ROW, COL);//传过去的是11*11的数组,而行和列我们只要9*9的即可
//布置雷
SetMine(mine, ROW, COL);
//排查雷
FindMine(mine, show, ROW, COL);
}

声明函数

1
2
//布置雷
void SetMine(char board[ROWS][COLS], int row, int col);

在排查雷的时候,我们输入排查雷的坐标

判断其合法性后,判断该位置是否是雷

如果是雷,炸死;如果不是雷,遍历周围的数组元素,获取到周围雷的数量

获取周围雷数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//获取周围雷数
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
int i = 0;
int j = 0;
int count = 0;
for (i = x - 1; i <= x + 1; i++)
{
for (j = y - 1; j <= y + 1; j++)
{
if (mine[i][j] == '1')
{
count++;
}
}
}
return count;
//或者
//前面说到 数字加上 '0'后变成字符
//那么八个字符相加后减去八个字符'0'后就变成了数字
/*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';*/
}

排查雷

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
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
//1.输入排查的坐标
//2.检查坐标是不是雷
// 是雷,炸死
// 不是雷,继续,并统计坐标周围的雷数
int x = 0;
int y = 0;
int win = 0;//记录次数
while (win < row * col - BOOM)
{
printf("请输入要排查的坐标:>");
while (getchar() != '\n')
{
}
scanf("%d %d", &x, &y);//1~9的下标
//判断坐标是否合法
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
//是雷
printf("BOOM!!!!你被炸死了\n");
show[x][y] = '@';//用@代表雷
DisPlayBoard(show, ROW, COL);
break;
}
else
{
//不是雷
int num = GetMineCount(mine,x,y);
show[x][y] = num + '0';//加上字符 0 后变为字符 3
DisPlayBoard(show, ROW, COL);
win++;
}
}
else
{
printf("坐标不合法,请重新输入\n");
}
}
if (win == row * col - BOOM)
{
printf("你赢了,你就是扫雷大师!!\n");
DisPlayBoard(mine, ROW, COL);
}

}

功能增加

到了上面,就完成了扫雷游戏的编写,不过我们还能进行功能的优化

比如说,在点击之后,如果该位置周围没有雷,会展开

类似:

那么要完成这个功能我们需要使用递归的方法实现

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 Expand(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y, int* win)
{
//必须要限制其在显示的雷区展开,不能超过,否则会死递归
if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
{
int i = 0;
int j = 0;
//获取雷的总数
int count = GetMineCount(mine,x,y);
//没有雷的话开始递归
if (count == 0)
{
show[x][y] = '0';
for (i = x - 1; i <= x + 1; i++)
{
for (j = y - 1; j <= y + 1; j++)
{
//只展开 * ,不然会死循环
if (show[i][j] == '*')
{
Expand(mine, show, i, j, win);
}
}
}

}
else
{
//有雷显示周围的雷数量
show[x][y] = count + '0';//加上字符 0 后变为字符 3
}
//记录展开的次数
(*win)++;
}
}

修改一下排查雷FindMine函数

直接调用Expand即可

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
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
//1.输入排查的坐标
//2.检查坐标是不是雷
// 是雷,炸死
// 不是雷,继续,并统计坐标周围的雷数
int x = 0;
int y = 0;
int win = 0;//记录次数
while (win < row * col - BOOM)
{
printf("请输入要排查的坐标:>");
while (getchar() != '\n')
{
}
scanf("%d %d", &x, &y);//1~9的下标
//判断坐标是否合法
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
//是雷
printf("BOOM!!!!你被炸死了\n");
printf("BOOM!!!!你被炸死了\n");
printf("BOOM!!!!你被炸死了\n");
show[x][y] = '@';//用@代表雷
DisPlayBoard(show, ROW, COL);
break;
}
else
{
Expand(mine,show, x, y, &win);
DisPlayBoard(show, ROW, COL);
//不是雷
//int num = GetMineCount(mine,x,y);
//show[x][y] = num + '0';//加上字符 0 后变为字符 3
//DisPlayBoard(show, ROW, COL);
//win++;
}
}
else
{
printf("坐标不合法,请重新输入\n");
}
}
if (win == row * col - BOOM)
{
printf("你赢了,你就是扫雷大师!!\n");
printf("你赢了,你就是扫雷大师!!\n");
printf("你赢了,你就是扫雷大师!!\n");
DisPlayBoard(mine, ROW, COL);
}

}

然后在game函数里加上重新开始游戏的倒计时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//雷 - 1
//没雷 - 0
void game()
{
char mine[ROWS][COLS];//存放布置好的雷
char show[ROWS][COLS];//存放排查出的雷的信息,用于打印
//初始化雷区
InitBoard(mine, ROWS, COLS,'0');//初始化为全是 0
InitBoard(show, ROWS, COLS,'*');//初始化为全是 *
//打印雷区
DisPlayBoard(show, ROW, COL);//传过去的是11*11的数组,但是我们只要9*9的行列即可
//布置雷
SetMine(mine, ROW, COL);
//DisPlayBoard(mine, ROW, COL);
//排查雷
FindMine(mine, show, ROW, COL);
Sleep(1000);
for (int i = 5; i > 0; i--)
{
printf("倒计时后重新开始游戏:%d\n", i);
Sleep(1000);
}
system("cls");
}

功能展示

代码展示

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
54
55
56
57
58
59
60
61
#define _CRT_SECURE_NO_WARNINGS 1

#include "game.h"
//菜单
void menu()
{
printf("**********************************\n");
printf("********** 1.play **********\n");
printf("********** 0.exit **********\n");
printf("**********************************\n");
}
//雷 - 1
//没雷 - 0
void game()
{
char mine[ROWS][COLS];//存放布置好的雷
char show[ROWS][COLS];//存放排查出的雷的信息,用于打印
//初始化雷区
InitBoard(mine, ROWS, COLS,'0');//初始化为全是 0
InitBoard(show, ROWS, COLS,'*');//初始化为全是 *
//打印雷区
DisPlayBoard(show, ROW, COL);//传过去的是11*11的数组,但是我们只要9*9的行列即可
//布置雷
SetMine(mine, ROW, COL);
//DisPlayBoard(mine, ROW, COL);
//排查雷
FindMine(mine, show, ROW, COL);
Sleep(1000);
for (int i = 5; i > 0; i--)
{
printf("倒计时后重新开始游戏:%d\n", i);
Sleep(1000);
}
system("cls");
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:>");
scanf("%d",&input);
switch (input)
{
case 1:
printf("开始扫雷游戏\n");
printf("游戏需要输入坐标(如:1 2)\n");
game();//扫雷游戏
break;
case 0:
printf("退出游戏");
break;
default:
printf("选择错误,请重新选择");
break;
}
} while (input);
return 0;
}

game.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#pragma once

#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define BOOM 10

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <windows.h>

//声明函数
//初始化雷区
void InitBoard(char board[ROWS][COLS], int rows, int cols,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);

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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#define _CRT_SECURE_NO_WARNINGS 1

#include "game.h"
//初始化雷区
void InitBoard(char board[ROWS][COLS], int rows, int cols,char set)
{
int i = 0;
int j = 0;
for ( i = 0; i < rows; i++)
{
for ( j = 0; j < cols; j++)
{
board[i][j] = set;//把数组全部初始化为传过来的set字符
}
}
}
//打印雷区
void DisPlayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
printf("------扫雷游戏------\n");
//打印行数
for ( i = 0; i <= row; i++)
{
printf("%d ",i);
}
printf("\n");
for (i = 1; i <=row; i++)
{
printf("%d ",i);//打印列数
for (j = 1; j <=col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("------扫雷游戏------\n");
}
//布置雷
void SetMine(char mine[ROWS][COLS], int row, int col)
{
//布置10个雷
int count = BOOM;
while (count)
{
//随机生产下标
int x = rand() % row+1;
int y = rand() % col+1;
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;
}
}
}
//获取周围雷数
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
int i = 0;
int j = 0;
int count = 0;
for (i = x - 1; i <= x + 1; i++)
{
for (j = y - 1; j <= y + 1; j++)
{
if (mine[i][j] == '1')
{
count++;
}
}
}
return count;
//或者
//前面说到 数字加上 '0'后变成字符
//那么八个字符相加后减去八个字符'0'后就变成了数字
/*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 Expand(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y, int* win)
{
//必须要限制其在显示的雷区展开,不能超过,否则会死递归
if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
{
int i = 0;
int j = 0;
//获取雷的总数
int count = GetMineCount(mine,x,y);
//没有雷的话开始递归
if (count == 0)
{
show[x][y] = '0';
for (i = x - 1; i <= x + 1; i++)
{
for (j = y - 1; j <= y + 1; j++)
{
//只展开 * ,不然会死循环
if (show[i][j] == '*')
{
Expand(mine, show, i, j, win);
}
}
}

}
else
{
//有雷显示周围的雷数量
show[x][y] = count + '0';//加上字符 0 后变为字符 3
}
//记录展开的次数
(*win)++;
}
}
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
//1.输入排查的坐标
//2.检查坐标是不是雷
// 是雷,炸死
// 不是雷,继续,并统计坐标周围的雷数
int x = 0;
int y = 0;
int win = 0;//记录次数
while (win < row * col - BOOM)
{
printf("请输入要排查的坐标:>");
while (getchar() != '\n')
{
}
scanf("%d %d", &x, &y);//1~9的下标
//判断坐标是否合法
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
//是雷
printf("BOOM!!!!你被炸死了\n");
printf("BOOM!!!!你被炸死了\n");
printf("BOOM!!!!你被炸死了\n");
show[x][y] = '@';//用@代表雷
DisPlayBoard(show, ROW, COL);
break;
}
else
{
Expand(mine,show, x, y, &win);
DisPlayBoard(show, ROW, COL);
//不是雷
//int num = GetMineCount(mine,x,y);
//show[x][y] = num + '0';//加上字符 0 后变为字符 3
//DisPlayBoard(show, ROW, COL);
//win++;
}
}
else
{
printf("坐标不合法,请重新输入\n");
}
}
if (win == row * col - BOOM)
{
printf("你赢了,你就是扫雷大师!!\n");
printf("你赢了,你就是扫雷大师!!\n");
printf("你赢了,你就是扫雷大师!!\n");
DisPlayBoard(mine, ROW, COL);
}

}

扫雷游戏程序下载地址

点击此处进行下载