目录
一、制作一个菜单
1.菜单栏
首先我们需要一个菜单来选择开始游戏或者退出游戏,do...while循环至少会运行一次符合我们对游戏程序的要求
#include <stdio.h>
void mean()
{
printf("************************\n");
printf("***** 0.退出游戏 *****\n");
printf("***** 1.开始游戏 *****\n");
printf("************************\n");
}
void game()
{
}
int main()
{
int n = 0;
do
{
mean();
scanf("%d", &n);
switch (n)
{
case 0:
break;
case 1:
game();
break;
default:
printf("请选择正确的选项\n");
break;
}
} while (n);
}
测试我们的菜单逻辑没有问题
二、游戏函数的实现
1.雷盘的实现
初阶扫雷的棋盘为9x9所以我们需要一个创建一个二维数组作为棋盘,考虑到我们需要在游戏未结束之前隐藏雷的位置和棋盘的内容,为了方便起见我们可以创建两个棋盘。一个用来展示,一个用来存放雷。
我们在选择一个位置后,如果不是雷则需要判断周围8格有几个雷,为了避免数组越界我们创建的存放雷的棋盘要比实际的宽两格,ROW和COL是我们创建的一个宏,值为9.
ROWS和COLS是(ROW+1)和(COL+1)
#define ROW 9
#define COL 9
#define ROWS (ROW+2)
#define COLS (COL+2)
数组创建之后我们需要将其初始化,考虑到需要,我们将展示的棋盘数组全部初始化为*
存放雷的棋盘全部初始化为0
为了方便后续代码的编写,我们将展示的棋盘也设置为11x11,不过在打印时只打印9x9
初始化完成之后将棋盘打印出来
void game()
{
char show_board[ROWS][COLS];
char memory_board[ROWS][COLS];
init_show(show_board,ROW,COL);//初始化展示的棋盘
init_memory(memory_board, ROWS, COLS);//初始化存放雷的棋盘
printf_board(show_board, ROW, COL);
printf_board(memory_board, ROW, COL);
}
void init_show(char board[][COL],int row,int col)
{
int i, j;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = '*';
}
}
}
void init_memory(char board[][COLS], int row, int col)
{
int i, j;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = '0';
}
}
}
void printf_board(char board[][COLS], int row, int col)
{
int i, j;
for (i = 0; i < col; 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");
}
}
测试结果符合预期,其中存放雷的棋盘只是为了方便观察和编写程序才将其打印出来,程序完成之后将其删去。
2.布置雷
此时我们已经有了一个符合要求的棋盘,那么我们需要将雷布置到存放雷的棋盘中。
初阶扫雷有10个雷,所以我们需要将10个雷布置到我们的数组当中。
void place_mine(char board[][COLS], int row, int col)
{
int i = 0;
while (i<mined)//mined是我们定义的一个宏用来确定放置雷的数量
{
int x = rand() %row+1;
int y = rand() %co+l;
if (board[x][y] == '0')
{
board[x][y] = '1';
i++;
}
}
}
可以看到我们已经将10个雷分布到了雷盘中
3.开始扫雷
1.整体逻辑
首先我们需要输入一个坐标,然后在在输入之后首先判断是否是雷,如果是雷则游戏结束。
如果不是雷则需要将,一圈八格雷的总数展示出来。
void saolei(char showboard[][COLS],char memoryboard[][COLS])
{
int x = 0,y=0;
while (1)
{
printf("请输入坐标:\n");
scanf(" %d%d", &x, &y);
if (x <= ROW && x > 0&&y > 0 && y <= COL&& showboard[x][y] == '*')
{
if (memoryboard[x][y] == '1')
{
printf_board(memoryboard, ROW, COL);
printf("boom*\n");
printf("you die\n");
break;
}
else
{
count(showboard, memoryboard, x, y);
}
if (showboard[x][y] == '0' && x > 0 && y > 0)
ufold(showboard, memoryboard, x, y);
printf_board(showboard, ROW, COL);
int win=whether_win(showboard,ROW,COL);
if (win)
{
printf("恭喜排雷成功\n");
printf_board(showboard, ROW, COL);
printf_board(memoryboard, ROW, COL);
break;
}
}
else
printf("坐标不合法,请重新输入\n");
}
}
2.统计雷的数量
void count(char showboard[][COLS],char memoryboard[][COLS], int x, int y)
{
int i = 0, j = 0;
char sum = '0';
for (i = x - 1; i <= x + 1; i++)
{
for (j = y - 1; j <= y + 1; j++)
{
if (memoryboard[i][j] == '1')
sum++;
}
}
showboard[x][y] = sum;
}
3.递归展开
在扫雷中如果我们选择的位置周围没有雷,则会展开周围八格,然后展开的格子中如果存在周围没有雷的格子则会继续展开。
所以这里我们可以写一个递归,让它每次识别到没有雷的格子就继续展开。
注意添加限制条件避免数组越界,此处编写过程中条件如果不完善容易陷入死循环,如果在调试运行过程中出现栈溢出的错误,可以仔细检查这里看是否出现死循环。
void ufold(char showboard[][COLS], char memoryboard[][COLS], int x, int y)
{
int i = 0, j = 0;
int num = 0;
for (i = x - 1; i <= x + 1; i++)
{
for (j = y - 1; j <= y + 1; j++)
{
if (i > 0 && i <= ROW && j > 0 && j <= COL && showboard[i][j] == '*')
{
count(showboard, memoryboard, i, j);
if(showboard[i][j]=='0')
ufold(showboard, memoryboard, i, j);
}
}
}
}
测试递归展开逻辑没有问题
4.判断是否排雷成功
int whether_win(char showboard[][COLS], int row, int col)
{
int sum = 0;
int i = 0, j = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= col; j++)
{
if (showboard[i][j] == '*')
sum++;
if (sum > mined)
return 0;
}
}
return 1;
}
在这里为了节省时间提高效率,我们可以将雷数量mine改为2进行测试。测试完毕没有问题。
#define mined 2//雷的数量
三、代码的优化
1.删去 printf_board(memory_board, ROW, COL);这个是我们存放雷的棋盘,为了方便观察才打印出来的。
2.美化雷盘,美化到自己满意即可,此处不做过多演示
void printf_board(char board[][COLS], int row, int col)
{
int i, j;
printf(" ");
for (i = 0; i <= col; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 0; i <= col; i++)
{
printf("--");
}
printf("\n");
for (i = 1; i <= row; i++)
{
printf("%d |", i);
for (j = 1; j <= col; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
3.在合适位置添加清屏函数提升界面美观度
windows系统下可以使用system("cls"),头文件为stdlib.h
四、总结
代码整体难度较低,所用到的知识非常基础,在编写时保证头脑清晰冷静可以较快完成。
五、源代码
头文件
#define _CRT_SECURE_NO_WARNINGS 1
#define ROW 9
#define COL 9
#define ROWS (ROW+2)
#define COLS (COL+2)
#define mined 10//雷的数量
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void init_show(char board[][COLS], int row, int col);//初始化展示的棋盘
void init_memory(char board[][COLS], int row, int col);//初始化存放雷的棋盘
void printf_board(char board[][COLS], int row, int col);//打印棋盘
void place_mine(char board[][COLS], int row, int col);//布置雷
void saolei(char showboard[][COLS], char memoryboard[][COLS]);//扫雷
void count(char showboard[][COLS], char memoryboard[][COLS], int x, int y);//计算雷的数量
void ufold(char showboard[][COLS], char memoryboard[][COLS], int x, int y);//递归展开没有雷的格子
int whether_win(char showboard[][COLS], int row, int col);//判断是否成功
test.c
#include "game.h"
void mean()
{
printf("************************\n");
printf("***** 0.退出游戏 *****\n");
printf("***** 1.开始游戏 *****\n");
printf("************************\n");
}
void game()
{
char show_board[ROWS][COLS];
char memory_board[ROWS][COLS];
init_show(show_board,ROWS,COLS);
init_memory(memory_board, ROWS, COLS);
place_mine(memory_board, ROW, COL);
printf_board(show_board, ROW, COL);
saolei(show_board, memory_board);
}
int main()
{
srand((unsigned int)time(NULL));
int n = 0;
do
{
mean();
scanf("%d", &n);
switch (n)
{
case 0:
break;
case 1:
game();
break;
default:
printf("请选择正确的选项\n");
break;
}
} while (n);
}
game.c
#include "game.h"
void init_show(char board[][COLS],int row,int col)
{
int i, j;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = '*';
}
}
}
void init_memory(char board[][COLS], int row, int col)
{
int i, j;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = '0';
}
}
}
void printf_board(char board[][COLS], int row, int col)
{
int i, j;
printf(" ");
for (i = 1; i <= col; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 0; i <= col; i++)
{
printf("--");
}
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 place_mine(char board[][COLS], int row, int col)
{
int i = 0;
while (i<mined)
{
int x = rand()%row+1;
int y = rand()%col+1;
if (board[x][y] == '0')
{
board[x][y] = '1';
i++;
}
}
}
void ufold(char showboard[][COLS], char memoryboard[][COLS], int x, int y)
{
int i = 0, j = 0;
int num = 0;
for (i = x - 1; i <= x + 1; i++)
{
for (j = y - 1; j <= y + 1; j++)
{
if (i > 0 && i <= ROW && j > 0 && j <= COL && showboard[i][j] == '*')
{
count(showboard, memoryboard, i, j);
if(showboard[i][j]=='0')
ufold(showboard, memoryboard, i, j);
}
}
}
}
void count(char showboard[][COLS],char memoryboard[][COLS], int x, int y)
{
int i = 0, j = 0;
char sum = '0';
for (i = x - 1; i <= x + 1; i++)
{
for (j = y - 1; j <= y + 1; j++)
{
if (memoryboard[i][j] == '1')
sum++;
}
}
showboard[x][y] = sum;
}
int whether_win(char showboard[][COLS], int row, int col)
{
int sum = 0;
int i = 0, j = 0;
for (i = 1; i <= row; i++)
{
for (j = 1; j <= col; j++)
{
if (showboard[i][j] == '*')
sum++;
if (sum > mined)
return 0;
}
}
return 1;
}
void saolei(char showboard[][COLS],char memoryboard[][COLS])
{
int x = 0,y=0;
while (1)
{
printf("请输入坐标:\n");
scanf(" %d%d", &x, &y);
system("cls");
if (x <= ROW && x > 0&&y > 0 && y <= COL&& showboard[x][y] == '*')
{
if (memoryboard[x][y] == '1')
{
printf_board(memoryboard, ROW, COL);
printf_board(showboard, ROW, COL);
printf("boom*\n");
printf("you die\n");
break;
}
else
{
count(showboard, memoryboard, x, y);
}
if (showboard[x][y] == '0' && x > 0 && y > 0)
ufold(showboard, memoryboard, x, y);
printf_board(showboard, ROW, COL);
int win=whether_win(showboard,ROW,COL);
if (win)
{
printf("恭喜排雷成功啦>>>>>>>>>>>\n");
printf_board(showboard, ROW, COL);
printf_board(memoryboard, ROW, COL);
break;
}
}
else
printf("坐标不合法,请重新输入\n");
}
}