文章目录
- 项目思路
- 一、分文件进行创建
- 二、进入游戏前的目录
-
- [2.1 目录的功能:](#2.1 目录的功能:)
- [2.2 目录界面:](#2.2 目录界面:)
- [2.3 选择进入或退出游戏](#2.3 选择进入或退出游戏)
-
- [2.3.1 代码示范](#2.3.1 代码示范)
- [2.3.2 图片示例:](#2.3.2 图片示例:)
- 三、画出游戏界面
-
- [3.1 创建两个数组](#3.1 创建两个数组)
- [3.2 初始化数组](#3.2 初始化数组)
- [3.3 打印游戏界面](#3.3 打印游戏界面)
-
- [3.3.1 代码思路](#3.3.1 代码思路)
- [3.3.2 代码示范:](#3.3.2 代码示范:)
- 四、用随机值放雷
-
- [4.1 代码思路:](#4.1 代码思路:)
- [4.2 代码示范:](#4.2 代码示范:)
- 五、游玩扫雷
-
- [5.1 代码思路:](#5.1 代码思路:)
- [5.2 注意事项:](#5.2 注意事项:)
- [5.3 代码实现:](#5.3 代码实现:)
- 六、整体代码示范
- 写在最后
项目思路
- 分文件进行创建
- 进入游戏前的目录
- 画出游戏界面
- 用随机值放雷
- 游玩扫雷
接下来,我们分步骤进行详细的解释说明。
一、分文件进行创建
在具体的项目实施中,我们需要分成不同的文件进行创建和书写,以此来保证项目的模块化。
那么在扫雷的实际书写中,
- 源文件:
- 测试游戏用的代码文件用test.c或者日期.c来作为文件名
- 游戏实现的底层代码用game.c文件作为文件名
- 头文件
- 游戏实现中使用的各个函数的声明 ,以及包含的其他库函数的头文件 需要写在头文件game.h文件里
如图所示:
- 游戏实现中使用的各个函数的声明 ,以及包含的其他库函数的头文件 需要写在头文件game.h文件里
二、进入游戏前的目录
2.1 目录的功能:
- 在游戏开始时,给玩家视觉上的帮助和提示
- 让玩家可以选择进入游戏或者退出游戏
- 将游戏形成一个可以不断重玩的循环
接下来,我们分步骤进行书写:
2.2 目录界面:
c
void menu()
{
printf("***********************\n");
printf("*****1、开始游戏*******\n");
printf("*****0、退出游戏*******\n");
printf("***********************\n");
}
接着,在main函数里面进行调用:
c
int main()
{
menu();
return 0;
}
这样目录的表面就写好了,接下来需要写玩家选择进入游戏和退出游戏的功能了
2.3 选择进入或退出游戏
选择功能的逻辑:1进入游戏,0退出游戏。
显然,必备的库函数有scanf,switch、case和default。为了让游戏的体验更加良好,可以再加一个printf增加视觉上的游玩帮助,用户友好。
那么根据刚刚的逻辑,可以写出如下的选择结构,其中game函数虽然还没有写出来,但是整体的框架可以先确定下来,之后再往里慢慢写内容。
2.3.1 代码示范
c
int main()
{
int input = 0;
menu();
printf("请选择:--->");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("非法输入!请重试\n");
break;
}
return 0;
}
2.3.2 图片示例:
三、画出游戏界面
3.1 创建两个数组
因为扫雷是一个隐藏式的游戏,放雷的数组玩家是不能看到的,所以需要两个数组,一个用来存放雷,一个用来展示给玩家隐藏后的界面,用来游玩。
创建数组代码示范:
c
char mine[ROWS][COLS];
char show[ROWS][COLS];
这里的行和列,用自定义变量来代替,这样以后在想更改行列的时候就可以很方便了
自定义变量代码在头文件game.h中,代码示范:
c
#define ROW 9
#define COL 9
3.2 初始化数组
现在数组已经创建好了,由于没有进行初始化,数组里放的是一些"烫烫烫"之类的乱码。
所以需要写一个函数,给这两个数组进行初始化,这一步也是为之后的重玩奠定了基础。
代码思路 :遍历数组每一个元素并赋值。
由于是给数组赋值,直接通过地址操作数组的,所以不需要返回值 ,直接void类型就可以。
至于接收值 ,需要接收:数组名 、行 、列 、以及需要赋值的符号 ,这样才能让函数有效的对不同的数组进行初始化。
代码示范:
c
void InitBoard(char board[ROWS][COLS], int row, int col, char set)
{
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = set;
}
}
}
在game里面的函数:
c
void game()
{
char mine[ROWS][COLS];//用mine数组来放雷
char show[ROWS][COLS];//用show数组来展示隐藏后的雷区
InitBoard(mine, ROWS, COLS,'0');//把放雷的数组赋值成全0,这样可以方便之后的扫雷显示
InitBoard(show, ROWS, COLS, '*');//把隐藏后的雷区赋成*(这个换其他的符号也可以)
}
3.3 打印游戏界面
3.3.1 代码思路
由于打印游戏界面是一个需要频繁进行的操作,无论是每次扫雷,还是被炸死的时候显示雷的位置,都需要打印。所以在这里,我们同样需要单独写一个函数来完成这个操作。
- 遍历数组并打印
- 返回值:由于是直接打印,是一个动作,所以做完后直接销毁就行,void类型
- 接收值:需要接收需要打印的数组、行、列
- 注意事项:
- 标头可以打印一个扫雷游戏分割线
- 在合适的地方加上换行,以保证游戏界面是9x9的正方形
- 在边缘处加上行和列的标号,以便玩家更方便的看到想扫的雷的坐标
- 注意是char数组,用%c 来打印,每个元素后面最好加空格,每一句后最好加换行
- 注意打印时数组的下标要从1开始,不要从0开始,否则扫雷的时候会向右下偏一位
3.3.2 代码示范:
c
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
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");
}
}
图片示例:
四、用随机值放雷
4.1 代码思路:
- 首先放雷是需要一个随机性的,那么就可以使用srand和rand函数(伪随机数),加上时间戳,构成一个真随机数,再利用这个真随机数取一个行列的模,就可以实现随机的放雷了。
- 随机取十个坐标,把mine里面的数字放成1,10个雷全部放完之后就有71个0和10个1。
- 在实现代码的时候需要注意,随机取的坐标不能重复,需要是0才能赋1。
- 一共只需要十个雷,while循环,再用一个int count来计算真实赋进去的雷的个数,就可以实现随机放雷了。
- 由于还是远程操作数组,所以返回值是void,接收值仍然是数组和行列。
- 在雷数方面,可以通过自定义变量来方便以后的操作。
4.2 代码示范:
c
void SetMine(char board[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count) {
i = rand() % row+1;
j = rand() % col+1;
if (board[i][j] == '0')
{
board[i][j] = '1';
count--;
}
}
}
头文件的代码:
c
#define EASY_COUNT 10
五、游玩扫雷
5.1 代码思路:
- printf进行视觉提示,scanf让玩家输入坐标
- 将坐标所处的数组元素进行判断
- 如果是雷,游戏结束
- 如果不是雷,统计该地点周围8个点位的雷数,并显示在棋盘上
- 如果位置超出棋盘范围,则重新输入
- 此过程不断循环,直到除了雷以外的所有点位被排干净,判定玩家赢
5.2 注意事项:
- 如果该点位处于边角位,如果统计周边8个点位,数组会越界,所以需要把数组多拓两行,避免越界
- 数字和字符的相互转换:加上'0'。比如如果想要把数字1转换为字符1,就需要加一个字符0,原理是0的ASCII码值是48,1的ASCII码值是49......加上字符0相当于加上48,正好是字符1的ASCII码值
5.3 代码实现:
c
void FindMine(char mine[ROWS][COLS],char show[ROWS][COLS] ,int row, int col)
{
int win = 0;
while (win < col * row - EASY_COUNT)
{
printf("请输入要排查的坐标>:");
scanf("%d %d", &i, &j);
if (i > 0 && i <= row && j > 0 && j <= col)
{
if (mine[i][j] == '1')
{
printf("很遗憾,你被炸死了\n");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
int count = GetCountMine(mine, i, j);
show[i][j] = count + '0';
DisplayBoard(show, ROW, COL);
win++;
}
}
else
printf("位置非法,请重新输入");
}
if (win == col * row - EASY_COUNT)
{
printf("恭喜你,游戏胜利!\n");
}
}
六、整体代码示范
game.h
c
#pragma once
#include <stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#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 board[ROWS][COLS], int row, int col);
test.c
c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu()
{
printf("********************\n");
printf("****** 1.play ******\n");
printf("****** 0.exit ******\n");
printf("********************\n");
}
void game()
{
char mine[ROWS][COLS];
char show[ROWS][COLS];
InitBoard(mine, ROWS, COLS,'0');
InitBoard(show, ROWS, COLS, '*');
//DisplayBoard(mine, ROW, COL); 这里的展示棋盘是用来测试代码用的,实际应用不需要
DisplayBoard(show, ROW, COL);
SetMine(mine, ROW, COL);
//DisplayBoard(mine, ROW, COL);这里的展示棋盘是用来测试代码用的,实际应用不需要
FindMine(mine, show, ROW, COL);
}
int main() {
int input = 0;
srand((unsigned int)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
c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
int i, j = 0;
void InitBoard(char board[ROWS][COLS], int row, int col, char set)
{
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = set;
}
}
}
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
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");
}
}
void SetMine(char board[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count) {
i = rand() % row+1;
j = rand() % col+1;
if (board[i][j] == '0')
{
board[i][j] = '1';
count--;
}
}
}
int GetCountMine(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 FindMine(char mine[ROWS][COLS],char show[ROWS][COLS] ,int row, int col)
{
int win = 0;
while (win < col * row - EASY_COUNT)
{
printf("请输入要排查的坐标>:");
scanf("%d %d", &i, &j);
if (i > 0 && i <= row && j > 0 && j <= col)
{
if (mine[i][j] == '1')
{
printf("很遗憾,你被炸死了\n");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
int count = GetCountMine(mine, i, j);
show[i][j] = count + '0';
DisplayBoard(show, ROW, COL);
win++;
}
}
else
printf("位置非法,请重新输入");
}
if (win == col * row - EASY_COUNT)
{
printf("恭喜你,游戏胜利!\n");
}
}
写在最后
如果本文对您有帮助,可不可以给我一个小小的点赞呀❤~您的支持是我最大的动力。
博主小白一枚,才疏学浅,难免有所纰漏,欢迎大家讨论和提出问题,博主一定第一时间改正。
谢谢观看嘿嘿(๑•̀ㅂ•́)و✧~!