代码分为三部分,test.c(整体游戏框架),game.c(游戏的实现,定义的大部分函数),game.h(放的用到的头文件)
目录
2.void Initboard(char board[ROWS][COLS],int row,int col,char set);
4.void Displayboard(char board[ROWS][COLS], int row, int col);
5.void leiboard(char board[ROWS][COLS], int row, int col);
6. void usermove(char board[ROWS][COLS], char userboard[ROWS][COLS], int row, int col);
7.int leicount(char board[ROWS][COLS], int x, int y);
8.void openaround(char board[ROWS][COLS], char userboard[ROWS][COLS], int x, int y);
9.int iswin(char userboard[ROWS][COLS], int row, int col);
一、游戏流程
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请输入:>");
scanf_s("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("游戏结束\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
二、定义的函数
void menu();
void game();
void Initboard(char board[ROWS][COLS],int row,int col,char set);
void Displayboard(char board[ROWS][COLS], int row, int col);
void leiboard(char board[ROWS][COLS], int row, int col);
void usermove(char board[ROWS][COLS], char userboard[ROWS][COLS], int row, int col);
//返回类型为整型,返回用户输入坐标周围雷的个数
int leicount(char board[ROWS][COLS], int x, int y);
void openaround(char board[ROWS][COLS], char userboard[ROWS][COLS], int x, int y);
int iswin(char userboard[ROWS][COLS], int row, int col);
三、函数的实现
1.void menu();
void menu()
{
printf("*********************************\n");
printf("********* 1.play **********\n");
printf("********* 0.end **********\n");
printf("*********************************\n");
}
2.void game();
void game()
{
char board1[ROWS][COLS];
char board2[ROWS][COLS];
printf("开始游戏\n");
//初始化扫雷棋盘
Initboard(board1, ROW, COL, '0');
//给用户展示的排雷页面的初始化
//放雷,把雷初始化好,雷是放在棋盘1
leiboard(board1, ROW, COL);
Initboard(board2, ROW, COL, '*');
//打印一下给用户展示的棋盘
Displayboard(board2, ROW, COL);
//这个打印棋盘
//1.初始化为0以及放入雷后的棋盘
//2.用户排雷失败被炸死的时候,让用户被炸的明白用这个给打印出来
//3.让程序员好用来测试完成扫雷游戏,最后注释掉
//Displayboard(board1, ROW, COL);
//用户进行扫雷,输入要排的坐标,都是在棋盘1上进行的,棋盘2,只是为了方便给用户展示,总不能把雷的位置也给用户展示了吧
usermove(board1, board2, ROW, COL);
}
2.void Initboard(char board[ROWS][COLS],int row,int col,char set);
//初始化棋盘
//多初始化的两行,两列棋盘是为了判断边缘是否有雷时,数组会被越界访问
void Initboard(char board[ROWS][COLS], int row, int col, char set)
{
int i = 0;
int j = 0;
for (i = 0; i < row + 2; i++)
{
for (j = 0; j < col + 2; j++)
{
board[i][j] = set;
}
}
}
4.void Displayboard(char board[ROWS][COLS], int row, int col);
//打印1-9的初始化的那部分棋盘
void Displayboard(char board[ROWS][COLS], int row, int col)
{
int i = 1;
int j = 1;
for (i = 0; i < row + 1; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i < row + 1; i++)
{
printf("%d ", i);//打印出行数,竖着的一排嘛,方便看是第几行
for (j = 1; j < col + 1; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
5.void leiboard(char board[ROWS][COLS], int row, int col);
//放雷
void leiboard(char board[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int i = 0;
//放十个雷,用字符1表示
for (i = 0; i < pri_count; i++)
{
//用随机数产生1-9的随机数(再棋盘为9*9的情况下,改变ROW和COL会改变)
x = rand() % row + 1;//放到内圈 整个大圈时0-10 内圈是需要初始化和放雷的 即1-9
y = rand() % col + 1;
//这个if也是为了让雷在内圈,多的两行两列只是为了判断边缘的雷的情况,如果不设置的话会比较麻烦,或者会越界访问数组。
//还有个条件就是这个地方没有雷才能放
if (x > 0 && x < row + 1 && y>0 && y < col + 1&& board[x][y] == '0')
{
board[x][y] = '1';
}
else
i--;//因为如果上一个if没进去的话,i就多加了一个1,但是没有放上雷,所以就减去一个1
}
}
6. void usermove(char board[ROWS][COLS], char userboard[ROWS][COLS], int row, int col);
void usermove(char board[ROWS][COLS], char userboard[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int win = 0;
do
{
printf("请输入你要排除的坐标:>");
scanf_s("%d %d", &x, &y);
//判断输入的坐标是否正确
if (x > 0 && x < row + 1 && y>0 && y < col + 1)
{
//判断是否为雷
if (board[x][y] == '1')
{
printf("很遗憾,你被炸死了,哈哈哈,太遗憾了\n");
printf("下面是本局雷的分布\n");
Displayboard(board, ROW, COL);//被炸死后把这个棋盘打印出来,让用户知道自己踩了哪里的雷,以及雷都分布在哪里
break;
}
else if(board[x][y] == '0' && userboard[x][y] == '*')
{
//设计一个函数,计算这个坐标周围八个位置的雷的数量
userboard[x][y] = leicount(board, x, y);
openaround(board, userboard, x, y);
Displayboard(userboard, ROW, COL);
//判断棋盘上剩余的雷的个数,等于初级设计的地雷的个数,就赢了
if (iswin(userboard, row, col) == pri_count)
{
printf("恭喜你,赢了!!!!\n");
Displayboard(board, ROW, COL);
break;
}
//if (win == row * col - pri_count)
//{
// printf("恭喜你,赢了!!!!\n");
// break;
//}
}
else {
printf("你已经排查过这个位置,请重新输入!\n");
}
}
else
{
printf("输入错误,请重新输入\n");
}
} while(1);
}
7.int leicount(char board[ROWS][COLS], int x, int y);
(//返回类型为整型,返回用户输入坐标周围雷的个数)
int leicount(char board[ROWS][COLS], int x, int y)
{
return board[x - 1][y] + board[x - 1][y + 1] +
board[x][y + 1] + board[x + 1][y + 1] +
board[x + 1][y] + board[x + 1][y - 1] +
board[x][y - 1] + board[x - 1][y - 1] - 8 * '0';
}
//字符1和字符0 的ASCLL码的十进制相差1,所以相减为1
// 有雷的话减去字符0,就表示一颗雷,所以八个坐标全判断一下
//例:(用户坐标头上的这个位置)board[x-1][y]-'0'
//如果每一个都减'0'就比较繁琐,所以直接八个坐标的位置直接相加 减去八倍的字符0
//所以以用户输入的坐标为中心
8.void openaround(char board[ROWS][COLS], char userboard[ROWS][COLS], int x, int y);
void openaround(char board[ROWS][COLS], char userboard[ROWS][COLS], int x, int y)
{
if (x > 0 && x < ROW + 1 && y>0 && y < COL + 1)
{
//这里两个限制条件,第一个限制条件就是为了展开没有雷的位置的周围的雷的情况
//第二个限制条件就是为了防止弄成死递归,可以想一下,如果不限制,就会进入死递归,最终导致栈溢出
if (leicount(board, x, y) == 0 && userboard[x][y] != ' ')
{
userboard[x][y] = ' ';
openaround(board, userboard, x - 1, y);
openaround(board, userboard, x - 1, y + 1);
openaround(board, userboard, x, y + 1);
openaround(board, userboard, x + 1, y + 1);
openaround(board, userboard, x + 1, y);
openaround(board, userboard, x + 1, y - 1);
openaround(board, userboard, x, y - 1);
openaround(board, userboard, x - 1, y - 1);
}
//这个限制条件也是为了防止把已经赋值为空格的坐标又给赋值为0了
else if(userboard[x][y] != ' ')
{
userboard[x][y] = leicount(board, x, y) + '0';
//这里解释一下 为什么加一个字符0
//因为首先返回来的是一个整型,而这个数组是一个字符型
//一个整型被进行强制类型转换为字符型的话,也会造成二进制位的丢失,打印出来也不确定打印棋盘时,打印出来的也不确定
//所以这里加上字符0,字符零在其十进制上加返回来的十进制位数,对应的也是字符的也是整型的那个数
}
}
}
9.int iswin(char userboard[ROWS][COLS], int row, int col);
int iswin(char userboard[ROWS][COLS],int row,int col)
{
int win = 0;
int i = 0;
int j = 0;
for (i = 1; i < row + 1; i++)
{
for (j = 1; j < col + 1; j++)
{
if (userboard[i][j] == '*')
{
win++;
//printf("%d\n", win);这个是我当时测试我的win是不是正确的时候弄得,我的思考过程,就注释掉,不删了吧
}
}
}
return win;
}
四、完整的代码
1.test.c
#define _CRT_SECURE_NO_WARNINGS 1//这个是因为我用的vs编译器认为scanf函数不安全,会报错
#include "game2.h"
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请输入:>");
scanf_s("%d", &input);//因为加了上面那个不报错了,但是有警告,所以我还使用了scanf_s
switch (input)
{
case 1:
game();
break;
case 0:
printf("游戏结束\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
2.game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game2.h"
void menu()
{
printf("*********************************\n");
printf("********* 1.play **********\n");
printf("********* 0.end **********\n");
printf("*********************************\n");
}
void game()
{
char board1[ROWS][COLS];
char board2[ROWS][COLS];
printf("开始游戏\n");
//初始化扫雷棋盘
Initboard(board1, ROW, COL, '0');
//给用户展示的排雷页面的初始化
//放雷,把雷初始化好,雷是放在棋盘1
leiboard(board1, ROW, COL);
Initboard(board2, ROW, COL, '*');
//打印一下给用户展示的棋盘
Displayboard(board2, ROW, COL);
//这个打印棋盘
//1.初始化为0以及放入雷后的棋盘
//2.用户排雷失败被炸死的时候,让用户被炸的明白用这个给打印出来
//3.让程序员好用来测试完成扫雷游戏,最后注释掉
//Displayboard(board1, ROW, COL);
//用户进行扫雷,输入要排的坐标,都是在棋盘1上进行的,棋盘2,只是为了方便给用户展示,总不能把雷的位置也给用户展示了吧
usermove(board1, board2, ROW, COL);
}
//初始化棋盘
//多初始化的两行,两列棋盘是为了判断边缘是否有雷时,数组会被越界访问
void Initboard(char board[ROWS][COLS], int row, int col, char set)
{
int i = 0;
int j = 0;
for (i = 0; i < row + 2; i++)
{
for (j = 0; j < col + 2; j++)
{
board[i][j] = set;
}
}
}
//放雷
void leiboard(char board[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int i = 0;
//放十个雷,用字符1表示
for (i = 0; i < pri_count; i++)
{
//用随机数产生1-9的随机数(再棋盘为9*9的情况下,改变ROW和COL会改变)
x = rand() % row + 1;//放到内圈 整个大圈时0-10 内圈是需要初始化和放雷的 即1-9
y = rand() % col + 1;
//这个if也是为了让雷在内圈,多的两行两列只是为了判断边缘的雷的情况,如果不设置的话会比较麻烦,或者会越界访问数组。
//还有个条件就是这个地方没有雷才能放
if (x > 0 && x < row + 1 && y>0 && y < col + 1&& board[x][y] == '0')
{
board[x][y] = '1';
}
else
i--;//因为如果上一个if没进去的话,i就多加了一个1,但是没有放上雷,所以就减去一个1
}
}
//打印1-9的初始化的那部分棋盘
void Displayboard(char board[ROWS][COLS], int row, int col)
{
int i = 1;
int j = 1;
for (i = 0; i < row + 1; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i < row + 1; i++)
{
printf("%d ", i);//打印出行数,竖着的一排嘛,方便看是第几行
for (j = 1; j < col + 1; j++)
{
printf("%c ", board[i][j]);
}
printf("\n");
}
}
int leicount(char board[ROWS][COLS], int x, int y)
{
return board[x - 1][y] + board[x - 1][y + 1] +
board[x][y + 1] + board[x + 1][y + 1] +
board[x + 1][y] + board[x + 1][y - 1] +
board[x][y - 1] + board[x - 1][y - 1] - 8 * '0';
}
void openaround(char board[ROWS][COLS], char userboard[ROWS][COLS], int x, int y)
{
if (x > 0 && x < ROW + 1 && y>0 && y < COL + 1)
{
//这里两个限制条件,第一个限制条件就是为了展开没有雷的位置的周围的雷的情况
//第二个限制条件就是为了防止弄成死递归,可以想一下,如果不限制,就会进入死递归,最终导致栈溢出
if (leicount(board, x, y) == 0 && userboard[x][y] != ' ')
{
userboard[x][y] = ' ';
openaround(board, userboard, x - 1, y);
openaround(board, userboard, x - 1, y + 1);
openaround(board, userboard, x, y + 1);
openaround(board, userboard, x + 1, y + 1);
openaround(board, userboard, x + 1, y);
openaround(board, userboard, x + 1, y - 1);
openaround(board, userboard, x, y - 1);
openaround(board, userboard, x - 1, y - 1);
}
//这个限制条件也是为了防止把已经赋值为空格的坐标又给赋值为0了
else if(userboard[x][y] != ' ')
{
userboard[x][y] = leicount(board, x, y) + '0';
//这里解释一下 为什么加一个字符0
//因为首先返回来的是一个整型,而这个数组是一个字符型
//一个整型被进行强制类型转换为字符型的话,也会造成二进制位的丢失,打印出来也不确定打印棋盘时,打印出来的也不确定
//所以这里加上字符0,字符零在其十进制上加返回来的十进制位数,对应的也是字符的也是整型的那个数
}
}
}
int iswin(char userboard[ROWS][COLS],int row,int col)
{
int win = 0;
int i = 0;
int j = 0;
for (i = 1; i < row + 1; i++)
{
for (j = 1; j < col + 1; j++)
{
if (userboard[i][j] == '*')
{
win++;
//printf("%d\n", win);这个是我当时测试我的win是不是正确的时候弄得,我的思考过程,就注释掉,不删了吧
}
}
}
return win;
}
void usermove(char board[ROWS][COLS], char userboard[ROWS][COLS], int row, int col)
{
int x = 0;
int y = 0;
int win = 0;
do
{
printf("请输入你要排除的坐标:>");
scanf_s("%d %d", &x, &y);
//判断输入的坐标是否正确
if (x > 0 && x < row + 1 && y>0 && y < col + 1)
{
//判断是否为雷
if (board[x][y] == '1')
{
printf("很遗憾,你被炸死了,哈哈哈,太遗憾了\n");
printf("下面是本局雷的分布\n");
Displayboard(board, ROW, COL);//被炸死后把这个棋盘打印出来,让用户知道自己踩了哪里的雷,以及雷都分布在哪里
break;
}
else if(board[x][y] == '0' && userboard[x][y] == '*')
{
//设计一个函数,计算这个坐标周围八个位置的雷的数量
userboard[x][y] = leicount(board, x, y);
openaround(board, userboard, x, y);
Displayboard(userboard, ROW, COL);
//判断棋盘上剩余的雷的个数,等于初级设计的地雷的个数,就赢了
if (iswin(userboard, row, col) == pri_count)
{
printf("恭喜你,赢了!!!!\n");
Displayboard(board, ROW, COL);
break;
}
//if (win == row * col - pri_count)
//{
// printf("恭喜你,赢了!!!!\n");
// break;
//}
}
else {
printf("你已经排查过这个位置,请重新输入!\n");
}
}
else
{
printf("输入错误,请重新输入\n");
}
} while(1);
}
3.game.h
#pragma once
#define ROW 9
#define COL 9
#define ROWS ROW + 2
#define COLS COL + 2
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//初级版本的雷的数量
#define pri_count 10
void menu();
void game();
void Initboard(char board[ROWS][COLS],int row,int col,char set);
void Displayboard(char board[ROWS][COLS], int row, int col);
void leiboard(char board[ROWS][COLS], int row, int col);
void usermove(char board[ROWS][COLS], char userboard[ROWS][COLS], int row, int col);
//返回类型为整型,返回用户输入坐标周围雷的个数
int leicount(char board[ROWS][COLS], int x, int y);
void openaround(char board[ROWS][COLS], char userboard[ROWS][COLS], int x, int y);
int iswin(char userboard[ROWS][COLS], int row, int col);
五、游戏测试
1.你赢了(步骤有点多,可以自己去玩一下嘻嘻)
2.你输了(我这个运气,第一个子儿就被炸死了哈哈)
3.输入坐标非法请重新输入
4.你已经排查过此位置,请重新输入
最后希望可以帮助到大家,去尝试一下~
有bug请指正我!