目录
一.基本介绍
扫雷,想必大家并不陌生。
这样一个9*9棋盘里,藏着十个雷,我们随便点开一个方格:
这样子,就出现了一些数字,而数字代表这个方格相邻的八个方格里的雷的个数。
根据这个规律,我们就能轻松获得游戏胜利!
学习完C语言基础知识后,我们就可以用C语言设计一个简易的扫雷小游戏啦!
怎么设计呢?我们可以列出大概步骤:
第一,菜单“开始游戏or结束游戏”。
这点很简单,不必多说。
第二,创建9*9棋盘。
我们可以用二维数组创建,也不难。
第三,布置随机雷。
有了上期“C语言简单程序:猜数字游戏”的知识后,生成随机雷也必然不在话下。
第四,判断玩家排查点周围雷的个数并反馈。
玩家排查点周围的八个位置都要统计,这一点需要注意
经过简单的分析,其实扫雷游戏就只要这几个步骤,那我们一步一步来就好了。
当然,写出来的代码也比较多,所以我们可以分成game.h,game.c, test.c。游戏需要的函数声明、类型说明放在game.h,游戏中函数的实现放在game.c,游戏的测试逻辑放在test.c。这样子更加利于管理和修改。
二.创建棋盘
菜单部分对游戏主体并无影响,所以先往后看:创建9*9棋盘。
既要用来展示给玩家,又要记录雷的位置,因此我们需要两份二维数组创建两份棋盘。
同时,因为玩家排查点周围的八个位置都要统计,那就有一个问题了:
如果是边缘或者角落处,想要统计“周围八个位置”,就会有越界访问的风险,那就必须要判断,边缘和拐角都不少,判断起来非常麻烦。因此,我们可以直接创建11*11的棋盘,在边缘和拐角全部设为非雷,再只打印中间9*9棋盘即可,这样就会方便很多。
两份棋盘创建好后就要初始化,一份全部为“ * ”展示给玩家当作隐藏方格(show);一份全部为“0”作为放置雷的地方(mine)。
代码如下:
//game.h
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
//game.c test.c里使用库函数需要的头文件可以在game.h里声明
#define ROW 9
#define COL 9//定义行和列
#define ROWS ROW + 2
#define COLS COL + 2//使程序能创建11*11的棋盘
void InitBoard(char Board[ROWS][COLS], int row, int col,char set);//初始化棋盘
void PrintBoard(char Board[ROWS][COLS], int row, int col);//打印棋盘
//game.c
#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 PrintBoard(char Board[ROWS][COLS], int row, int col)//打印棋盘
{
for (int j = 0; j <= col; j++)
{
printf("%d ", j);
}
printf("\n");
for (int i = 1; i <= row; i++)
{
printf("%d ", i);
for (int j = 1; j <= col; j++)
{
printf("%c ", Board[i][j]);
}
printf("\n");
}
}
//test.c
#include "game.h"
char mine[ROWS][COLS];
char show[ROWS][COLS];
InitBoard(mine, ROWS, COLS,'0');
InitBoard(show, ROWS, COLS,'*');//字符,注意用单引号
PrintBoard(show, ROW, COL);
PrintBoard(mine, ROW, COL);
这里需要注意,我们在头文件定义了行和列,这是因为后面所有跟棋盘有关的操作都会用到棋盘的行和列,所以在这定义之后,可以直接使用ROW和COL,如果我们想要修改行和列的信息,可以直接修改ROW和COL的值即可。
同时,玩家每次输入后程序肯定都要再打印一次棋盘,所以需要写入了一个打印棋盘的函数,其中也要包含横坐标和纵坐标,方便玩家查找对应坐标。
我们可以先打印两份棋盘看看效果:
这样,创建棋盘就完成啦!
三.布置随机雷
随机数我们调用srand()和rand()函数即可,这个随机数肯定是作为数组坐标去设置雷,那么只需要生成1~9的随机数就可以了,我们就需要一些运算符限制随机数的范围,并且只要十个雷就完成任务了。综上,我们可以写出以下代码:
//game.h
#EASY_COUNT 10
void SetBoare(char Board[ROWS][COLS], int row, int col);//布置雷
//game.c
void SetBoard(char Board[ROWS][COLS], int row, int col)
{
int number = EASY_COUNT;
while (number)
{
int i = rand() % 10 + 1;
int j = rand() % 10 + 1;
if (i <= row && j <= col)//对坐标进行限制
{
if (Board[i][j] != '1') //是字符不是字符串,用‘’单引号
{
Board[i][j] = '1';//防止重复赋值,保证满足十个雷
number--;
}
}
}
}
srand((unsigned int)time(NULL));
test.c里的main函数调用一次srand函数,再使用该函数就可以啦,
我们综合起来运行看看:
非常成功!
四.判断并反馈
获取玩家输入的坐标后,我们就可以判断该坐标周围八个坐标的雷个数总和,并赋值给玩家输入的坐标,再打印出来反馈给玩家。
我们先考虑一种最简单的情况,玩家很不幸运,直接”踩雷“,也就是玩家输入坐标正好是“1”所在位置,直接输入“你被炸死了”就可以跳出循环,准备下一次游戏了。
另一种情况就是玩家没有“踩雷”,这时候就要开始判断了。
这里的判断需要我们注意:
输入坐标x y,那我们需要获取周围八个坐标,只需要(x+1)(x-1)(x)和(y+1)(y-1)(y)之间互相“配对”,就能产生周围的八个坐标,怎么判断有多少雷呢?我们可以将这八个坐标所代表的值相加,是1 就会加1,是0就不会变,就能达到需要的效果了。当然,这里数组存放的是字符类型,运算时会用对应的ACSII码值进行计算,所以需要(- ‘ 0 ’ * 8),再(+ ‘ 0 ’ ),这个时候计算得来的值才能重新储存在mine数组里。
代码如下:
//game.h
int GetCount(char Board[ROWS][COLS],int x, int y);
//判断玩家输入坐标的周围雷的个数
void StartBoard(char mine[ROWS][COLS], char show[ROWS][COLS],int row, int col);
//与玩家互动部分
//game.c
int GetCount(char mine[ROWS][COLS], int x, int y)
{
return (mine[x][y - 1] + mine[x][y + 1] + mine[x - 1][y]
+ mine[x - 1][y + 1] + mine[x - 1][y - 1] + mine[x + 1][y]
+ mine[x + 1][y - 1] + mine[x + 1][y + 1] - 8 * '0');
}
void StartBoard(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x, y;
int win = 0;
while (win < row * col - EASY_COUNT)//判断是否将所有非雷全部排查,防止死循环
{
printf("请输入你想排查的坐标:");
int n = scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)//判断输入坐标是否合法
{
if (mine[x][y] == '1')
{
printf("你被炸死了!!!\n");
PrintBoard(mine, ROW, COL);//玩家失败游戏后展示mine数组即揭示答案
break;
}
else
{
int count = GetCount(mine, x, y);
show[x][y] = count + '0';//注意字符的计算时对应ASCII码值
PrintBoard(show, ROW, COL);
}
}
else
{
printf("坐标非法输入,请重新输入\n");
}
if (win == row * col - EASY_COUNT)
{
printf("恭喜你,扫雷成功,游戏胜利!!!\n");
PrintBoard(mine, ROW, COL);
}
}
}
五.总结
至此,游戏整体已经差不多完成了,再加开始游戏的菜单等等,一个简单的扫雷小游戏就诞生啦!
总代码如下:
//game.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#define EASY_COUNT 10
#define ROW 9
#define COL 9//定义行和列
#define ROWS ROW + 2
#define COLS COL + 2
void InitBoard(char Board[ROWS][COLS], int row, int col,char set);//初始化棋盘
void PrintBoard(char Board[ROWS][COLS], int row, int col);//打印棋盘
void SetBoare(char Board[ROWS][COLS], int row, int col);//布置雷
int GetCount(char Board[ROWS][COLS],int x, int y);//判断玩家输入坐标的周围雷的个数
void StartBoard(char mine[ROWS][COLS], char show[ROWS][COLS],int row, int col);
//与玩家互动部分
//game.c
#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 PrintBoard(char Board[ROWS][COLS], int row, int col)//打印棋盘
{
for (int j = 0; j <= col; j++)
{
printf("%d ", j);
}
printf("\n");
for (int i = 1; i <= row; i++)
{
printf("%d ", i);
for (int j = 1; j <= col; j++)
{
printf("%c ", Board[i][j]);
}
printf("\n");
}
}
void SetBoard(char Board[ROWS][COLS], int row, int col)
{
int number = EASY_COUNT;
while (number)
{
int i = rand() % 10 + 1;
int j = rand() % 10 + 1;
if (i <= row && j <= col)
{
if (Board[i][j] != '1') //是字符不是字符串
{
Board[i][j] = '1';
number--;
}
}
}
}
int GetCount(char mine[ROWS][COLS], int x, int y)
{
return (mine[x][y - 1] + mine[x][y + 1] + mine[x - 1][y]
+ mine[x - 1][y + 1] + mine[x - 1][y - 1] + mine[x + 1][y]
+ mine[x + 1][y - 1] + mine[x + 1][y + 1] - 8 * '0');
}
void StartBoard(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x, y;
int win = 0;
while (win < row * col - EASY_COUNT)
{
printf("请输入你想排查的坐标:");
int n = scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("你被炸死了!!!\n");
PrintBoard(mine, ROW, COL);
break;
}
else
{
int count = GetCount(mine, x, y);
show[x][y] = count + '0';
PrintBoard(show, ROW, COL);
}
}
else
{
printf("坐标非法输入,请重新输入\n");
}
if (win == row * col - EASY_COUNT)
{
printf("恭喜你,扫雷成功,游戏胜利!!!\n");
PrintBoard(mine, ROW, COL);
}
}
}
//test.c
#include "game.h"
void menu()
{
printf("*************************\n");
printf("*******1 . 开始游戏******\n");
printf("*******0 . 退出游戏******\n");
printf("*************************\n");
printf("请选择:");
}
void game()
{
printf("------游戏开始-----\n");
char mine[ROWS][COLS];
char show[ROWS][COLS];
InitBoard(mine, ROWS, COLS,'0');
//准备两个棋盘,一个给观众用来记录并展示对应点周围的雷的数目
InitBoard(show, ROWS, COLS,'*');
//另一个用来保存初始状态的雷的位置
PrintBoard(show, ROW, COL);
SetBoard(mine, ROW, COL);
//PrintBoard(mine, ROW, COL);//注意这个mine数组不能展示给玩家
StartBoard(mine, show, ROW, COL);
}
int main()
{
printf("扫雷游戏\n");
printf("你只需要输入坐标即可扫雷\n");
printf("输入格式:纵坐标 横坐标\n");
srand((unsigned int)time(NULL));
int input;
do
{
menu();
int a =scanf("%d", &input);
switch (input)
{
case 1:
game();//进入游戏主题
break;
case 0:
printf("游戏结束。");
break;
default:
printf("选择错误,请重新你输入:\n");
break;
}
} while (input);
return 0;
}
当然,上述的扫雷游戏,它不能一次展开周围非雷的一片,不能标识雷,不能记录游戏时间,不能选择难度,这么一看还是非常简陋的,但是学习过相关基础知识后,增加更多功能也不过是多定义几个函数而已,也是很轻松的。
夯实基础,无限进步。如有疑惑或者更多见解,欢迎讨论!!!
标签:ROWS,入门,int,COLS,C语言,char,game,小游戏,mine From: https://blog.csdn.net/T_L_the_language/article/details/143378480