C语言数组练习--扫雷
一.游戏规则
扫雷的基本规则:
- 点击方格,如果是地雷,游戏失败;找到所有方格而不踩到地雷则游戏胜利。
- 左键翻开方格,右键标记地雷。
- 双击左键(或者左右键一起点)可以看到数字的可点击范围。
- 数字表示周围有几个雷,例如“2”周围有两个雷。
基于对规则的分析,我们对于代码的实现有了一点点小的思路:
1.要有棋盘的打印
2.扫雷游戏要存储布置好的雷的信息,需要一个二维数组
3.预计以9*9的数组为例,需要2个二维数组,一个存放雷的信息(10个雷)(mine数组),一个存放布置好的雷的信息(show数组)。
4.考虑到排查雷的时候是看其周围八个里面存在几个雷,为了防止统计统计坐标周围的雷的个数的时候越界,我们设计为11*11(以9*9的数组为例,浅绿色为显示的9*9数组,深绿色为我们加入的边框,当统计雷的时候,统计到四个角以及边框时会出现数组越界的情况,为了避免此情况的出现,我们采用了11*11数组)
二.代码实现
我们依旧采取分模块编写程序代码
test.c:测试游戏的代码
game.c:游戏实现代码
game.h:游戏函数的声明
三.具体代码详解
3.1 游戏进出及界面的实现
定义menu()函数完成菜单界面的编写
//开始界面,进入时的菜单
void menu()
{printf("*******************************\n");printf("************1. play ***********\n");printf("************0. exit ***********\n");printf("*******************************\n");
}
在main()函数中,用do…while循环实现菜单使用,switch语句进行菜单选择
这点利用 input 这个变量,当用户输入 1 进行开始游戏时,input 值为1,同时switch语句中也依据 input 为1还是为0来进行判断。
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("退出游戏\n");break;default:printf("选择错误,重新选择\n");break;}} while (input);return 0;
}
3.2 棋盘创建与打印
棋盘的创建,我们在此并没有把棋盘的初始化函数InitBoard()写死(只能用什么符号并没有非常固定),我们添加了一个set参数,想传什么参可以自己来定义。
//创建棋盘
//添加了一个set参数,自己确认想初始化的参数
void InitBoard(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 DisplayBoard(char board[ROWS][COLS], int row, int col)
{int i = 0;printf("--------扫雷游戏-------\n");//给行标数for (i = 0; i <= col; i++){printf("%d ", i);}printf("\n");for (i = 1; i <= row; i++){printf("%d ", i);int j = 0;for (j = 1; j <= col; j++){printf("%c ", board[i][j]);}printf("\n");}
}
3.3 布置雷函数SetMine()
在game.c文件中实现布置雷函数,设置随机雷数EASY_COUNT,进入while循环每设置一个雷,EASY_COUNT减一,直到雷设置完毕跳出循环。为保证雷的随机性需生成随机坐标,判断设置雷是否重复,未重复设置雷”1“
void SetMine(char board[ROWS][COLS], int row, int col)
{//布置10个雷//生成随机的坐标,布置雷int count = EASY_COUNT;while (count){int x = rand() % row + 1;int y = rand() % col + 1;if (board[x][y] == '0'){board[x][y] = '1';count--;}}
}
3.4 排查雷函数FindMine()
玩家输入坐标后,首先确保坐标在棋盘范围内(否则重新输入),其次判断棋盘范围内坐标是否重复输入,未重复输入判断是否踩雷。
用GetMineCount函数统计周围雷个数
若踩雷”很遗憾炸死“,放入while循环,若雷没有排查完持续循环,若被炸死跳出循环。若所有雷被排查出则排雷成功。
int GetMineCount()
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');
}
FindMine()
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{//该位置不是雷,就统计这个坐标周围有几个雷int count = GetMineCount(mine, x, y);show[x][y] = count + '0';DisplayBoard(show, ROW, COL);win++;}}else{printf("坐标非法,重新输入\n");}}if (win == row * col - EASY_COUNT){printf("恭喜你,排雷成功\n");DisplayBoard(mine, ROW, COL);}
}
3.5 代码运行结果部分展示
排到雷
未排到雷
游戏结束可以选择是否要重新开始
3.6 所有源码
test.c:测试游戏的代码
#include "game.h"//开始界面,进入时的菜单
void menu()
{printf("*******************************\n");printf("************1. play ***********\n");printf("************0. exit ***********\n");printf("*******************************\n");
}void game()
{char mine[ROWS][COLS];//存放布置好的雷char show[ROWS][COLS];//存放排查出的雷的信息//初始化棋盘//1. mine数组最开始是全'0'//2. show数组最开始是全'*'InitBoard(mine, ROWS, COLS, '0');InitBoard(show, ROWS, COLS, '*');//打印棋盘//只需要打印show数组,存放雷的数组不需要打印//DisplayBoard(mine, ROW, COL);DisplayBoard(show, ROW, COL);//1. 布置雷SetMine(mine, ROW, COL);//DisplayBoard(mine, ROW, COL);//2. 排查雷FindMine(mine, show, ROW, COL);
}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("退出游戏\n");break;default:printf("选择错误,重新选择\n");break;}} while (input);return 0;
}
game.c:游戏实现代码
#include "game.h"//创建棋盘
//添加了一个set参数,自己确认想初始化的参数
void InitBoard(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 DisplayBoard(char board[ROWS][COLS], int row, int col)
{int i = 0;printf("--------扫雷游戏-------\n");//给行标数for (i = 0; i <= col; i++){printf("%d ", i);}printf("\n");for (i = 1; i <= row; i++){printf("%d ", i);int j = 0;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;while (count){int x = rand() % row + 1;int y = rand() % col + 1;if (board[x][y] == '0'){board[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');
}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{//该位置不是雷,就统计这个坐标周围有几个雷int count = GetMineCount(mine, x, y);show[x][y] = count + '0';DisplayBoard(show, ROW, COL);win++;}}else{printf("坐标非法,重新输入\n");}}if (win == row * col - EASY_COUNT){printf("恭喜你,排雷成功\n");DisplayBoard(mine, ROW, COL);}
}
game.h:游戏函数的声明
#include<stdio.h>
#include <stdlib.h>
#include <time.h>#define EASY_COUNT 10#define ROW 9
#define COL 9
//为了打印方便,我们只需要打印9*9,儿不需要打印11*11
#define ROWS ROW+2
#define COLS COL+2//初始化棋盘
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 board[ROWS][COLS], int row, int col);//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);