目录
前言
经过前面的学习,我们到了一个能写简单代码的阶段。这里我将带领大家使用 C 语言来编写一个扫雷的小游戏,用来将前面的知识整合并且融会贯通。相信各位写完这个代码会对 C 语言有更浓厚的学校兴趣。车速太快,请系好安全带,上车,开整。
本文所使用到的代码与一些步骤的讲解板书:扫雷代码与板书
rand、srand、time更详细内容:rand、srand、time。
三字棋小游戏文章:三字棋
程序编写大纲
俗话说的好:只要思想不滑坡,办法总比困难多。
写代码的时候,我们应该先要构思出代码执行需要什么,根据需求我们再去作出判断。这里我将给大家带来一些我写这个扫雷游戏的一些思路。
首先我们想这个游戏实现所需要的所需要什么?
- 开始游戏和退出游戏的这个页面。当确认开始游戏的时候,我们就会进入到下一步,当退出游戏的时候,我们就会退出这个程序。
- 当我们进入扫的有序的时候,里面肯定会出现一个扫雷棋盘的页面。所以我们要把这个棋盘给创造出来。
- 扫雷肯定是要以雷为主。我们要怎么去把雷给创造出来?
- 我们个人要去排雷,肯定回去选择一个位置。当我们选择一个位置的时候,我们要去判断:我确定地方有没有雷?如果有雷会怎么样?如果没有雷会怎么样?当棋盘内没有了会怎么办?
这大概就是我们需要的一些去用代码解决的一些问题。然后解决了这些问题,我们这个代码才能说基本上去实现这个小游戏所需要的功能。
扫雷小游戏代码分解
一、开始游戏和退出游戏的页面
我们经过前面的知识可以知道 do…while 循环,就是循环必须进行一次。然后当我们进入这个游戏的时候,这个程序肯定是必然要进去一次的,所以这里我们选择 do…while 循环,然后当进入这个循环的时候,我们就打一个 menu 函数。这个 menu 函数让我们看到了一个菜单,然后让我们进行判断,根据我们输入的数字,从而进行决定程序的走向。
PS:这里游戏执行程序的代码还没有写,这游戏已经开始代表代码能正确执行。
void Play()
{
printf("游戏已经开始\n");
}
void menu()
{
printf("*****************************\n");
printf("****** 1. 开始游戏 *******\n");
printf("****** 0. 退出游戏 *******\n");
printf("*****************************\n");
}
int main()
{
int input = 0;
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
Play();
break;
case 0:
printf("正在退出游戏");
break;
default:
printf("选择错误请重新选择\n");
break;
}
} while (input);
return 0;
}
二、棋盘的打印与初始化
当我们第一次进入这个扫雷程序的时候,我们会看到下面展示的页面。
在第一次进入这个程序的时候,因为是第一次进入没有人去玩这个棋盘,所以这个棋盘应该上面没有任何的痕迹,没有去被扫过雷的痕迹。
- 当我们写这个程序的时候,要确定位置,当我们输入一个行列坐标的时候就可以那个确定一个位置,所以我们可以用二维数组去创建这个棋盘。
- 按照这个扫雷程序的规则来看,一般 9 * 9 的棋盘。会出现 10 个雷。所以我们可以创造一个 9 行 9 列的数组。
- 然后当我们下棋的时候,不可能说把雷的位置告诉你,让你去玩。所以我们要创建两个数组,两个棋盘,一个用来创建雷的位置,一个是用来让自己下的。
注意:
因为我们用的是二维数组进行创建的,而根据扫雷的规则,当我们选中一个位置如果这个位置不是雷的话,会向四周去看,如果有四周有雷的话,就会吧四周雷的个数放在所确定的位置上。而如果我点击靠棋盘周围的位置时,就极容易造成数组的越界访问。
为了解决这个问题,我们需要在创建棋盘的时候,多设计两行与两列。
如下图所示:蓝边为多创建的行和列。
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
//放置雷的棋盘
InitBoard(mine, ROWS, COLS, '0');//函数调用
//扫雷的棋盘
InitBoard(show, ROWS, COLS, '*');//函数调用
//初始化两个棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}
我们设置好两个棋盘,把放置雷的棋盘都初始化为 0,等待后面随机放雷的代码程序。然后把我们要下来雷的棋盘全部初始化为 * 。
打印我们下雷的棋盘
DisplayBoard(show, ROW, COL);//函数调用
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
for ( i = 0; i <= col; 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");
}
三、创建雷
现在是创建雷的代码,创建的雷的部分,需要随机创建。
- C 语言用来产生随机数有一个rand函数。
- rand函数,这函数的作用就是生成库函数。使用这个函数要去搭配srand函数,这个函数里面需要一个可变的种子(参数),在日常生活中常见的也是时间是有变化的,这个时候我们可以使用time函数。(函数具体的参数和效果见本文版书部分)。
#define EASY_COUNT 10//代表10个雷 定义成宏方便扩展性
//创建雷
SetMine(mine, ROW, ROW);
//看创建的雷的位置
//DisplayBoard(mine, ROW, COL);
//写这个写这个歌是为了方便看代码执行是否正确,在玩的时候注意删除或者屏蔽这项代码
void SetMine(char mine[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{
int x = rand() % row + 1;
//假如当row为9的时候会创建0-8的数字,+1就会变成0-9的数字
//col同理
int y = rand() % col + 1;
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;
}
}
}
四、排查雷
首先我们来了解一下扫雷的规,我确定一个位置或者说我输入一个坐标,当这个位置有雷的时候,我就会输,当这个位置没有雷的时候,我就会向四周扫描有几个雷,有几个雷就返回几个雷,并在我确定的位置打印出或者说反映出雷的数量。
假如我们以 x 为横坐标,以 y 为纵坐标,就可以得到 x、y 坐标四周的数据位置。
如下图所示:
//因为字符 - 字符 变成整型 字符和字符相减 减的是ASCII码值
//'1' -->49
//'2' -->50
//相减 --> 1 整型
int GetMineCount(char mine[ROWS][COLS], int x, int y)
{
return mine[x - 1][y] +
mine[x - 1][y - 1] +
mine[x][y - 1] +
mine[x + 1][y - 1] +
mine[x + 1][y] +
mine[x + 1][y + 1] +
mine[x][y + 1] +
mine[x - 1][y + 1] - 8 * '0';
}//因为我给的雷的位置是 1,然后把周围8个字符的 1 相加就会得到周围雷的个数-0就会返回一个整型。
//排除雷
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
{
//不是雷,就统计x,y坐标周围有几个雷
int c = GetMineCount(mine, x, y);
//show字符数组 c 是int类型的 加上一个字符就会变成字符
show[x][y] = c + '0';
DisplayBoard(show, ROW, COL);
win++;
}
}
else
{
printf("坐标非法,重新输入\n");
}
}
if (win == row * col - EASY_COUNT)//当把所有点都拍完了就会跳出程序
{
printf("恭喜你,排雷成功\n");
DisplayBoard(mine, ROW, COL);
}
}
这里为了方便我们能检验快速的检验代码是否正确我们直接对着雷的位置来检查一遍,no并为9×9的棋盘设置80个雷。
代码合集
1.模块一:
#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
//代表10个雷 定义成宏方便扩展性
#define EASY_COUNT 10
//初始化棋盘
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 mine[ROWS][COLS], int row, int col);
//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
2.模块二:
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
//初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}
//打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
for ( i = 0; i <= col; 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)
{
int count = EASY_COUNT;
while (count)
{
int x = rand() % row + 1;
//假如当row为9的时候会创建0-8的数字,+1就会变成0-9的数字
//col同理
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)
{
return mine[x - 1][y] +
mine[x - 1][y - 1] +
mine[x][y - 1] +
mine[x + 1][y - 1] +
mine[x + 1][y] +
mine[x + 1][y + 1] +
mine[x][y + 1] +
mine[x - 1][y + 1] - 8 * '0';
}//因为我给的雷的位置是 1,然后把周围8个字符的 1 相加就会得到周围雷的个数-0就会返回一个整型。
//排除雷
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 (show[x][y] != '*')
{
printf("该坐标被排查,请重新输入坐标\n");
}
else if (mine[x][y] == '1')
{
printf("很遗憾,你被炸死了\n");
DisplayBoard(mine, ROW, COL);
//一般扫雷游戏输得时候就会有雷的位置打印出来
break;
}
else
{
//不是雷,就统计x,y坐标周围有几个雷
int c = GetMineCount(mine, x, y);
//字符数组 c 是int类型的 加上一个字符就会变成字符
show[x][y] = c + '0';
DisplayBoard(show, ROW, COL);
win++;
}
}
else
{
printf("坐标非法,重新输入\n");
}
}
if (win == row * col - EASY_COUNT)//当把所有点都拍完了就会跳出程序
{
printf("恭喜你,排雷成功\n");
DisplayBoard(mine, ROW, COL);
}
}
3.模块三
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void Play()
{
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
//放置雷的棋盘
InitBoard(mine, ROWS, COLS, '0');
//扫雷的棋盘
InitBoard(show, ROWS, COLS, '*');
//打印扫雷棋盘
DisplayBoard(show, ROW, COL);
//创建雷
SetMine(mine, ROW, ROW);
//看创建的雷的位置
DisplayBoard(mine, ROW, COL);
//写这个写这个歌是为了方便看代码执行是否正确,在玩的时候注意删除或者屏蔽这项代码
//排查雷
FindMine(mine, show, ROW, COL);
}
void menu()
{
printf("*****************************\n");
printf("****** 1. 开始游戏 *******\n");
printf("****** 0. 退出游戏 *******\n");
printf("*****************************\n");
}
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
Play();
break;
case 0:
printf("正在退出游戏");
break;
default:
printf("选择错误请,重新选择\n");
break;
}
} while (input);
return 0;
}
后语
希望各位在翻阅过本篇文章各位能够对扫雷小游戏有所认识,并在看完之后能够把它写出来。
希望能对各位有所帮助,如果各位有任何疑问,欢迎各位留言,我们可以进行友好的探讨与交流。
欢乐的时间总是过得特别快。又到时间讲bye,我们下一篇再见!!!