扫雷规则:
自定义大小的方块矩阵中随机布置一定量的雷。由玩家逐个翻开方块,以找出所有地雷为最终游戏目标。如果玩家翻开的方块有地雷,则游戏结束;如果翻开的方块里没雷,则显示以这个方块为中心的九宫格里一共有多少雷。
思路:
假如我们要供用户玩的棋盘大小是10x10,为了显示边界栏上的雷数,我们要设置一个12x12大小的棋盘,这样在统计周围雷的数目时方法也是一样的(具体见代码中 GetMine()子函数)。另外,我们不光要设置一个展示给用户的棋盘,还要设置一个大小一样的用户看不见的棋盘用来种随机数种子(设置雷的分布),注意种的随机数种子是在棋盘二的内部10x10里分布的,边界处均设置成无雷。字符‘1’代表有雷,字符‘0’代表无雷。
难点一:
如何统计雷的数目?这里我们均使用的是char型的,假设被翻开的放块周围有6个‘1’,2个‘0’,那么我们写返回值时可以写成6x‘1’+2x‘0’-7‘0’,这样返回的就是字符型‘6’而非数字型6。6x(‘0’+1)+2x‘0’-7x‘0’=6x’0’+6x1+2x’0’-7x‘0’=‘0’+6=52,这样返回的char就是‘6’了。
难点二:
为什么都要用char型而不用int型,是因为初始化的时候Board[ROW][COL]和Mine[ROW][COL]使用的都是一个接口,为了方便初始化所以就都用char型了,再加上int占4个字节,而char只占一个字节。
难点三:
棋盘的展示,详见子函数ShowBoard()。
代码展示:
头文件mine.h
#ifndef _MINE_H
#define _MINE_H
#include<stdio.h>
#include<Windows.h>
#include<time.h>
#include<stdlib.h>
#pragma warning (disable:4996)
#define ROW 12 //行数
#define COL 12 //列数
#define MINE 20 //雷数
void Game();
void InitBoard(char Board[][COL], int row, int col, char elem);
void ShowBoard(char Board[][COL], int row, int col);
void SetMine(char Mine[][COL], int row, int col);
char GetMine(char Mine[][COL], int x, int y);
#endif
主文件部分main.c
#include "mine.h"
void Menu()
{
printf("####################################\n");
printf("#########欢迎来到扫雷小游戏#########\n");
printf("#####1.Start 2.Quit#####\n");
printf("####################################\n");
printf("Please enter your select=>");
}
int main()
{
int quit = 0;
int select = 0;
while (!quit)
{
Menu();
scanf("%d", &select);
switch (select)
{
case 1:
printf("游戏开始,快来排雷吧!\n");
Game();
break;
case 2:
quit = 1;
printf("再见!欢迎下次来玩...\n");
break;
default:
printf("Enter Error!Please enter again!\n");
break;
}
}
system("pause");
return 0;
}
mine.c
#include"mine.h"
void InitBoard(char Board[][COL], int row, int col,char elem)
{
int i = 0;
for (; i < row; i++){
int j = 0;
for (; j < col; j++){
Board[i][j] = elem;
}
}
}
void ShowBoard(char Board[][COL], int row, int col)
{
int i = 1;
printf(" ");
for (; i <= col - 2; i++){
printf(" %-2d|", i);
}
printf("\n");
for (i = 1; i <= col - 2; i++){
printf("%3s", "----");
}
printf("---\n");
for (i = 1; i <= row - 2; i++){
printf("%-2d|", i);
int j = 1;
for (; j <= col - 2; j++){
printf(" %-2c|", Board[i][j]);
}
printf("\n");
for (j = 1; j <= col - 2; j++){
printf("%3s", "----");
}
printf("---\n");
}
}
void SetMine(char Mine[][COL], int row, int col)
{
int n = MINE;
while (n){
int x = rand() % (ROW - 2) + 1;
int y = rand() % (COL - 2) + 1;
if (Mine[x][y] == '1'){
continue;
}
Mine[x][y] = '1';
n--;
}
}
char GetMine(char Mine[][COL], int x, int y)
{
return Mine[x - 1][y + 1] + Mine[x - 1][y] + Mine[x - 1][y - 1] + \
Mine[x][y + 1] + Mine[x][y - 1] + \
Mine[x + 1][y + 1] + Mine[x + 1][y] + Mine[x + 1][y - 1] - 7 * '0';
}
void Game()
{
srand((unsigned long)time(NULL)); //种随机数种子种子
char Board[ROW][COL];
char Mine[ROW][COL];
InitBoard(Board, ROW, COL,'*'); //初始化两个棋盘
InitBoard(Mine, ROW, COL,'0');
SetMine(Mine, ROW, COL); //设置雷的分布
int count = (ROW-2)*(COL-2) - MINE;//除了雷之外方块的个数
while (count>0)
{
system("cls"); //清屏
int x = 0;
int y = 0;
ShowBoard(Board, ROW, COL); //向用户展示棋盘
printf("请输入你要扫的坐标:\n");
scanf("%d %d", &x, &y);
if (x<1 || x>10 || y<1 || y>10){
printf("你输入的坐标有误,请重新输入!\n");
Sleep(1000);
continue;
}
else if (Board[x][y] != '*'){
printf("此坐标已被重复输入,请重新输入!\n");
Sleep(1000);
continue;
}
else if(Mine[x][y] == '0'){
char num = GetMine(Mine, x, y);//获得周围雷的个数
Board[x][y] = num;
count--;
}
else {
printf("你输入的[%d][%d]地方有雷!\n",x,y);
Sleep(1000);
break;
}
}
char *result = NULL;
if (count > 0){ //代表是因为扫到雷了跳出了while循环而不是因为全部扫完了count减到0了
result = "## 啊哦!你被炸死了!o( ╥ ﹏ ╥ )o ##\n";
Sleep(1000);
printf("\n");
}
else{
result = "## 扫雷结束!恭喜!你赢啦!(*^▽^*) ##\n";
Sleep(1000);
}
printf("####################################\n");
printf("%s", result);
printf("####################################\n");
ShowBoard(Mine, ROW, COL);
}