1. 游戏描述
在一个9x9的棋盘上,玩家可自行设置地雷的数量,当所有的地雷被标记出来则玩家获得胜利。倘若在排雷过程中不小心排到地雷,则系统提示游戏失败,游戏结束,但玩家依旧可以选择是否再来一盘。
2. 功能实现分析
2.1 棋盘设置
因为我们要整一个9x9的棋盘,所以第一时间肯定二话不说直接搞出来一个 arr[9][9] 的二维数组来存放我们的地雷数据,就像这样:
但是...真的就这么草率地决定了吗...
当我们在判断类似于(2,2)这个位置的时候,是需要将其周围一圈的框都判断一遍才能判断四周有多少个地雷,但如果是(8,6)呢?我们会发现这个时候再检查就会出现越界的情况
当然不只是这个位置,任意一个在边上的位置都会出现这个情况,为了应对这个问题,我们需要在外面多加一圈位置,将arr[9][9]变为arr[11][11]
这样,在9x9的棋盘的基础上,我们就能很好的处理地雷数量判定的功能。
2.2 地雷判定
在棋盘上,当我们选的位置(位置1)没有地雷,但是该位置的四周地带有一个地雷,我们就需要在这个已经排查出来的位置上标注一个1,但是如果这个数是个整型数字,当我们在判定位置1的周围的地方时,系统便会误把位置1也算作是有一个地雷在,如此无疑是为我们的游戏带来了一个BUG。
要解决此问题,只需将棋盘上的所有整型数据变为字符型变量,这样就不会受到整形数判定的影响了。
同时,如果我们希望在一开始有点神秘感,不把答案显示出来,就可以再设计一个全都是‘*’的棋盘,第一个棋盘用来做判定,第二个用来显示四周的地雷数。
char mine[10][10]={0};
char show[10][10]={0};
3.代码解决
3.1 文件安排
我们用分别用game.h、game.c、test.c来分别处理函数的声明、函数的实现以及主函数。
3.2代码解决
game.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdio.h>
#include<time.h>
#include<windows.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 2
//函数声明
//菜单
void menu();
//初始化棋盘
void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set);
//放置炸弹
void SetMine(char arr[ROWS][COLS], int rows, int cols);
//展示棋盘
void DisplayBoard(char arr[ROWS][COLS], int row, int col);
//周围地雷的数量
int GetMineNum(char mine[ROWS][COLS], int x, int y);
//排查地雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
//标记地雷
void MarkMine(char arr[ROWS][COLS]);
//总地雷数判定
int MineNum(char mine[ROWS][COLS], char show[ROWS][COLS]);
//胜利判断
void Victory(char mine[ROWS][COLS], char show[ROWS][COLS]);
//小游戏实现
void game();
game.c
#include"game.h"
//菜单
void menu()
{
printf("************************\n");
printf("***** 1.Play *****\n");
printf("***** 0.Exit *****\n");
printf("************************\n");
printf("请输入您的选项:>");
}
//操作菜单
void OperationMenu()
{
printf("------------------------\n");
printf("| 1.排查地雷 | \n");
printf("| 2.标记地雷 | \n");
printf("------------------------\n");
printf("请选择要进行的操作:>");
}
//初始化棋盘
void InitBoard(char arr[ROWS][COLS], int rows, int cols, char set)
{
int i = 0, j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
arr[i][j] = set;
}
}
}
//放置炸弹
void SetMine(char arr[ROWS][COLS], int rows, int cols)
{
int count = EASY_COUNT;
while (count)
{
//要将两个坐标的生成放在循环语句内
int x = rand() % 9 + 1;
int y = rand() % 9 + 1;
if (arr[x][y] != '1')
{
arr[x][y] = '1';
}
else
{
continue;
}
count--;
}
}
//展示棋盘
void DisplayBoard(char arr[ROWS][COLS], int row, int col)
{
printf(" -----扫雷游戏-----\n");
printf(" ");
for (int i = 1; i <= 9; i++)
{
printf("%d ", i);
}printf("\n");
printf(" ");
for (int i = 1; i <= 9; i++)
{
printf("- ");
}
printf("\n");
for (int i = 1; i <= row; i++)
{
printf("%d ", i);
printf("| ");
for (int j = 1; j <= col; j++)
{
printf("%c ", arr[i][j]);
}
printf("\n");
}
}
//周围地雷数量
int GetMineNum(char arr[ROWS][COLS], int x, int y)
{
return ((arr[x - 1][y - 1] + arr[x][y - 1] + arr[x + 1][y - 1] + arr[x - 1][y] + arr[x + 1][y] + arr[x - 1][y + 1] + arr[x][y + 1] + arr[x + 1][y + 1]) - 8 * '0');
}
//排查地雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int win = 0;
int x = 0;
int y = 0;
int count = 0;
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);
printf("再挑战一次吗?\n");
}
else
{
count = GetMineNum(mine, x, y);
show[x][y] = count + '0';
DisplayBoard(show, ROW, COL);
win++;
}
}
else
{
printf("坐标输入错误,请重新输入\n");
}
}
//标记地雷
void MarkMine(char arr[ROWS][COLS])
{
int x = 0;
int y = 0;
printf("请输入您要标记的坐标:>");
scanf("%d %d", &x, & y);//x和y之间记得加上个逗号
arr[x][y] = '#';
DisplayBoard(arr, ROW, COL);
}
//总地雷数判定
int MineNum(char mine[ROWS][COLS],char show[ROWS][COLS])
{
int Num = EASY_COUNT;//地雷数量
for (int i = 1; i <= ROW; i++)
{
for (int j = 1; j <= COL; j++)
{
if (show[i][j] == '#' && mine[i][j] == '1') /**//**//**/
{
--Num;
}
}
}
printf("还剩%d个地雷\n",Num);
return Num;
}//似乎还有优化空间,如下一次又标对了只需在原来的基础上+1就可以而不是又重新从头到尾排查一遍
void Victory(char mine[ROWS][COLS],char show[ROWS][COLS])
{
int x;
int num = EASY_COUNT;
while (num)
{
OperationMenu();
scanf("%d", &x);
switch (x)
{
case 1:
FindMine(mine, show, ROW, COL);
break;
case 2:
MarkMine(show);
num = MineNum(mine, show);
if (num == 0)
{
printf("恭喜你!排雷成功!\n");
printf("再来一局吗\n");
}
break;
default:
printf("输入错误,请重新输入:\n");
break;
}
}
}
//小游戏实现
void game()
{
//创建两个二维数组(两个棋盘)
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
//初始化棋盘
InitBoard(mine, ROWS, COLS, '0');
InitBoard(show, ROWS, COLS, '*');
//放置地雷
SetMine(mine, ROW, COL);
//展示棋盘
DisplayBoard(mine, ROW, COL);
DisplayBoard(show, ROW, COL);
//胜利判定
Victory(mine, show);
}
test.c
#include"game.h"
int main()
{
srand((unsigned int)time(NULL));
printf("欢迎来到扫雷游戏!\n");
int input = 0;
do {
menu();
scanf("%d", &input);
switch (input)
{
case 1:
printf("游戏开始\n");
game();
break;
case 0:
printf("退出游戏...\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
由此,我们便可实现我们的目标程序功能了。
4.运行效果
看到这里是不是感觉自己也手痒痒的了?
快去试试吧!