本次讲解扫雷小游戏(小小升级的版本)
文章目录
前言一、game.h二、test.c1.主函数 main() 的编写2.游戏系列函数编写game.c 整体代码前言
游戏规则:根据电脑提示输入位置,当输入的位置让有雷,游戏结束;输入的位置是哪个没有雷,游戏继续,并且会显示周围八个位置的雷的情况
为了让代码更加模块化,首先我们需要分别创建game.h game.c test.c
一、game.h
game.h 里面存放的是头文件的声明、函数的声明、以及雷盘大小的自由化改动
#pragma once#define _CRT_SECURE_NO_WARNINGS 1//包含头文件#include <stdio.h>#include <stdlib.h>#include <time.h>//方便修改雷盘大小#define ROW 3 #define COL 3#define ROWS ROW+2#define COLS COL+2//声明初始化雷盘函数void InitBoard(char board[ROWS][COLS], int rows, int cols, char ret);//声明打印雷盘函数void PrintBoard(char board[ROWS][COLS], int row, int col);//声明布置雷函数void setmine(char board[ROWS][COLS], int row, int col, int num);//声明排查雷的函数void findmine(char secret[ROWS][COLS], char show[ROWS][COLS], int row,int col,int num);
二、test.c
1.主函数 main() 的编写
根据游戏需求,我们需要一个可以提供玩家选择的游戏菜单
void menu(){printf("*************---------------***************\n");printf("******--------- ---------*******\n");printf("******--------- 1.玩游戏 ---------*******\n");printf("\n");printf("******--------- 0.退出游戏 --------********\n");printf("******--------- ---------*******\n");printf("*************---------------***************\n");}
玩家按照菜单的内容进行选择,根据不同的选择编写 switch 语句
int main(){srand((unsigned int)time(NULL));int input = 0;do{menu();printf("请选择:");scanf("%d", &input); switch (input){case 0:system("cls");system("pause");printf("欢迎您的下一次体验,再见!\n");break;case 1:game();break;default:printf("输入错误,请重新选择\n");break;}} while (input);}
2.游戏系列函数编写game.c
创建一个理想雷盘
char Secret[ROWS][COLS] = {0 }; //秘密雷盘char Show[ROWS][COLS] = {0 };//展示的雷盘
正常来说,扫雷游戏只需要一个雷盘,但是这里设置了两个雷盘的原因是:Secret雷盘是用来存储雷的信息的,这里不能给玩家看;Show雷盘是玩家进行游戏的雷盘,两者有不同的作用,所以需要设置两个规模一样的雷盘。
初始化雷盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char ret){memset(board, ret, sizeof(board[0][0]) * rows * cols);}
因为这里是char类型的数组,所以直接使用memset初始化。
雷盘打印
void PrintBoard(char board[ROWS][COLS], int row, int col){printf("------------------------扫雷游戏-------------------\n");int i = 0, j = 0;printf(" ");for (i = 1; i <= row; i++){printf("%3d ", i);}printf("\n");printf(" +");for (i = 0; i < row; i++){printf("---+");}printf("\n");for (i = 1; i <= row; i++){printf("%2d", i);printf("|");for (j = 1; j <= col; j++){printf(" %c |", board[i][j]);}printf("\n");printf(" +");for (j = 0; j < col; j++){printf("---+");}printf("\n");}printf("------------------------扫雷游戏-------------------\n");}
布置雷盘
void setmine(char board[ROWS][COLS], int row, int col, int num){//随机布雷int x = 0;int y = 0;for (int i = 0; i < num; ){x = rand() % row + 1; //x产生[1,row]之间的坐标y = rand() % col + 1; //y产生[1,col]之间的坐标if (board[x][y] == '0'){board[x][y] = '1';i++; }}}
模式选择
玩家可以自行选择困难模式,也可以自定义模式
int ModeSelection(){int num = 0;again: //玩家选择模式错误时返回到这里printf("欢迎玩家来到扫雷游戏\n");printf("\n请选择扫雷难度: (num的代表雷的数量)\n");printf("A.轻松模式:num=5 B.皱眉头模式:num=15 C.出汗模式:num=30 D.DIY难度(玩家自行输入雷的个数)\n ");char pattern = 0;getchar();//清空缓存区scanf("%c", &pattern);switch (pattern){case 'A':case 'a':printf("轻松模式:num=5\n");num = 5;return num;break;case 'B':case 'b':printf("皱眉头模式:num=15\n");num = 15;return num;break;case 'C':case 'c':printf("出汗模式:num=30\n");num = 30;return num;break;case 'D':case 'd':printf("DIY模式:\n");printf("请输入想要布置雷的个数:\n");getchar();//清楚缓存区int intput = 0;scanf("%d", &intput);//用户自定义的雷的个数num = intput;return num;break;default:printf("\n******不好意思,皮蛋还没有此功能按键,请重新选择:******\n\n");goto again;break;}}
排查雷
首先需要知道玩家输入的坐标是否合法其次需要判断此位置有没有被排查过如果没有被排查过,就需要进行递归显示周围雷的数量
void findmine(char secret[ROWS][COLS], char show[ROWS][COLS], int row, int col, int num){int x = 0;int y = 0;int win = 0; //被排查的个数while ((row * col - num) > win){printf("请输入排雷坐标(格式:行号 列号)\n");scanf("%d%d", &x, &y);if (show[x][y] != '*'){printf("该坐标已经被排查过了 请重新输入:\n");continue;}if (x >= 1 && x <= row && y >= 1 && y <= col){if (secret[x][y] == '1')//如果是1就代表是雷,游戏结束{printf("很遗憾,你失败了\n");printf("请看答案:\n");PrintBoard(secret, ROW, COL);//失败后,给玩家看答案雷盘break;}else{Recursive(secret, show, ROW, COL, x, y); //自动递归排雷函数win = is_win(show, ROW, COL); //计算已经被排查的位置PrintBoard(show, ROW, COL);//打印给玩家的雷盘}}else{printf("坐标非法,请重新输入:\n");}}if (win == (row * col - num)){printf("恭喜你排雷成功\n");}}
递归进行自动排雷(显示周围雷的情况)
Recursive(char secret[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y){if (x >= 1 && x <= row && y >= 1 && y <= col){int count = countmine(secret, x, y);//计算该坐标周围有几个雷if (count == 0){show[x][y] = ' ';//周围没有雷的坐标变为空格int i = 0, j = 0;for (i = x - 1; i <= x + 1; i++)//观察周围八个坐标{for (j = y - 1; j <= y + 1; j++){if (show[i][j] == '*' && (i != x || j != y))//防止重新递归show[x][y]坐标{Recursive(secret, show, ROW, COL, i, j);}}}}else{show[x][y] = count + '0';}}}
计算周围雷的个数
int countmine(char secret[ROWS][COLS], int x, int y){int ret = secret[x - 1][y - 1] + secret[x - 1][y] + secret[x - 1][y + 1]+ secret[x][y - 1] + secret[x][y + 1]+ secret[x + 1][y - 1] + secret[x + 1][y] + secret[x + 1][y + 1] - 8 * '0';return ret;}
计算已经被排查过的位置,进而判断是否还有空位进行排雷游戏
int is_win(char show[ROWS][COLS], int row, int col){int count1 = 0;//已经被排查的坐标个数int i = 0, j = 0;for (i = 1; i <= row; i++){for (j = 1; j <= col; j++){if (show[i][j] != '*')//只要不是*,表示该坐标已经被排查了.{count1++;}}}return count1;}
整体代码
game.h
#pragma once#define _CRT_SECURE_NO_WARNINGS 1//包含头文件#include <stdio.h>#include <stdlib.h>#include <time.h>//方便修改雷盘大小#define ROW 9#define COL 9#define ROWS ROW+2#define COLS COL+2//声明初始化雷盘函数void InitBoard(char board[ROWS][COLS], int rows, int cols, char ret);//声明打印雷盘函数void PrintBoard(char board[ROWS][COLS], int row, int col);//声明布置雷函数void setmine(char board[ROWS][COLS], int row, int col, int num);//声明排查雷的函数void findmine(char secret[ROWS][COLS], char show[ROWS][COLS], int row,int col,int num);
test.c
#include "game.h"void menu(){printf("*************---------------***************\n");printf("******--------- ---------*******\n");printf("******--------- 1.玩游戏 ---------*******\n");printf("\n");printf("******--------- 0.退出游戏 --------********\n");printf("******--------- ---------*******\n");printf("*************---------------***************\n");}void game(){//创建雷盘char Secret[ROWS][COLS] = {0 }; //秘密雷盘char Show[ROWS][COLS] = {0 };//展示的雷盘//初始化雷盘InitBoard(Secret, ROWS, COLS,'0'); //初始化的答案雷盘InitBoard(Show, ROWS, COLS, '*'); //初始化的玩家雷盘//打印雷盘PrintBoard(Show, ROW, COL); //打印给玩家看的雷盘//布置雷int num = ModeSelection(); //模式选择函数,返回雷的数量setmine(Secret, ROW, COL, num); //布置雷函数//排查雷findmine(Secret, Show, ROW, COL, num);}int main(){srand((unsigned int)time(NULL));int input = 0;do{menu();printf("请选择:");scanf("%d", &input); switch (input){case 0:system("cls");system("pause");printf("欢迎您的下一次体验,再见!\n");break;case 1:game();break;default:printf("输入错误,请重新选择\n");break;}} while (input);}
game.c
#include "game.h"//初始化雷盘函数的定义void InitBoard(char board[ROWS][COLS], int rows, int cols, char ret){memset(board, ret, sizeof(board[0][0]) * rows * cols);}//打印雷盘函数的定义void PrintBoard(char board[ROWS][COLS], int row, int col){printf("------------------------扫雷游戏-------------------\n");int i = 0, j = 0;printf(" ");for (i = 1; i <= row; i++){printf("%3d ", i);}printf("\n");printf(" +");for (i = 0; i < row; i++){printf("---+");}printf("\n");for (i = 1; i <= row; i++){printf("%2d", i);printf("|");for (j = 1; j <= col; j++){printf(" %c |", board[i][j]);}printf("\n");printf(" +");for (j = 0; j < col; j++){printf("---+");}printf("\n");}printf("------------------------扫雷游戏-------------------\n");}//模式选择函数的定义(返回设置雷的个数)int ModeSelection(){int num = 0;again: //玩家选择模式错误时返回到这里printf("欢迎玩家来到扫雷游戏\n");printf("\n请选择扫雷难度: (num的代表雷的数量)\n");printf("A.轻松模式:num=5 B.皱眉头模式:num=15 C.出汗模式:num=30 D.DIY难度(玩家自行输入雷的个数)\n ");char pattern = 0;getchar();//清空缓存区scanf("%c", &pattern);switch (pattern){case 'A':case 'a':printf("轻松模式:num=5\n");num = 5;return num;break;case 'B':case 'b':printf("皱眉头模式:num=15\n");num = 15;return num;break;case 'C':case 'c':printf("出汗模式:num=30\n");num = 30;return num;break;case 'D':case 'd':printf("DIY模式:\n");printf("请输入想要布置雷的个数:\n");getchar();//清楚缓存区int intput = 0;scanf("%d", &intput);//用户自定义的雷的个数num = intput;return num;break;default:printf("\n******不好意思,皮蛋还没有此功能按键,请重新选择:******\n\n");goto again;break;}}//定义布置雷函数void setmine(char board[ROWS][COLS], int row, int col, int num){//随机布雷int x = 0;int y = 0;for (int i = 0; i < num; ){x = rand() % row + 1; //x产生[1,row]之间的坐标y = rand() % col + 1; //y产生[1,col]之间的坐标if (board[x][y] == '0'){board[x][y] = '1';i++; }}}//统计坐标周围雷的数量int countmine(char secret[ROWS][COLS], int x, int y){int ret = secret[x - 1][y - 1] + secret[x - 1][y] + secret[x - 1][y + 1]+ secret[x][y - 1] + secret[x][y + 1]+ secret[x + 1][y - 1] + secret[x + 1][y] + secret[x + 1][y + 1] - 8 * '0';return ret;}//自动排雷函数定义Recursive(char secret[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y){if (x >= 1 && x <= row && y >= 1 && y <= col){int count = countmine(secret, x, y);//计算该坐标周围有几个雷if (count == 0){show[x][y] = ' ';//周围没有雷的坐标变为空格int i = 0, j = 0;for (i = x - 1; i <= x + 1; i++)//观察周围八个坐标{for (j = y - 1; j <= y + 1; j++){if (show[i][j] == '*' && (i != x || j != y))//防止重新递归show[x][y]坐标{Recursive(secret, show, ROW, COL, i, j);}}}}else{show[x][y] = count + '0';}}}//计算已经被排查的位置int is_win(char show[ROWS][COLS], int row, int col){int count1 = 0;//已经被排查的坐标个数int i = 0, j = 0;for (i = 1; i <= row; i++){for (j = 1; j <= col; j++){if (show[i][j] != '*')//只要不是*,表示该坐标已经被排查了.{count1++;}}}return count1;}//定义排查雷的函数void findmine(char secret[ROWS][COLS], char show[ROWS][COLS], int row, int col, int num){int x = 0;int y = 0;int win = 0; //被排查的个数while ((row * col - num) > win){printf("请输入排雷坐标(格式:行号 列号)\n");scanf("%d%d", &x, &y);if (show[x][y] != '*'){printf("该坐标已经被排查过了 请重新输入:\n");continue;}if (x >= 1 && x <= row && y >= 1 && y <= col){if (secret[x][y] == '1')//如果是1就代表是雷,游戏结束{printf("很遗憾,你失败了\n");printf("请看答案:\n");PrintBoard(secret, ROW, COL);//失败后,给玩家看答案雷盘break;}else{Recursive(secret, show, ROW, COL, x, y); //自动递归排雷函数win = is_win(show, ROW, COL); //计算已经被排查的位置PrintBoard(show, ROW, COL);//打印给玩家的雷盘}}else{printf("坐标非法,请重新输入:\n");}}if (win == (row * col - num)){printf("恭喜你排雷成功\n");}}