文章目录
🍪设计思路
1.提供菜单对于玩家选择
2.游戏可以多次玩
3.不是雷 显示周围雷的个数
4.排雷周围没有雷,可实现展开
🔔# 程序结构
test.c 测试代码的逻辑
game.c 扫雷游戏的实现
game.c 函数的声明 符号的定义
🍔具体功能实现
🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍
🏀主函数实现
运用do while循环 case语句
用户选择1进入游戏
选择0 退出游戏
这里需要注意case语句结束后,加入转向语句break
int main()
{
int input = 0;
srand((unsigned int)time(NULL));//生成随机数种子 用于电脑下棋坐标
do
{
menu();
printf("请选择:>\n");
scanf("%d", &input);//选择菜单选项
switch (input)
{
case 1:
game();//三子棋游戏的实现
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误 请重新输入\n");
break;
}
} while (input);
}
🎄打印菜单
void menu()
{
printf("********************************\n");
printf("*********** 1 .play ************\n");
printf("*********** 0 .exit ************\n");
printf("********************************\n");
}
🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍
💡game函数实现
💡创建扫雷棋盘
为什么要创建两个棋盘呢?
mine棋盘是用来存储雷信息,我们布置雷使用的,
show棋盘是用来展示周围雷个数,我们给玩家展示使用的
char mine[ROWS][COLS] = { 0 };//mine数组是用来存放布置好的雷的信息
char show[ROWS][COLS] = { 0 };//show数组是用来存放排查出的雷的信息
注意!这里ROWS COLS 是在头文件宏定义的
当我们扫雷 排查蓝色位置时,排查周围8个坐标已经越界造成非法访问
解决的办法:上下两行多创建一行,左右两端多创建一列,可以完美解决这个问题
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
🍪初始化棋盘
用set传参
用‘ 0 ’来初始化mine数组
用’ * ’来初始化show数组 保持神秘感hhhh
//初始化棋盘
void Init_board(char board[ROWS][COLS], int rows, int cols, char set)
{
int i = 0;
for (i = 0; i < rows; i++)
{
int j = 0;
for (j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}
🍮打印棋盘
我们虽然创建数组用的11 * 11的数组
但是我们使用的是中间9*9的棋盘
外面一圈是为了防止越界而生成的
这里传参row col 和上面初始化数组中传入的行和列rows cols进行了区分
为了方便排雷,我们给予行和列的坐标
这里也是参考了优秀学长的棋盘页面
棋盘展示:
//打印行线
void line_board(int row, int col)
{
int i = 0;
for (i = 0; i <= row; i++)
{
printf("----");
}
printf("\n");
}
//打印棋盘
void Print_board(char board[ROWS][COLS], int row, int col)
{
printf(" ");
int n = 0;
for (n = 1; n <= col; n++)
{
printf(" %-3d", n);
}
printf("\n");
line_board(row, col);
int i = 0;
for (i = 1; i <= row; i++)
{
printf("%-3d|", i);
int j = 0;
for (j = 1; j <= col; j++)
{
printf(" %c |", board[i][j]);
}
printf("\n");
line_board(row, col);
}
}
🍚放置雷
注意:rand函数之前要用srand搭配使用
这里放置雷 传入ROW,COL只在9*9格子里放
不要放入ROWS COLS (刚开始学我犯下的低级错误…始终棋盘里不是十个雷)😭
//放置雷
void set_mine(char mine[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = Easy_count;
while (count)
{
x = rand()%row+1;//rand()%10的取值范围是0~8 +1之后取值1~9
y = rand()%col+1;//
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;
}
}
}
🍥获取周围雷的数量
如果想知道周围有多少雷 需要遍历周围八个坐标
字符0-字符0 = 0;
字符1-字符0 = 0;
只要把周围八个坐标的数值加起来减掉8 * ‘ 0 ’ 就得到该坐标周围雷的个数
//如果输入的坐标不是雷 获取输入坐标周围雷的数量
static 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';
}
🍥排查雷
如果排查的周围没有雷
可以使用递归展开区域如果把所有雷都找到了 排雷成功
9*9棋盘 -十个雷 只要排查71个位置
如果71个不是雷的位置都被排查 则排雷成功
这里创建了一个win变量
//查找雷
void Find_mine(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("请输入排查雷的坐标:>\n");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("很遗憾你被炸死了\n");
Print_board(mine, ROW, COL);//被炸死后打印埋雷的棋盘
break;
}
if (show[x][y] != '*')
{
printf("该坐标已经被排查过了 换一个试试\n");
continue;
}
else
{
Unfold(mine, show,row, col, x, y, &win);
Print_board(show, ROW, COL);
}
}
else
{
printf("坐标输入错误 请重新输入\n");
}
}
🍥递归展开
递归展开几个重要条件:
该坐标不是雷
该坐标周围不是雷 这时候可以展开一片每发现一个周围没有雷的点,就将其设置成空格,同时给win++
每发现一个周围有雷的点,就调用get_mine_count函数,将结果返回给这个点,同时win++
注意,由于是递归的方式来排查点,一定不要重复对排过的点进行win++
将win通过指针传址的方式与Find_mine函数建立联系
//递归展开一片区域
void Unfold(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y,int* win)
{
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
//排除已经排查过的坐标 避免重复
if (show[x][y] == ' ' || show[x][y] != '*')
return;
else if (get_mine_count(mine, x, y) != 0)//如果周围有雷
{
//需要字符0 但是返回的是数字0,所以需要+' 0 '转换一下
show[x][y] = get_mine_count(mine, x, y) + '0';
(*win)++;
return;
}
else//如果周围没雷
{
show[x][y] = ' ';//把坐标设置为空格
(*win)++;//找到一个雷 返回给win 离成功又进一步!
Unfold(mine, show, row, col, x - 1, y, win);
Unfold(mine, show, row, col, x + 1, y, win);
Unfold(mine, show, col, col, x, y - 1, win);
Unfold(mine, show, row, col, x, y + 1, win);
}
}
return;
}
🍥判断输赢
//判断输赢
if (win == (row * col) - Easy_count)
{
printf("恭喜你取得胜利!\n");
}
🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍🎍
🏠完整代码
🏠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 };
//初始化棋盘
Init_board(mine,ROWS,COLS,'0');
Init_board(show,ROWS,COLS,'*');
//打印棋盘
Print_board(show, ROW, COL);
//存放雷
set_mine(mine, ROW, COL);
//排查雷
Find_mine(mine,show, ROW, COL);
}
int main ()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:>\n");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误 请重新输入\n");
break;
}
} while (input);
return 0;
}
🏠game.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define Easy_count 10
//初始化棋盘
void Init_board(char board[ROWS][COLS], int rows, int cols, char set);
//打印棋盘
void Print_board(char board[ROWS][COLS], int row, int col);
//放置雷
void set_mine(char mine[ROWS][COLS], int row, int col);
//排查雷
void Find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
//展开一片
void Unfold(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col,int x,int y,int* win);
🏠game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
//初始化棋盘
void Init_board(char board[ROWS][COLS], int rows, int cols, char set)
{
int i = 0;
for (i = 0; i < rows; i++)
{
int j = 0;
for (j = 0; j < cols; j++)
{
board[i][j] = set;
}
}
}
//打印行线
void line_board(int row, int col)
{
int i = 0;
for (i = 0; i <= row; i++)
{
printf("----");
}
printf("\n");
}
//打印棋盘
void Print_board(char board[ROWS][COLS], int row, int col)
{
printf(" ");
int n = 0;
for (n = 1; n <= col; n++)
{
printf(" %-3d", n);
}
printf("\n");
line_board(row, col);
int i = 0;
for (i = 1; i <= row; i++)
{
printf("%-3d|", i);
int j = 0;
for (j = 1; j <= col; j++)
{
printf(" %c |", board[i][j]);
}
printf("\n");
line_board(row, col);
}
}
//放置雷
void set_mine(char mine[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int count = Easy_count;
while (count)
{
x = rand()%row+1;
y = rand()%col+1;
if (mine[x][y] == '0')
{
mine[x][y] = '1';
count--;
}
}
}
//获取输入坐标周围雷的数量
static 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';
}
//递归展开一片区域
void Unfold(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y, int* win)
{
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (show[x][y] == ' ' || show[x][y] != '*')
return;
else if (get_mine_count(mine, x, y) != 0)
{
show[x][y] = get_mine_count(mine, x, y) + '0';
(*win)++;
return;
}
else
{
show[x][y] = ' ';
(*win)++;
Unfold(mine, show, row, col, x - 1, y, win);
Unfold(mine, show, row, col, x + 1, y, win);
Unfold(mine, show, col, col, x, y - 1, win);
Unfold(mine, show, row, col, x, y + 1, win);
}
}
return;
}
//查找雷
void Find_mine(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("请输入排查雷的坐标:>\n");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (mine[x][y] == '1')
{
printf("很遗憾你被炸死了\n");
Print_board(mine, ROW, COL);//被炸死后打印埋雷的棋盘
break;
}
if (show[x][y] != '*')
{
printf("该坐标已经被排查过了 换一个试试\n");
continue;
}
else
{
Unfold(mine, show, row, col, x, y, &win);
Print_board(show, ROW, COL);
}
}
else
{
printf("坐标输入错误 请重新输入\n");
}
if (win == (row * col) - Easy_count)
{
printf("恭喜你取得胜利!\n");
}
}
}
这里的扫雷不包含 计时和标记的功能 此后会完善
个人水平不足 如果代码中有错误,可以多多在评论区指出,一定会及时修改!
谢谢大家看到这里 觉得有收获的话可以三连一下 一起加油!