前言:
当我们初学了c语言,已经学会了一些基础的语法。面对一些简单的算法已经可以轻松拿下。
但是我们可能会生成一个疑惑:
除了算法题,我还能拿它做些什么呢?
而今天,就给大家推荐一用c做个简单的小游戏:扫雷,;来用上我们所学的知识,融汇贯通,充分吸收知识,也能提高我们对编程的兴趣。
目录
游戏逻辑实现:
在我们动手写代码之前,我们需要提前对代码实现的逻辑进行梳理;不然盲目去写代码,只会一地鸡毛,bug重重。
让我们先观察一下扫雷的基本结构:
图一
图二
图三
我们由图一可以发现基本框架是由一个9*9的结构组成和10个雷,因此我们需要:
1.一个9*9的数组
2.10个雷
(难点)在有图二中,我们发现当我们点击一个没有雷的位置后,能够引起一片的扫雷,而此机制由我查询,是以你点击的位置,对此位置3*3的位置进行“查雷”后扩散。
那么“查雷“是个什么操作呢 ?————对你所点击的位置(没雷的前提下)对3*3范围的8 个位置进行再次的以8个位置进行 3*3的范围查询雷数量,如果该位置的3*3范围里没有雷;此位置就属于扩散区域 ,因此,我们需要一个可以对此机制的算法
总结:
1.一个9*9的数组
2.10个雷
3.扩散算法
代码实现 :
头文件展示:
#pragma once
#include<stdio.h>
#include<stdlib.h>#define ROWS 11
#define COLS 11
#define Boomnumber 10void InitBorad(char borad[ROWS][COLS], int row, int col, char x);
void DisplayBorad(char borad[ROWS][COLS], int row, int col);
void MineBorad(char borad[ROWS][COLS], int row, int col);
Minesweeper(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
我们先进行简单的菜单显示:
void meun()
{
printf("************************\n");
printf("****** 1.play ******\n");
printf("****** 0.exit ******\n");
printf("************************\n");
}
int main()
{
srand((unsigned int)time(NULL));
//用input 来记录游戏启动还是退出
int input = 1;
do
{
meun();
printf("请输入你的选择 :\n");
scanf("%d", &input);
switch (input)
{
case 0:
{
input = 0;
break;
}
case 1:
{
//游戏函数
play();
break;
}
default:
{
printf("非法输入,请重新输入\n");
}
}
} while (input);
}
简单的菜单写完,我们就需要进行游戏代码的实现了:
重点一:
由于我们需要在棋盘上显示地雷的状态,一个棋盘完全不能够显示那么多的信息,于是我们需要两个棋盘来分别记录信息: mine棋盘用于记录什么地方有雷,什么地方没雷,show棋盘用于展示玩家玩时的状态。
如图:
mine show
重点二:
在检测靠四边位置的位置 3*3内雷的数量时,由于在最边上,旁边没有格子,会给我们写代码时造成麻烦,因此我们将两个棋盘都 扩大到11*11,其中四边是不向玩家展示,只做辅助用。
void play()
{
//设置扫雷大小,我们写一个简单模式下的扫雷:9*9大小,但是为了方便进行“排雷”操作计算地雷数量,将扩大一圈,也就是 11*11
//这个是用来埋雷的;
char mine[ROWS][COLS];
//记录雷的状态,当此位置没有雷,与mine雷盘对应的位置下,show盘就显示附件(以此位置3*3大小)雷的数量
char show[ROWS][COLS];
//初始化mine棋盘 0表示没有地雷
InitBorad(mine, ROWS, COLS, '0');
//初始化show棋盘
InitBorad(show,ROWS, COLS, '*');
//进行埋雷,对mine棋盘
MineBorad(mine, ROWS, COLS, '1');
//打印棋盘
DisplayBorad(show, ROWS, COLS);
//进行扫雷
Minesweeper(mine, show, ROWS, COLS);
}
各部分函数实现
InitBorad(mine, ROWS, COLS, '0')
//char 用于选择初始化什么字符
void InitBorad(char borad[ROWS][COLS], int row, int col, char x)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
borad[i][j] = x;
}
}
}
MineBorad(mine, ROWS, COLS, '1');
//用1来表示表示地雷
void MineBorad(char borad[ROWS][COLS], int row, int col)
{
int count = Boomnumber;
while (count)
{
int x = 0, y = 0;
x = rand() % 9 + 1;
y = rand() % 9 + 1;
if (borad[x][y] == '0')
{
borad[x][y] = '1';
count--;
}
}
}
DisplayBorad(show, ROWS, COLS);
void DisplayBorad(char borad[ROWS][COLS], int row, int col)
{
printf(" %d %d %d %d %d %d %d %d %d\n\n",1,2,3,4,5,6,7,8,9);//显示多少列
for (int i = 1; i < row-1; i++)
{
//显示多少行
printf("%d ", i);
for (int j = 1; j < col-1; j++)
{
printf(" %c ", borad[i][j]);
}
printf("\n");
}
}
下图是打印出的棋盘
Minesweeper函数是代码中最复杂的部分,含有三个函数:
Minesweeper sweeper Minesnumber
其中Minesweeper是主体函数,使用了其他两个函数
sweeper函数主要实现了当我们点击一个位置时,却能够联动周围3*3雷数量为0的一起被显示,从而不需要一个一个的扫雷。
Minenumber函数实现了,查询某位子3*3范围里雷的数量
Minesweeper(mine, show, ROWS, COLS);
//
char Minesnumber(char mine[ROWS][COLS], int x, int y)
{// ’0‘=48(ASCII值) ’1‘-’0‘=1 1+’0’=‘1’
char ret = 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] + mine[x+1][y +1] - 7 * '0';
return ret;
}
void sweeper(char mine[ROWS][COLS], char show[ROWS][COLS],int x,int y)
{
if (x > 0&& x < 10 && y>0 && y < 10)
{
//对3*3范围里,是零的就继续扫,非零就停止
//x-1 y-1
if (Minesnumber(mine, x - 1, y - 1)=='0' && show[x-1][y-1] == '*')
{
show[x - 1][y - 1] = '0';
sweeper(mine,show, x - 1, y - 1);
}
else if (Minesnumber(mine, x - 1, y - 1) != '0')
{
show[x - 1][y - 1] = Minesnumber(mine, x - 1, y - 1);
}
//x y-1
if (Minesnumber(mine, x , y - 1) == '0' && show[x][y-1] == '*')
{
show[x - 1][y - 1] = '0';
sweeper(mine, show, x , y -1);
}
else if (Minesnumber(mine, x, y - 1) != '0')
{
show[x][y - 1] = Minesnumber(mine, x, y - 1);
}
//x+1 y-1
if (Minesnumber(mine, x+1, y - 1) == '0' && show[x+1][y-1] == '*')
{
show[x +1][y - 1] = '0';
sweeper(mine, show, x+1, y - 1);
}
else if (Minesnumber(mine,x+1, y - 1) != '0')
{
show[x +1][y - 1] = Minesnumber(mine, x+1, y - 1);
}
//x-1 y
if (Minesnumber(mine, x-1, y ) == '0' && show[x-1][y] == '*')
{
show[x - 1][y ] = '0';
sweeper(mine, show, x-1, y );
}
else if (Minesnumber(mine, x-1, y ) != '0')
{
show[x - 1][y ] = Minesnumber(mine, x-1, y );
}
//x-1 y+1
if (Minesnumber(mine, x-1, y +1) == '0' && show[x-1][y+1] == '*')
{
show[x - 1][y +1] = '0';
sweeper(mine, show, x-1, y + 1);
}
else if (Minesnumber(mine, x-1, y - 1) != '0')
{
show[x - 1][y +1 ] = Minesnumber(mine, x-1, y + 1);
}
//x y+1
if (Minesnumber(mine, x, y + 1) == '0' && show[x][y+1] == '*')
{
show[x ][y + 1] = '0';
sweeper(mine, show, x, y + 1);
}
else if (Minesnumber(mine, x, y + 1) != '0')
{
show[x][y + 1] = Minesnumber(mine, x, y + 1);
}
//x+1 y
if (Minesnumber(mine, x+1, y ) == '0' && show[x+1][y] == '*')
{
show[x +1][y ] = '0';
sweeper(mine, show, x+1, y );
}
else if (Minesnumber(mine, x, y - 1) != '0')
{
show[x +1][y ] = Minesnumber(mine, x+1, y );
}
//x+1 y+1
if (Minesnumber(mine, x+1, y + 1) == '0' && show[x+1][y+1] == '*')
{
show[x + 1][y + 1] = '0';
sweeper(mine, show, x+1, y +1 );
}
else if (Minesnumber(mine, x+1, y + 1) != '0')
{
show[x + 1][y + 1] = Minesnumber(mine,x+1, y + 1);
}
}
//将最外维的格子除去,默认为零
else if ((x==0&&(y<=10&&y>=0))||(x==10 && (y <= 10 && y >= 0))||(y==0&&(x<10&&x>0))|| (y == 10 && (x < 10 && x>0)))
{
show[x][y] = '0';
}
}
Minesweeper(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x, y;
int win=0;
while (win<71)
{
printf("\n");
printf("请输入你要排查的下标:\n");
scanf("%d %d", &x, &y);
if (x > 0 && x < 10 && y>0 && y < 10)
{
if (mine[x][y] == '1')
{printf("你踩到雷了!\n");
DisplayBorad(mine, ROWS, COLS);
break;
}
//将x,y位置3*3格子,雷数量为0 的扫出,知道格子附近有雷
else {
show[x][y] = Minesnumber(mine, x, y);
sweeper(mine, show, x, y);
DisplayBorad(show, ROWS, COLS);
win++;
}
}
else
{
printf("非法输入\n");
}
}
if (win == 71)
{
printf("你赢了\n");
DisplayBorad(mine, ROWS, COLS);
}
}
最后:
至此,我们的扫雷就完成了,如果大家觉得有用的话,希望大家多多给我点赞,关注。