前言
本文写的是用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