目录
本文将介绍简单扫雷小游戏的一种实现思路及具体过程
先创建三个文件:
test.c 用于测试游戏
game.h 声明游戏中所使用的的函数
game.c 用于存放游戏中所使用的函数的具体实现
在开始扫雷小游戏前,首先需要一个可供玩家选择的菜单,于是我们可以编辑一个简易菜单,用switch …case分支语句来进行各种选择,游戏不止玩一次且至少循环一次,可以利用do…while循环语句,具体菜单如下:
void menu()
{
printf("*********************************\n");
printf("************ 1.play ***********\n");
printf("************ 0.exit ***********\n");
printf("*********************************\n");
}
int main()
{
int input = 0;
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;
}
以下开始进行各种游戏功能的实现:
一、创建用于存放雷及排查雷的空间
在进行扫雷游戏的时候,我们需要一块空间来存放游戏中布置的雷的信息,排雷空间是二维的,由此我们可以想到用n*n的二维数组作为存放该信息的空间;由于布置的雷在排查过程中不能暴露在玩家视线中,所以需要两个二维数组,一个存放雷,只用于存放信息不用于显示给玩家;一个用于排雷,将排雷过程的信息就显示在给玩家,所以用两个二维数组便可以存放这个游戏进行中的内容
//扫雷游戏两个棋盘,一个布置雷,一个扫雷两个二维数组
char mine[ROWS][COLS] = { 0 };
char show[ROWS][COLS] = { 0 };
二、扫雷空间二维数组大小参数设置
玩过扫雷游戏的大家都知道,当玩家排雷时,若被排位置无雷,会对以被排查位置为中心的九宫格周围进行搜查,并将周围雷的数目存放在被排查的位置中,仔细考虑一下,当玩家在排雷的时候,如果选择了边缘的位置,在排查时以此中心为九宫格,一定会有一部分需要排查的部位超出这个二维数组,即会发生数组的越界访问,为了方便排查,将二维数组的上下左右都扩大一个字节的位置可以避免数组的越界访问。
这里我们用了#define定义标识符,方便我们对游戏中棋盘的规格大小进行修改:
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
其中ROW和COL为实际放置雷及玩家排查雷所使用的行列大小,而ROWS和COLS便是避免数组越界访问而设置。
三、扫雷空间的初始化
首先要初始化放置雷的二维数组,排雷时是排查该二维数组上的雷,显示在排查雷的二维数组上,由于排雷时是对被排查位置为中心的九宫格周围进行搜查,不妨将该二维数组全部初始化为‘0’,设置雷时,将雷设置为‘1’,这样被排查周围雷的个数就是周围数字相加之和;而玩家排雷的二维数组,大家是看不见当中的内容的,只有排查过后才在该位置显示出周围雷的个数,所以可以将该二维数组初始化为全“*”,排查过后变为周围雷的个数。函数声明及具体实现如下:
//初始化棋盘
void init_board(char board[ROWS][COLS], int rows, int cols, char ch);
//初始化棋盘
void init_board(char board[ROWS][COLS], int rows, int cols, char ch)
{
int i = 0;
for (i = 0; i < rows; i++)
{
int j = 0;
for (j = 0; j < cols; j++)
{
board[i][j] = ch;
}
}
}
/初始化,布置雷的棋盘全部初始化为0;排雷棋盘初始化为*
init_board(mine, ROWS, COLS, '0');
init_board(show, ROWS, COLS, '*');
四、打印玩家排雷的空间
玩家进行游戏时自然是需要对着排雷空间进行排查的,所以将其打印在屏幕上是必要一环:
//打印棋盘
void display_board(char board[ROWS][COLS], int row, int col);
//打印棋盘
void display_board(char board[ROWS][COLS], int row, int col)
{
int i = 0;
for (i = 0; i <= row; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
int j = 0;
printf("%d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
//打印棋盘
display_board(show, ROW, COL);
在打印是将行列显示出来能更好的进行游戏。
五、布置雷
在布置雷的二维数组中,初始化为全0,所以现在需要随机布置几个雷,随机数的设置使用rand函数,布置雷的时候,要考虑放置雷的位置是否合法以及位置是否已经被非‘0’的字符占用:
/布置雷
void put_board(char board[ROWS][COLS], int row, int col);
//布置雷
void put_board(char board[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = BOOM;
while (count)
{
x = rand() % row + 1;
y = rand() % col + 1;
if (x >= 1 && x <= row && y >= 1 && y <= col)//合法性
{
if (board[x][y] == '0')//位置是否被占用
{
board[x][y] = '1';
count--;
}
}
}
}
//布置雷
put_board(mine, ROW, COL);
六、玩家排雷及游戏输赢的判断
在雷布置好以后,就可以进行排雷了,排雷过程在排查雷的二维数组上进行,也要注意排雷位置的合法性及空间是否被非‘*’的字符占用;
排雷的逻辑,碰到雷,游戏结束,没碰到雷,游戏继续,排完全部雷,游戏结束并且获胜。
//排雷 从雷的棋盘中排雷放到玩家玩的棋盘中,所以参数中既要有布置雷的二维数组,也要有排雷的二维数组
void find_board(char show[ROWS][COLS],char mine[ROWS][COLS], int row, int col);
//排雷的位置不为雷时,计算周围八个位置雷的个数并放入排雷的位置中
int sum(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 find_board(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col)
{
printf("玩家排雷:>\n");
int x = 0;
int y = 0;
int win = 0;
while (win<col*row-BOOM)//游戏继续的条件,还未排到雷且雷未排完
{
printf("请输入要排雷位置的坐标:>");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)//合法性
{
if (show[x][y] == '*')
{
if (mine[x][y] == '1')
{
printf("排到雷,游戏失败\n");
display_board(mine, ROW, COL);
break;
}
else
{
show[x][y] = sum(mine, x, y) + '0';//特殊处理
display_board(show, ROW, COL);
win++;
}
}
else
{
printf("该位置已经排过雷,请重新输入\n");
}
}
else
{
printf("输入非法,请重新输入\n");
}
}
if (win == row * col - BOOM)
{
printf("排雷成功,游戏获胜\n");
display_board(mine, ROW, COL);
}
}
//排雷的逻辑,碰到雷,游戏结束,没碰到雷,游戏继续,排完全部雷,游戏结束并且获胜
//排雷
find_board(show, mine, ROW, COL);
游戏原码
game.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define BOOM 10
//初始化棋盘
void init_board(char board[ROWS][COLS], int rows, int cols, char ch);
//打印棋盘
void display_board(char board[ROWS][COLS], int row, int col);
//布置雷
void put_board(char board[ROWS][COLS], int row, int col);
//排雷 从雷的棋盘中排雷放到玩家玩的棋盘中,所以参数中既要有布置雷的二维数组,也要有排雷的二维数组
void find_board(char show[ROWS][COLS],char mine[ROWS][COLS], int row, int col);
game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
//初始化棋盘
void init_board(char board[ROWS][COLS], int rows, int cols, char ch)
{
int i = 0;
for (i = 0; i < rows; i++)
{
int j = 0;
for (j = 0; j < cols; j++)
{
board[i][j] = ch;
}
}
}
//打印棋盘
void display_board(char board[ROWS][COLS], int row, int col)
{
int i = 0;
for (i = 0; i <= row; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
int j = 0;
printf("%d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
//布置雷
void put_board(char board[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = BOOM;
while (count)
{
x = rand() % row + 1;
y = rand() % col + 1;
if (x >= 1 && x <= row && y >= 1 && y <= col)//合法性
{
if (board[x][y] == '0')//位置是否被占用
{
board[x][y] = '1';
count--;
}
}
}
}
//排雷的位置不为雷时,计算周围八个位置雷的个数并放入排雷的位置中
int sum(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 find_board(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col)
{
printf("玩家排雷:>\n");
int x = 0;
int y = 0;
int win = 0;
while (win<col*row-BOOM)//游戏继续的条件,还未排到雷且雷未排完
{
printf("请输入要排雷位置的坐标:>");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)//合法性
{
if (show[x][y] == '*')
{
if (mine[x][y] == '1')
{
printf("排到雷,游戏失败\n");
display_board(mine, ROW, COL);
break;
}
else
{
show[x][y] = sum(mine, x, y) + '0';//特殊处理
display_board(show, ROW, COL);
win++;
}
}
else
{
printf("该位置已经排过雷,请重新输入\n");
}
}
else
{
printf("输入非法,请重新输入\n");
}
}
if (win == row * col - BOOM)
{
printf("排雷成功,游戏获胜\n");
display_board(mine, ROW, COL);
}
}
//排雷的逻辑,碰到雷,游戏结束,没碰到雷,游戏继续,排完全部雷,游戏结束并且获胜
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#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 };
//初始化,布置雷的棋盘全部初始化为0;排雷棋盘初始化为*
init_board(mine, ROWS, COLS, '0');
init_board(show, ROWS, COLS, '*');
//打印棋盘
display_board(show, ROW, COL);
//布置雷
put_board(mine, ROW, COL);
//display_board(mine, ROW, COL);
//排雷
find_board(show, mine, ROW, COL);
}
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
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;
}