大家龙年快乐啊!这个春节过的怎么样,是好好的睡了一觉,还是到处走亲戚呢。不过不管如何,假期已经临近结束,还是得打起精神迎接新一年的机遇和挑战了。
话回正题,今天我们要实现的是一个简单命令行窗口的扫雷程序。
一.头文件准备
#pragma once
#define ROW 9
#define COL 9
//防止越界
#define ROWS ROW+2
#define COLS COL+2
#define MINENUM 10
//启动游戏
void game();
//布雷
void SetMine();
//将a数组中全部填充val值
void initBoard(char a[ROWS][COLS], char val);
//探测周围有几个雷
int detect(int x, int y);
//打印棋盘
void DisplayBoard(char arr[ROWS][COLS]);
//根据探测结果修改展示数组
void modify(int x, int y, int& win);
我们需要首先准备一个头文件,在其中定义一些宏和抽象函数以便后续的编辑。这样做的好处有三:1.如果想要修改扫雷的数据只需要在头文件中修改即可 2.首先定义抽象方法有便于结构清晰明了,如果第一次无法考虑完善,也可以后续再抽象出函数添加。 3.C语言中还是分函数先后的,如果先在头文件中声明就可以避免一些先后顺序带来的麻烦。
二.游戏菜单的完成
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
extern void game();//引用外部函数
void menu() {
printf("****************************\n");
printf("******0.exit 1.play*******\n");
printf("****************************\n");
}
int main() {
int input = 0;
do {
menu();
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏");
break;
default:printf("输入错误!请重新输入:");
break;
}
} while (input);
return 0;
}
编写一些漂亮的界面,为用户提供进入和退出游戏的选择:
三.游戏主体的完成
这一部分涉及到逻辑控制部分,只需要使用数组,逻辑判断,循环和分支;总体而言是比较简单的。
3.1 设计思路
我们首先需要两个11行11列的坐标分别用于存放地雷和显示画板。
//我这里设置为全局变量,但也可以设置为game()内局部变量
//定义为静态类型防止外部访问
//雷
static char mine[ROWS][COLS] = { 0 };
//显示的矩阵
static char show[ROWS][COLS] = { 0 };
之所以是11行11列是因为我这里没有对detect()做特殊处理,所有数组元素统一都是探测周围8格元素相加,而如图所示,探测1行1列时,则会访问到0行1列(绿色框)位置。因此需要多出两行置零,防止越界。
然后需要对mine和show两个数组进行初始化。接着进行布雷,展示初始show数组。接着在存活条件下不断循环,判断输入条件(这里只做了点击的功能)是否满足获胜条件。直至获胜或死亡。
3.2 game()函数实现
void game() {
int win = 0;
printf("---------扫雷----------\n");
initBoard(mine,'0');
initBoard(show,'*');
SetMine();
DisplayBoard(show);
DisplayBoard(mine);
int x, y;
//这里只做了
while(win<ROW*COL-MINENUM){
printf("请分别输入要点击的位置的x轴和y轴坐标:\n");
scanf("%d %d", &x, &y);
if (x > 0 && x <= ROW && y > 0 && y <= COL) {
if (mine[y][x] == '1') {
printf("你死了!\n");
DisplayBoard(mine);
system("pause");
system("cls");
return;
}
else {
modify(x,y,win);
system("cls");
DisplayBoard(show);
}
}
else {
printf("输入范围错误!请重新输入:\n");
}
}
printf("恭喜你!你赢了!");
system("pause");
system("cls");
}
3.3 抽象函数实现
剩下就是一些抽象函数的实现了。
void SetMine() {
srand((unsigned int)time(NULL));
for (int i = 0; i < MINENUM; i++) {
int a = rand() % ROW+1;
int b = rand() % COL+1;
if (mine[a][b] == '0') {
mine[a][b] = '1';
}
else {
i--;
}
}
}
void initBoard(char a[ROWS][COLS],char val) {
for (int i = 0; i < ROWS ; i++)
for (int j = 0; j < COLS ; j++)
a[i][j] = val;
}
void DisplayBoard(char arr[ROWS][COLS]) {
for (int i = 0; i <= ROW;i++) {
printf("%d ", i);
}
printf("\n");
for (int i = 1; i <=ROW; i++) {
printf("%d ", i);
for (int j = 1; j <= COL; j++) {
printf("%c ", arr[i][j]);
}
printf("\n");
}
}
int detect(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][y + 1] + mine[x - 1][y + 1] + mine[x + 1][y - 1]-(int)8*'0';
}
void modify(int x,int y,int& win) {
win++;
int count = detect(x, y);
if (count != 0) {
show[y][x] = char('0'+count);
}
else {
show[y][x] = ' ';
//防止探测已经探测过的地方进入死循环
if(x>1&&show[y][x-1]=='*')modify(x - 1, y, win);
if(y>1 && show[y-1][x] == '*')modify(x, y - 1, win);
if(x<ROW && show[y][x+1] == '*')modify(x + 1, y, win);
if(y<COL && show[y+1][x] == '*')modify(x, y + 1, win);
}
}
完整代码放到了我的gitee仓库:小游戏: 一些小游戏(gitee.com) ,可自取。