服务器之家

服务器之家 > 正文

C语言实现简易扫雷游戏详解

时间:2021-12-14 15:03     来源/作者:快乐的星球

本文实例为大家分享了C语言实现简易扫雷游戏的具体代码,供大家参考,具体内容如下

一、想要达到的游戏功能:

大家如果想编写一个游戏,应具备以下的步骤:

1:了解游戏的规则

2:   知道游戏应该实现哪些功能

3:根据这些功能构建出游戏的基本框架

4:如何将整个游戏拆分成一个个模块,进行模块化编程

我们拿到一个任务,尤其是编写像扫雷这对于初学者有难度的问题时,应该做到先理清思路,再进行代码编写,现在我们来讲一下扫雷游戏预期实现的功能。

1:要有一个游戏菜单能让玩家选择进入游戏还是退出游戏。

2:程序能够实现反复玩,玩家玩完一盘后可以进行选择是否继续游戏还是退出。

3:应该有一个game函数来进入游戏后游戏的整体功能

game中应有的功能:

1:创建两个棋盘二维数组:一个棋盘是放置雷的,另一个棋盘则是玩家游戏时看到的棋盘。

(注意如果只有一个棋盘:那么这个棋盘数组要放1:表示有雷  还要放0表示无雷。此时棋盘已经放满,但还需要表示玩家扫雷时显示该位置周围的雷数,因此一个棋盘数组不方便做到)

2:编写一个函数对数组进行初始化:比如把mine(表示放置雷数组)全部初始化成0(表示无雷),将show(表示展示给玩家看并进行排雷的数组)全部初始化成'*'(表示此位置没有被查过,像网页版上没有排雷之前的空白一样)

3:编写一个函数进行放置雷,即在mine数组中随机选取位置放置'1‘(表示此位置有雷)

4:编写一个函数表示在mine数组中一个位置周围的雷数,并将它传递给show,这样在排雷后,如果没有被炸死就会显示这个位置的雷数

5:编写一个递归函数其功能是如果一个位置显示0(即周围的雷数为0),会先把自己的位置变成空格,再检索周围8个数组元素,把表示为0的也重置成空格。以上的目的是实现像网页版一样,点开一个空格展开一片空格。

6:让玩家输入坐标进行排雷(此过程应是一个循环),并且能反馈”很遗憾!你被炸死了。“和”恭喜你排雷成功!“两种结果

二、代码展示环节:

为了更加清晰有条理的编写程序,我们用多文件的方式来呈现。

1:text.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
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#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, '*');
 
 
 //在mine数组中进行放置雷
 SetMine(mine, ROW, COL);
 
 //打印出show棋盘给玩家看
 DisplayBoard(show, ROW, COL);
 
 //进行排雷
 FindMine(mine, show, ROW, COL);
 
 
}
 
int main()
{
 srand((unsigned int)time(NULL));
 int input = 0;
 do {
  menu();
  printf("请选择>:\n");
  scanf("%d", &input);
  //在菜单中选择是否进入游戏
  //因为要实现反复玩,所以用do while循环
  switch (input)
  {
  case 1:
   game();
   break;
  case 0:
   printf("退出游戏\n");
   break;
  default:
   printf("输入的是无效指令,请重新输入:\n");
   break;
  }
 
 } while (input);
 return 0;
}

2:进行game.c功能的实现

1:在game.h中进行游戏函数的声明:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#pragma once
#define ROW 9
#define COL 9//玩家操作的棋盘应该是9*9的
//但为了防止在查雷的数目时,9*9边缘的格子周围并没有8个格子
#define ROWS ROW+2
#define COLS COL+2
#define MineCount 10//定义雷的数目
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
//初始化棋盘数组的声明
void InitBoard(char arr[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);
//求mine数组中一个位置周围的雷数
int GetMineCount(char mine[ROWS][COLS], int x, int y);
//排雷函数的声明
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

2:初始化棋盘数组函数的定义

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//这里进行棋盘数组的初始化
//
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
 int i = 0;
 for (i = 0; i < rows; i++)
 {
  int j = 0;
  for (j = 0; j < cols; j++)
  {
   board[i][j] = set;//这里的set存放的是0或*,方便测试时两个棋盘的打印
  }
 }
}

3:棋盘打印函数的实现

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
 int i = 1;
 printf("---------------------------------\n");
 for (i = 0; i <= col; i++)
 {
  printf("%d ", i);
 }
 printf("\n");//打印棋盘的坐标序号
 for (i = 1; i <= row; i++)
 {
  printf("%d ", i);
  int j = 1;
  for (j = 1; j <= col; j++)
  {
   printf("%c ", board[i][j]);
  }
  printf("\n");
 }
 //棋盘数组元素的定义
 printf("------------------------------\n");
}

4:放置雷函数的实现

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//这里来实现放置雷的功能
void SetMine(char board[ROWS][COLS], int row, int col)
{
 int count =10;//总共放置10颗雷
 while (count)
 {
  int x = rand() % row + 1;//让电脑随机生成一组x,y保证雷位置的随机性
  int y = rand() % col + 1;//因为整个数组是11*11的所以中间有效区域是9*9下标是1到9 
  if (board[x][y] != '1')
  {
   board[x][y] = '1';
   count--;
  }
 }
}

5:实现在show中排查后显示位置的雷数

?
1
2
3
4
5
6
7
8
//统计周围雷的个数
int GetMineCount(char mine[ROWS][COLS], int x, int y)
 
{//因为在放置雷函数中放的是字符0和1所以雷数就等于周围八个元素之和减8倍的'0'
 return (mine[x - 1][y] + mine[x + 1][y] + mine[x][y - 1] + mine[x][y + 1]
  + mine[x - 1][y - 1] + mine[x - 1][y + 1] + mine[x + 1][y - 1] + mine[x + 1][y + 1]
  - 8 * '0');
}

6:实现排雷函数

?
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
//这里来实现排查雷的功能
 
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
 int x = 0;
 int y = 0;
 int ret = row * col - 10;//有81个位置10个雷只有71个位置没有放雷,如果71位置全排查完的获胜
 while (ret)
 {
  printf("请输入你要排查的坐标");
  scanf("%d %d", &x, &y);
  if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
  {
   if (show[x][y] == '*')
   {
    if (mine[x][y] == '1')
    {
     printf("很遗憾!你被炸死了\n");
     DisplayBoard(mine, ROW, COL);
     break;
    }
    else {
     
     OpenNOMine(mine, show, x, y);
     DisplayBoard(show, ROW, COL);
     
         }
   }
   else
   {
    printf("你输入的位置已经被排查过,请重新输入\n");
   }
  }
  else
  {
   printf("你输入的坐标超出范围,请重新输入\n");
  }
 
 }
 if (ret == 0)
 {
  printf("恭喜你!排雷成功\n");
 }
}

7:用递归来实现打开一个空格展开一片

?
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
void OpenNOMine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
 int n=0;
 n=GetMineCount(mine, x, y);
 if (n == 0)
 {
  show[x][y] = ' ';//为防止出现死递归的现象,将该位置变为空格
  int i = 0;
  for (i = x - 1; i <= x + 1; i++)
  {
   int j = 0;
   for (j = y - 1; j <= y + 1; j++)
   {
    if (show[i][j] == '*'&&mine[i][j]=='0')//需满足该位置没有雷,且没有被排查过
    {
     OpenNOMine(mine, show, i, j);//进行递归
     
    }
   }
  }
 }
 else {
  show[x][y] =n+'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
134
135
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
//这里进行棋盘数组的初始化
//
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
 int i = 0;
 for (i = 0; i < rows; i++)
 {
  int j = 0;
  for (j = 0; j < cols; j++)
  {
   board[i][j] = set;//这里的set存放的是0或*,方便测试时两个棋盘的打印
  }
 }
}
//这里实现棋盘的打印
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
 int i = 1;
 printf("---------------------------------\n");
 for (i = 0; i <= col; i++)
 {
  printf("%d ", i);
 }
 printf("\n");//打印棋盘的坐标序号
 for (i = 1; i <= row; i++)
 {
  printf("%d ", i);
  int j = 1;
  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 =10;//总共放置10颗雷
 while (count)
 {
  int x = rand() % row + 1;//让电脑随机生成一组x,y保证雷位置的随机性
  int y = rand() % col + 1;//因为整个数组是11*11的所以中间有效区域是9*9下标是1到9 
  if (board[x][y] != '1')
  {
   board[x][y] = '1';
   count--;
  }
 }
}
//统计周围雷的个数
int GetMineCount(char mine[ROWS][COLS], int x, int y)
 
{//因为在放置雷函数中放的是字符0和1所以雷数就等于周围八个元素之和减8倍的'0'
 return (mine[x - 1][y] + mine[x + 1][y] + mine[x][y - 1] + mine[x][y + 1]
  + mine[x - 1][y - 1] + mine[x - 1][y + 1] + mine[x + 1][y - 1] + mine[x + 1][y + 1]
  - 8 * '0');
}
//实现扫雷时,点开一个空白打开周围一片的功能
void OpenNOMine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
 int n=0;
 n=GetMineCount(mine, x, y);
 if (n == 0)
 {
  show[x][y] = ' ';//为防止出现死递归的现象,将该位置变为空格
  int i = 0;
  for (i = x - 1; i <= x + 1; i++)
  {
   int j = 0;
   for (j = y - 1; j <= y + 1; j++)
   {
    if (show[i][j] == '*'&&mine[i][j]=='0')//需满足该位置没有雷,且没有被排查过
    {
     OpenNOMine(mine, show, i, j);//进行递归
     
    }
   }
  }
 }
 else {
  show[x][y] =n+'0';
 }
 
}
 
//这里来实现排查雷的功能
 
 
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
 int x = 0;
 int y = 0;
 int ret = row * col - 10;//有81个位置10个雷只有71个位置没有放雷,如果71位置全排查完的获胜
 while (ret)
 {
  printf("请输入你要排查的坐标");
  scanf("%d %d", &x, &y);
  if (x >= 1 && x <= 9 && y >= 1 && y <= 9)
  {
   if (show[x][y] == '*')
   {
    if (mine[x][y] == '1')
    {
     printf("很遗憾!你被炸死了\n");
     DisplayBoard(mine, ROW, COL);
     break;
    }
    else {
     
     OpenNOMine(mine, show, x, y);
     DisplayBoard(show, ROW, COL);
     
         }
   }
   else
   {
    printf("你输入的位置已经被排查过,请重新输入\n");
   }
  }
  else
  {
   printf("你输入的坐标超出范围,请重新输入\n");
  }
 
 }
 if (ret == 0)
 {
  printf("恭喜你!排雷成功\n");
 }
}

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

原文链接:https://blog.csdn.net/ai15013602354/article/details/119492616

标签:

相关文章

热门资讯

yue是什么意思 网络流行语yue了是什么梗
yue是什么意思 网络流行语yue了是什么梗 2020-10-11
背刺什么意思 网络词语背刺是什么梗
背刺什么意思 网络词语背刺是什么梗 2020-05-22
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全 2019-12-26
2021年耽改剧名单 2021要播出的59部耽改剧列表
2021年耽改剧名单 2021要播出的59部耽改剧列表 2021-03-05
苹果12mini价格表官网报价 iPhone12mini全版本价格汇总
苹果12mini价格表官网报价 iPhone12mini全版本价格汇总 2020-11-13
返回顶部