目录
前言
大家好,今天利用C语言实现9行9列扫雷游戏的全过程,十分详细,供大家参考
需要创建三个文件 一个test.c用来调用函数 game.c用于各种函数的具体实现 ,game.h头文件用于各种函数的声明 以及宏常量的一些定义
1、test.c文件
main函数
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("退出游戏!");
break;
default:
printf("输出错误,请重新输入\n");
break;
}
}
while (input);
return 0;
}
这部分主要用于菜单的选择界面 输入1开始游戏 输入0退出游戏 输入其他重新输入
menu函数
其中首先会调用menu菜单函数 代码如下
void menu()
{
printf("*****************************\n");
printf("*****************************\n");
printf("*******1、开始游戏***********\n");
printf("*******0、exit***************\n");
printf("*****************************\n");
printf("*****************************\n");
printf("*****************************\n");
}
game函数
然后玩家打1 怎会调用 game函数 开始扫雷游戏
void game()
{
char mine[ROWS][COLS]; //设置成11行11列是防止数组越界
char show[ROWS][COLS];
init_board(mine, ROWS, COLS, '0'); //初始化这两个棋盘 一个埋雷 一个显示
init_board(show, ROWS, COLS, '*');
//display_board(mine, ROW, COL); //打印棋盘时 打印9行9列就好
//printf("---------------------\n");
//display_board(show, ROW, COL); //打印棋盘时 打印9行9列就好
setmine(mine, ROW, COL); //设置雷 在mine初始化的棋盘中设置
//display_board(mine, ROW, COL);//打印棋盘
//printf("---------------------\n");
display_board(show, ROW, COL);
findmine(mine,show, ROW, COL); //找雷 在show初始化的棋盘中去找雷
}
game函数中包含有创建了两个数组 该数组都是11行11列的 因为防止在第一行和列 以及最后一行和列在判断四周列时会发生数组越界
初始化两个棋盘 其中一个棋盘设置雷(这部分不会显示出来玩家不能看到) 一个是玩家棋盘(玩家可以看到)
用init_board函数初始化这两个棋盘 设置雷的棋盘刚开始全是‘0’ 玩家棋盘初始化设置全是‘ * ’
然后display_board函数可以将这些棋盘显示出来(只是设置雷的棋盘最后不会显示)
setmine函数用来设置雷
findmine函数用来使玩家找雷
以上就是test.c的主要函数
2、game.c文件
这部分主要展示game函数中的各个函数的具体实现
初始化棋盘 init_board函数
void init_board(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’或者‘ * ’ 是雷棋盘和玩家的棋盘都可以初始化
打印棋盘display_board函数
void display_board(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
for (j = 0; j <=col; j++) //从0开始 多打印一列
{
printf("%d ", j);//打印列号
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d ", i); //打印行号
for (j = 1; j <=col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
将二维数组打印出来 注意打印出来行号和列号 打印9行9列 但在第一行前面一行打印每列的列号
在第一列前面打印每行的行号
要注意的是打印列号因为第一列前面多了一列行号 因此 i 应从0开始 这样才能将9行9列对齐 其余都是从1开始的
设置雷setmine函数
void setmine(char board[ROWS][COLS], int row, int col)
{
//布置10个雷
int count = EASY_COUNT; //初始化10个
while (count)
{
int x = rand() % row + 1; // 之前是0~8 后面+1 变成1~9的数字
int y = rand() % col + 1; // 之前是0~8 后面+1 变成1~9的数字
if (board[x][y]=='0') //如果有1 说明已经布置过雷 需要重新布置 如果是0说明没有布置过雷
{
board[x][y] = '1';
count--; //直到10个雷全部布置完
}
}
}
也是利用到随机时间函数 后面用行与列取模加1 得到1~9的数字 可以放在二维9乘9的数组中
将雷设置为1 循环直到雷数全部设置完
找雷finemine函数
void findmine(char mine[ROWS][COLS],char show[ROWS][COLS], int row, int col) //找雷
{
int win = 0;
int sum = row*col-EASY_COUNT; //表示的是行乘列在减去布置的雷数 就是空雷的数量
int x = 0;
int y = 0;
while (win < sum) //循环到把是所有没有雷的坐标都点到 则游戏结束
{
printf("请输入坐标:\n");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (show[x][y] == '*') //这里避免该雷判断过 避免重复需要重新判断 没判断过才去显示
{
if (mine[x][y] == '1')
{
printf("很遗憾,你被雷炸死了,游戏结束\n");
break;
}
else
{
int count = getminecount(mine, x, y); //函数内定义一个得到count的函数
show[x][y] = count + '0'; //因为数组里存放的是字符 而count是整型 所以加上‘0’让整型数字变成字符数字
display_board(show, ROW, COL); //打印这个棋盘
win++;
}
}
else
{
printf("该坐标已经判断过,请重新输入坐标\n");
}
}
else
{
printf("输入的坐标非法,请重新输入\n");
}
}
if (win == sum)
{
printf("恭喜你,游戏胜利!");
display_board(show, ROW, COL);
}
}
具体思路就是玩家输入坐标将全部没有雷的坐标全部填满 则玩家就会获胜
如果没满的情况下就一直输入坐标并且判断 如果输入的坐标不等于‘*’说明这个位置已经输入过了 没有的话则输入
如果输入的坐标在设置雷的棋盘里等于1 说明这个位置是雷 则直接退出循环 游戏失败
如果输入的坐标在雷的棋盘不是1 则需要用到自己定义的getmine函数来计算周围雷的数量 在将这个数量用字符的形式赋给玩家的那个棋盘 这是win++ 在与没有雷的sum比较 如果小于继续输入判断 等于了则退出循环 游戏胜利!
getmine函数
int getminecount(char mine[ROWS][COLS], int x, int y) //统计mine里面有多少了雷
{
return(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]
+ mine[x + 1][y] + mine[x + 1][y - 1]-8*'0'); //切记不要忘了这个8*‘0’ 因为需要返回的count是整形 而存在数组中的是字符
//每一个字符都应该减去一个字符‘0’ 才能是整型 8个字符就减8个‘0’
}
该函数将雷棋盘里传入的坐标上下左右都加起来 因为有雷为1 加起来周围有几个雷就有几个1
注意的是需要返回的是整型数 而数组是字符 需要每一个字符1减去‘0’转换成整型1 8个则需要减8*‘0’ 再返回
至此 game.c中所有函数的实现细节已经完成
3、test.c game.c game.h所有的代码
test.c代码
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu()
{
printf("*****************************\n");
printf("*****************************\n");
printf("*******1、开始游戏***********\n");
printf("*******0、exit***************\n");
printf("*****************************\n");
printf("*****************************\n");
printf("*****************************\n");
}
void game()
{
char mine[ROWS][COLS]; //设置成11行11列是防止数组越界
char show[ROWS][COLS];
init_board(mine, ROWS, COLS, '0'); //初始化这两个棋盘 一个埋雷 一个显示
init_board(show, ROWS, COLS, '*');
//display_board(mine, ROW, COL); //打印棋盘时 打印9行9列就好
//printf("---------------------\n");
//display_board(show, ROW, COL); //打印棋盘时 打印9行9列就好
setmine(mine, ROW, COL); //设置雷 在mine初始化的棋盘中设置
//display_board(mine, ROW, COL);//打印棋盘
//printf("---------------------\n");
display_board(show, ROW, COL);
findmine(mine,show, ROW, COL); //找雷 在show初始化的棋盘中去找雷
}
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("退出游戏!");
break;
default:
printf("输出错误,请重新输入\n");
break;
}
}
while (input);
return 0;
}
game.c代码
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void init_board(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;
}
}
}
void display_board(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
for (j = 0; j <=col; j++) //从0开始 多打印一列
{
printf("%d ", j);//打印列号
}
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)
{
//布置10个雷
int count = EASY_COUNT; //初始化10个
while (count)
{
int x = rand() % row + 1; // 之前是0~8 后面+1 变成1~9的数字
int y = rand() % col + 1; // 之前是0~8 后面+1 变成1~9的数字
if (board[x][y]=='0') //如果有1 说明已经布置过雷 需要重新布置 如果是0说明没有布置过雷
{
board[x][y] = '1';
count--; //直到10个雷全部布置完
}
}
}
int getminecount(char mine[ROWS][COLS], int x, int y) //统计mine里面有多少了雷
{
return(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]
+ mine[x + 1][y] + mine[x + 1][y - 1]-8*'0'); //切记不要忘了这个8*‘0’ 因为需要返回的count是整形 而存在数组中的是字符
//每一个字符都应该减去一个字符‘0’ 才能是整型 8个字符就减8个‘0’
}
void findmine(char mine[ROWS][COLS],char show[ROWS][COLS], int row, int col) //找雷
{
int win = 0;
int sum = row*col-EASY_COUNT; //表示的是行乘列在减去布置的雷数 就是空雷的数量
int x = 0;
int y = 0;
while (win < sum) //循环到把是所有没有雷的坐标都点到 则游戏结束
{
printf("请输入坐标:\n");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (show[x][y] == '*') //这里避免该雷判断过 避免重复需要重新判断 没判断过才去显示
{
if (mine[x][y] == '1')
{
printf("很遗憾,你被雷炸死了,游戏结束\n");
break;
}
else
{
int count = getminecount(mine, x, y); //函数内定义一个得到count的函数
show[x][y] = count + '0'; //因为数组里存放的是字符 而count是整型 所以加上‘0’让整型数字变成字符数字
display_board(show, ROW, COL); //打印这个棋盘
win++;
}
}
else
{
printf("该坐标已经判断过,请重新输入坐标\n");
}
}
else
{
printf("输入的坐标非法,请重新输入\n");
}
}
if (win == sum)
{
printf("恭喜你,游戏胜利!");
display_board(show, ROW, COL);
}
}
game.h
#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 init_board(char board[ROWS][COLS], int rows, int cols, char set); //这里面声明 注意int rows 和int cols不能写成大写因为实参是宏常量 形参是变量 这里形参和实参不能相同
void display_board(char board[ROWS][COLS], int rows, int cols); //打印棋盘声明
void setmine(char board[ROWS][COLS], int row, int col); //设置雷的声明
void findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col); //找类的声明
int getminecount(char mine[ROWS][COLS], int x, int y); //getminecount函数的声明
4 、后面可以改进的部分
以上就可以实现建议的扫雷 但现有的游戏中如果周围没有雷时会展开一大片 这项功能目前并没有在此实现 目前只能玩家一个一个输入 将全部没有雷的坐标全部填满才可以
未来可以实现此功能
满足此功能需要满足以下条件
1、确保输入的次坐标不是雷
2、之前没有输入过并且周围没有雷
3、如果满足count是0则递归实现 直到周围有雷的情况再继续往后执行 show[x][y] = count + '0';
后面可以将此功能加入 实现如果输入此坐标周围没有雷的话递归 实现输入一次win不止加一个