简单扫雷游戏的C语言实现
一、对扫雷游戏进行全面的多方位的分析
1、使用两个二维数组表示地图
a)show_map表示每个位置是否被翻开
*表示未翻开,‘1’-'8’表示周围8个格子中有几个地雷
b)mine_map表示每个位置是否是地雷
‘0’表示不是地雷,‘1’表示是地雷
2、两个二维数组的初始化
a)show_map初始化全为*
b)mine_map先初始化全为’0’,然后随机生成CONST(10)个位置作为地雷
3、打印地图(show_map)
调试的时候也打印下mine_map
4、让用户输入一组坐标,需要检查坐标的合法性
5、判定当前位置如果是地雷,提示GameOver
6、如果不是地雷,就需要判定是否游戏胜利
胜利条件是翻开了所有不是地雷的格子(用个计数器就能实现,ROW*COL-CONST)
7、如果不是地雷,需要更新一个数字
这个数字表示周围8个格子中有几个地雷
a.写一个九宫格,用8个if判断(用周围有几个雷判断 打开周围的数字)
b.用数组时,保证数组不能越界
c.count要转换为字符型,count+‘0’
二、部分函数详细介绍以及注意事项
1、game.h头文件
#define _CRT_SECURE_NO_WARNINGS 1
#define ROW 9
#define COL 9
#define COUNT 10
#include<stdio.h>
//菜单
void menu();
//游戏主函数
void game();
//初始化
void init(char show_map[ROW][COL], char mine_map[ROW][COL], int rows, int cols);
//打印输出
void printArray(char print_map[ROW][COL], int rows, int cols);
//随机生成雷
void random_mine(char mine_map[ROW][COL], int rows, int cols);
//更新显示
void update_show(char show_map[ROW][COL], char mine_map[ROW][COL], int rows, int cols, int row, int col);
头文件除了对函数进行声明,可以将宏定义都放在头文件中,也可以将引用头文件的操作(#include<stdio.h>)放在头文件中,方便其他.c文件的调用。
2、主函数
while (1){
menu();
scanf("%d", &input);
if (input == 1){
game();
}
else if(input == 0){
break;
}
else{
printf("输入错误,请重输!\n");
}
}
主函数的作用仅仅是为了选择开始和结束游戏的,创建一个无限循环,若输入1则开始扫雷游戏,若输入0则退出程序,当程序首次打开或一局游戏已经结束时再次弹出菜单框进行进一步的选择。
3、随机生成10颗雷
int count = COUNT;
int row = 0;
int col = 0;
while (count>0){
row = rand() % rows;
col = rand() % cols;
if (mine_map[row][col] == '1'){
continue;
}
mine_map[row][col] = '1';
--count;
}
这里需要注意:该函数使用一个循环来控制随机生成雷的情况,这样的好处是如果某次随机出来的坐标已经布过雷,可以直接通过continue进入下次随机坐标生成,count并不用进行自减,控制雷数始终为CONST(10)个。
4、翻开后更新一个数字代表周围8个格子有几个雷
int count = 0;
//判断row,col周围的雷
if (row - 1 >= 0 && col - 1 >= 0 && mine_map[row - 1][col - 1] == '1'){
++count;
}
if (row - 1 >= 0 && mine_map[row - 1][col] == '1'){
++count;
}
if (row - 1 >= 0 && col + 1 <cols && mine_map[row - 1][col + 1] == '1'){
++count;
}
if (col - 1 >=0 && mine_map[row][col - 1] == '1'){
++count;
}
if (col + 1 <cols && mine_map[row][col + 1] == '1'){
++count;
}
if (row + 1 <rows && col - 1 >=0 && mine_map[row + 1][col - 1] == '1'){
++count;
}
if (row + 1 <rows && mine_map[row + 1][col] == '1'){
++count;
}
if (row + 1 <rows && col + 1 <cols && mine_map[row + 1][col + 1] == '1'){
++count;
}
show_map[row][col] = count + '0';
通过8个if的判断以及计数器的使用,来确定格子周围类雷的情况。
注意:在使用row+1、row-1、col+1、col-1操作时一定要对是否越界进行判断,不然会出错。
三、所有代码
Main.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
int main(){
int input = 0;
while (1){
menu();
scanf("%d", &input);
if (input == 1){
game();
}
else if(input == 0){
break;
}
else{
printf("输入错误,请重输!\n");
}
}
return 0;
}
game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
#include<stdlib.h>
#include<time.h>
//菜单
void menu(){
printf("**************************\n");
printf("***** 1.play *****\n");
printf("***** 0.exit *****\n");
printf("**************************\n");
}
//初始化两个数组
void init(char show_map[ROW][COL], char mine_map[ROW][COL], int rows, int cols){
int row = 0, col = 0;
for (row = 0; row < rows; row++){
for (col = 0; col < cols; col++){
show_map[row][col] = '*';
mine_map[row][col] = '0';
}
}
}
//数组输出
void printArray(char print_map[ROW][COL], int rows, int cols){
int row = 0, col = 0;
for (row = 0; row < rows; row++){
for (col = 0; col < cols; col++){
printf("%c ", print_map[row][col]);
}
printf("\n");
}
printf("\n\n");
}
//随机生成10个雷
void random_mine(char mine_map[ROW][COL], int rows, int cols){
int count = COUNT;
int row = 0;
int col = 0;
while (count>0){
row = rand() % rows;
col = rand() % cols;
if (mine_map[row][col] == '1'){
continue;
}
mine_map[row][col] = '1';
--count;
}
}
//翻开后更新一个数字代表周围8个格子有几个雷
void update_show(char show_map[ROW][COL], char mine_map[ROW][COL], int rows, int cols,int row,int col){
int count = 0;
//判断row,col周围的雷
if (row - 1 >= 0 && col - 1 >= 0 && mine_map[row - 1][col - 1] == '1'){
++count;
}
if (row - 1 >= 0 && mine_map[row - 1][col] == '1'){
++count;
}
if (row - 1 >= 0 && col + 1 <cols && mine_map[row - 1][col + 1] == '1'){
++count;
}
if (col - 1 >=0 && mine_map[row][col - 1] == '1'){
++count;
}
if (col + 1 <cols && mine_map[row][col + 1] == '1'){
++count;
}
if (row + 1 <rows && col - 1 >=0 && mine_map[row + 1][col - 1] == '1'){
++count;
}
if (row + 1 <rows && mine_map[row + 1][col] == '1'){
++count;
}
if (row + 1 <rows && col + 1 <cols && mine_map[row + 1][col + 1] == '1'){
++count;
}
show_map[row][col] = count + '0';
}
void game(){
srand((unsigned int)time(NULL));
int row=0,col=0;
//使用两个二维数组表示地图的两种格式
//show_map表示每个位置是否被翻开: *表示未翻开,'1'-'8'表示周围8个格子中有几个地雷
//mine_map表示每个位置是否是地雷:‘0’表示不是地雷,‘1’表示是地雷
char show_map[ROW][COL];
char mine_map[ROW][COL];
//初始化两个数组
init(show_map, mine_map,ROW,COL);
//随机生成10个地雷
random_mine(mine_map,ROW,COL);
//打印数组
printArray(show_map,ROW,COL);
printArray(mine_map, ROW, COL);
int count = 0;
while (1){
//让用户输入一组坐标,需要检查坐标的合法性
printf("请输入坐标(row col):");
scanf("%d%d", &row, &col);
if (row<0 || row >= ROW || col<0 || col >= COL){
printf("请输入正确的坐标\n");
continue;
}
if (show_map[row][col] != '*'){
printf("该位置已被打开,请重新输入\n");
continue;
}
if (mine_map[row][col] == '1'){
printf("GameOver!\n");
printArray(mine_map, ROW, COL);
break;
}
if (row >= 0 && row < ROW&&col >= 0 && col < COL&&show_map[row][col] == '*'){
update_show(show_map,mine_map, ROW, COL,row,col);
//用于测试
//show_map[row][col] = '#';
}
count++;
if (count == ROW*COL - COUNT){
printArray(mine_map, ROW, COL);
printf("You Win\n");
break;
}
//打印数组
printArray(show_map, ROW, COL);
printArray(mine_map, ROW, COL);
}
//如果跳出来则游戏结束
}
game.h
#define _CRT_SECURE_NO_WARNINGS 1
#define ROW 9
#define COL 9
#define COUNT 10
#include<stdio.h>
//菜单
void menu();
//游戏主函数
void game();
//初始化
void init(char show_map[ROW][COL], char mine_map[ROW][COL], int rows, int cols);
//打印输出
void printArray(char print_map[ROW][COL], int rows, int cols);
//随机生成雷
void random_mine(char mine_map[ROW][COL], int rows, int cols);
//更新显示
void update_show(char show_map[ROW][COL], char mine_map[ROW][COL], int rows, int cols, int row, int col);