提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
一、程序思路及游戏规则讲解
当我们每次点击方块,程序会统计你所点击方块周围雷的个数(此图中含有递归)
举个例子
图中所用红笔画出的九宫格中心数字显示位移,就说明在他的周围有1个雷,而他的左上角和正上方的数字也显示1我们就可以确定这个雷的位置在他的左边,而他的右下角就是安全的。
当我们明白游戏规则之后我们来设计程序。
二、程序设计思路
1.打印菜单函数
代码如下(示例):
void menu()//打印菜单
{
printf("*****************\n");
printf("**** 1、Play ****\n");
printf("**** 0、Exit ****\n");
printf("*****************\n");
}
当玩家输入1的时候我们进入游戏,输入0时退出游戏,输入其他时报错。
void test()
{
int input = 0;
do
{
menu();
printf("请选择:>");
scanf_s("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
}
2.棋盘初始化函数
我们设想一下我们只设置一个棋盘,那么我们将很难同时实现埋雷和玩家排雷。所以我们打印出2个9*9的棋盘。
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
由图我们可以看到当我们排查左上角这个位置时我们的棋盘将出现溢出状态,经过观察我们发现我们若想设计9*9的棋盘我们就需要排查11*11的棋盘位置才能使游戏更加合理,所以我们在上面的宏定义中将ROW(行)COL(列)都拓宽一下。
初始化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}
打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)//打印棋盘
{
int i = 0;
int j = 0;
printf("-------------- 扫雷游戏 --------------\n");
for (j = 0; j <= col; j++)
{
printf("%d ", j);
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("-------------- 扫雷游戏 --------------\n");
}
我们将设置的两个棋盘一个用于存储雷,另一个用于给玩家展现出排雷的结果。
void game()
{
char mine[ROWS][COLS] = { 0 };//存放布置雷的信息
char show[ROWS][COLS] = { 0 };//存放排查雷的信息
//初始化棋盘
InitBoard(mine, ROWS, COLS, '0');//初始化为‘0’
InitBoard(show, ROWS, COLS, '*');//初始化为‘*’
DisplayBoard(show, ROW, COL);
DisplayBoard(mine, ROW, COL);
}
打印结果如下:
注:我们打印的是字符0而不是数字0,我们电脑随机生成的雷也是字符1,但是当我们输入坐标显示出的统计数字是数字1 2 3.。。。。后面我会为读者讲解这样做的目的。
3、随机数与放置雷的函数
我们控制电脑生成10个随机数(用做雷),并随机分布在mine棋盘上。
void SetMine(char mine[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{
//生成随机下标
int x = rand() % row + 1;
int y = rand() % col + 1;
//布置雷
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;
}
}
}
4、排查雷的函数
我们通过判断所输入的坐标位置存储的是否为字符1,如果是字符1说明是雷,游戏结束,如果不是字符1,我们设置另一个函数统计输入坐标周围字符1的个数并通过转换将字符转换为阿拉伯数字。
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_s("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("很遗憾,你被炸死了");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
int n = get_mine_count(mine, x, y);
show[x][y] = n + '0';
DisplayBoard(show,ROW,COL);
win++;
}
}
else
{
printf("坐标非法,重新输入\n");
}
}
if (win == (row * col - EASY_COUNT))
{
printf("恭喜你,闯关成功!\n");
}
}
int get_mine_count(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');
}
补充:字符数字转换为阿拉伯数字的公式是
字符数字-字符0=阿拉伯数字;
游戏胜利的条件:
将电脑设置的10个随机雷全部避开(排除),或者说把9*9=81-10的位置全都排查
输入坐标时要注意我们坐标是从1 1开始的而不是0 0 !!!
总结
代码如下:
game.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 9
#define COL 9
#define COLS COL+2
#define ROWS ROW+2
#define EASY_COUNT 10
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 mine[ROWS][COLS], int row, int col);//放置雷
int get_mine_count(char mine[ROWS][COLS], int x, int y);
void FindMine(char min
game.c
#include "game.h"
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}
void DisplayBoard(char board[ROWS][COLS], int row, int col)//打印棋盘
{
int i = 0;
int j = 0;
printf("-------------- 扫雷游戏 --------------\n");
for (j = 0; j <= col; j++)
{
printf("%d ", j);
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
printf("-------------- 扫雷游戏 --------------\n");
}
void SetMine(char mine[ROWS][COLS], int row, int col)
{
int count = EASY_COUNT;
while (count)
{
//生成随机下标
int x = rand() % row + 1;
int y = rand() % col + 1;
//布置雷
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;
}
}
}
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_s("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("很遗憾,你被炸死了");
DisplayBoard(mine, ROW, COL);
break;
}
else
{
int n = get_mine_count(mine, x, y);
show[x][y] = n + '0';
DisplayBoard(show,ROW,COL);
win++;
}
}
else
{
printf("坐标非法,重新输入\n");
}
}
if (win == (row * col - EASY_COUNT))
{
printf("恭喜你,闯关成功!\n");
}
}
int get_mine_count(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');
}
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] = { 0 };//存放布置雷的信息
char show[ROWS][COLS] = { 0 };//存放排查雷的信息
//初始化棋盘
InitBoard(mine, ROWS, COLS, '0');//初始化为‘0’
InitBoard(show, ROWS, COLS, '*');//初始化为‘*’
//打印一下棋盘
DisplayBoard(show, ROW, COL);
//放置雷
SetMine(mine, ROW, COL);
/*DisplayBoard(mine, ROW, COL);*/
//排雷
FindMine(mine,show,ROW, COL);
}
void test()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请选择:>");
scanf_s("%d", &input);
switch (input)
{
case 1:
printf("准备游戏\n");
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
这个扫雷游戏只是初阶版没有考虑递归只能一个坐标一个坐标的排查不能像
这种操作,所以可玩性并不高,后面会再出一期进阶版。
本期代码的Gitee仓库连接: