扫雷游戏的玩法应该都知道,本篇文章实现的是9X9棋盘10个雷,在这里我先给大家梳理一下思路
初始化棋盘(在这里我们准备两个棋盘,一个棋盘用来布雷,另一个棋盘用来展示)-->布雷-->开始游戏-->排雷-->判断输赢
- 在这里面我们会有一个问题,在统计周围雷的个数的时候,坐标位于边界处,则会出现越界访问,所以在这里我们在原来棋盘的基础上加上2行2列。
代码展示: 在这里我们将代码分成3块:game.h(头文件),game.c(游戏功能函数),test.c(主函数)
- test.c代码
#include "game.h"
//打印菜单
void meau()
{
printf("****************************\n");
printf("****** 1. play 0.exit ******\n");
printf("****************************\n");
}
//游戏代码
void game()
{
//定义棋盘
char mine[ROWS][COLS];
char show[ROWS][COLS];
InitBoard(mine, ROWS, COLS, '0');//初始化布雷棋盘
InitBoard(show, ROWS, COLS, '*');//初始化展示棋盘
SetMine(mine, ROW, COL);//布雷
DisplayBoard(show, ROW, COL);//展示棋盘
FindMine(mine, show, ROW, COL);//扫雷
}
void test()
{
int input = 0;
srand((unsigned int)time(NULL));//这个函数实现的是真正意义上的随机
do
{
meau();
printf("请输入:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("重新输入\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
- game.h代码展示
//可以避免头文件的重复引入
#ifndef __GAME_H__
#define __GAME_H__
#endif //__GAME_H__
#ifndef __GAME_H__
#define __GAME_H__
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+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 board[ROWS][COLS], int row, int col);
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
void OpenMine(char mine[ROWS][COLS], char show[ROWS][COLS], int i, int j);
void Firstleave(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y);
#endif //__GAME_H__
- game.c代码展示
- 初始化棋盘
memset是内存设置函数,函数的形势为==void * memset(void *s,int value,size_t num)==它将s当前位置后面的num个字节用value替换并返回s。
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
memset(board, set, rows*cols*sizeof(board[0][0]));
}
- 打印棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i <= row; i++) //打印列号
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d ",i);//打印行号
for (j = 1; j <= col; j++)
{
printf("%c ",board[i][j]);
}
printf("\n");
}
}
- 布雷
void SetMine(char board[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = EASY_COUNT;
while (count)
{
x = rand() % 9 + 1;
y = rand() % 9 + 1;
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
- 计算坐标周围雷数
我们设置雷和非雷为字符型的‘1’,‘0’,可以将8个格子雷的数目加起来减去8*‘0’
int GetMineCount(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 Firstleave(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col,int x,int y)
{
int a = x;
int b = y;
int ret = 1;
if ('1' == mine[x][y])//如果第一次遇到雷
{
mine[x][y] = '0';//置为0,并展示周围雷的个数
int count = GetMineCount(mine, x, y);
show[x][y] = count + '0';
while (ret)//重新放位置
{
x = rand() % 9 + 1;
y = rand() % 9 + 1;
if (mine[x][y] == '0')
{
mine[x][y] = '1';
ret--;
}
}
}
OpenMine(mine, show, a, b);
DisplayBoard(show, row, col);
}
- 判断输赢
如果场上剩下的未知个数为你所布置得雷的个数,则胜利,这个函数返回的是场上剩下的未知的个数
int IfWin(char show[ROWS][COLS], int row, int col)
{
int i = 0;
int j = 0;
int win = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= col; j++)
{
if (show[i][j] == '*')
{
win++;
}
}
}
return win;
}
- 排雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
printf("请输入坐标:>");
scanf("%d%d", &x, &y);
Firstleave(mine,show,row,col,x,y);
while(1)
{
printf("请输入坐标:>");
scanf("%d%d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("Boom You Are Died!\n");
DisplayBoard(mine, row, col);
break;
}
else
{
OpenMine(mine,show,x,y);//展开
int count = GetMineCount(mine, x, y);
show[x][y] = count + '0';
DisplayBoard(show, row, col);
if (IfWin(show,row,col) == EASY_COUNT)
{
break;
}
}
}
else
{
printf("坐标非法\n");
}
}
if (IfWin(show, row, col) == EASY_COUNT)
{
printf("YOU WIN!\n");
DisplayBoard(mine, row, col);
}
}
- 扩展
当周围没有雷时,递归调用该函数,当碰到雷时停止调用
void OpenMine(char mine[ROWS][COLS], char show[ROWS][COLS], int i, int j) { if (mine[i][j] == '0' && show[i][j] == '*') { show[i][j] = GetMineCount(mine, i, j) + '0'; } if (mine[i][j - 1] == '0' && show[i][j - 1] == '*') { show[i][j - 1] = GetMineCount(mine, i, j - 1) + '0'; if (GetMineCount(mine, i, j - 1) == 0) { OpenMine(mine, show, i, j - 1); } } if (mine[i][j + 1] == '0' && show[i][j + 1] == '*') { show[i][j + 1] = GetMineCount(mine, i, j + 1) + '0'; if (GetMineCount(mine, i, j + 1) == 0) { OpenMine(mine, show, i, j + 1); } } if (mine[i - 1][j] == '0' && show[i - 1][j] == '*') { show[i - 1][j] = GetMineCount(mine, i - 1, j) + '0'; if (GetMineCount(mine, i - 1, j) == 0) { OpenMine(mine, show, i - 1, j); } } if (mine[i - 1][j - 1] == '0' && show[i - 1][j - 1] == '*') { show[i - 1][j - 1] = GetMineCount(mine, i - 1, j - 1) + '0'; if (GetMineCount(mine, i - 1, j - 1) == 0) { OpenMine(mine, show, i - 1, j - 1); } } if (mine[i - 1][j + 1] == '0' && show[i - 1][j + 1] == '*') { show[i - 1][j + 1] = GetMineCount(mine, i - 1, j + 1) + '0'; if (GetMineCount(mine, i - 1, j + 1) == 0) { OpenMine(mine, show, i - 1, j + 1); } } if (mine[i + 1][j + 1] == '0' && show[i + 1][j + 1] == '*') { show[i + 1][j + 1] = GetMineCount(mine, i + 1, j + 1) + '0'; if (GetMineCount(mine, i + 1, j + 1) == 0) { OpenMine(mine, show, i + 1, j + 1); } } if (mine[i + 1][j] == '0' && show[i + 1][j] == '*') { show[i + 1][j] = GetMineCount(mine, i + 1, j) + '0'; if (GetMineCount(mine, i + 1, j) == 0) { OpenMine(mine, show, i + 1, j); } } if (mine[i + 1][j - 1] == '0' && show[i + 1][j - 1] == '*') { show[i + 1][j - 1] = GetMineCount(mine, i + 1, j - 1) + '0'; if (GetMineCount(mine, i + 1, j - 1) == 0) { OpenMine(mine, show, i + 1, j - 1); } } }