【纯手工扫雷“不含一点添加剂”】完全c语言版 您所在的位置:网站首页 扫雷游戏方法 【纯手工扫雷“不含一点添加剂”】完全c语言版

【纯手工扫雷“不含一点添加剂”】完全c语言版

2023-04-21 05:24| 来源: 网络整理| 查看: 265

前言

扫雷包括雷区、地雷计数器(位于左上角,记录剩余地雷数)和计时器(位于右上角,记录游戏时间),确定大小的矩形雷区中随机布置一定数量的地雷(初级为9*9个方块10个雷,中级为16*16个方块40个雷,高级为16*30个方块99个雷,自定义级别可以自己设定雷区大小和雷数,但是雷区大小不能超过24*30),玩家需要尽快找出雷区中的所有不是地雷的方块,而不许踩到地雷。

今天的内容我们就来写一个初级9*9的扫雷

一、🤔扫雷如何基本实现的?

首先它需要来打印一个9*9的‘游戏棋盘’就像左下角那样,由于我们是c语言板就不搞这莫花哨了,就搞个c语言纯手工版吧

原画版游戏棋盘

手工版棋盘

 然后就是扫雷的关键玩家行动的排雷和标记雷了,当然还有比必不可少的判断函数

二、代码实现1.👀创建事先打包分类:

我们将游戏实现的底层代码放在test.c里面,将需要使用的且函数的实现放在game.c中,头文件声明一下。  方便我们管理

2.👀game.h

我们先来看看我们会用到那些函数与它的作用

#pragma once #include #include #define MINES 10//雷的数量 #define ROW 9 #define COL 9 //比棋盘大一圈防止数组越界访问 #define ROWS ROW + 2 #define COLS COL + 2 //初始化棋盘 void init_board(char board[ROWS][COLS], int rows,int cols,char set); //打印棋盘 void print(char board[ROWS][COLS], int row, int col); //埋雷 void set_mine(char mine_board[ROWS][COLS], int row, int col); //玩家行动 int player_action(char show_board[ROWS][COLS], char mine_board[ROWS][COLS]); //排雷 int demine(char show_board[ROWS][COLS], char mine_board[ROWS][COLS], int row, int col); //标记雷 void mark_mine(char show_board[ROWS][COLS], char mine_board[ROWS][COLS], int row, int col); //判断棋盘是否全部翻开 int judge_ogame(char show_board[ROWS][COLS], int row, int col); //排雷翻格子 void over_mine(char show_board[ROWS][COLS], char mine_board[ROWS][COLS], int x, int y);3.👀test.c

先看预期效果如图                                                                                    :

玩家看到的:游戏进入菜单,并提示用户选择开始游戏,打印棋盘 

    由于我们需要展示棋盘,又要记录雷的位置,这里我们创建show来展示和mine来记录雷两个   棋盘来分工一下。 

int main() { //用于随机埋雷 srand((unsigned int)time(NULL)); int input = 0; do { menu(); printf("用户请选择:"); scanf("%d", &input); switch (input) { case 1: //开始游戏 start_game(); break; case 0: printf("退出游戏!!\n"); break; default: printf("输入错误,请重新输入:"); break; } } while (input); }

  当然在玩家看不到的地方:两个棋盘的初始化、埋雷等准备工作也是必不可少的 ╰( ̄ω ̄o) 

当求边界格子周围9宫格内雷的数量

由于在后续求边界雷的数量(如右图的绿框) 

为了避免越界访问,我们就将棋盘的定义大一圈 ,则为11*11

#include"game.h" void menu() { printf("**********************\n"); printf("*******1.paly*********\n"); printf("*******0.exct*********\n"); printf("**********************\n"); } //开始游戏 void start_game() { int flag = 1; char show[ROWS][COLS] = { 0 };//用于展示扫雷棋盘 char mine[ROWS][COLS] = { 0 };//用于记录扫雷信息 //初始化棋盘 init_board(show,ROWS,COLS,'*'); init_board(mine,ROWS,COLS,'0'); //打印棋盘 print(show, ROW, COL); //埋雷 set_mine(mine, ROW, COL); //print(mine, ROW, COL);(调试用) //玩家行动 while (flag) { // flag=1 游戏继续 // flag=0 游戏结束 if (player_action(show, mine, ROW, COL) == 0) break; //打印棋盘 print(show, ROW, COL); //判断棋盘是否翻完 flag = judge_ogame(show, ROW, COL); } } 4.👀game.c一、🐗初始化棋盘(init_board)

由于我们这里需要初始化两个棋盘,所以为了通用性,我们需要将把棋盘内需要初始化的类型传进去就有了 char set

void init_board(char board[ROWS][COLS], int rows, int cols, char set) { for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { board[i][j] = set; } } }二、 🐗打印棋盘(print)

访问方式类似与 ‘初始化棋盘’,再加一点点修饰

红框为修饰部分

void print(char board[ROWS][COLS], int row, int col) { int i, j; printf(" _________扫雷游戏_________\n"); printf(" 1 2 3 4 5 6 7 8 9\n"); 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"); } }三、🐗玩家的行动 (play_action)

1.💪这里我们分一下流,分为排雷和标记雷

2.💪将 flag = 0 时,认定为游戏结束,flag = 1时,认定为游戏继续

(对应了test.c中start_game函数)

int player_action(char show_board[ROWS][COLS], char mine_board[ROWS][COLS]) { int op = 0; int flag = 1; printf("请输入你想\n1.排雷\n2.标记雷\n"); scanf("%d", &op); switch (op) { //排雷 case 1: flag = demine(show_board, mine_board, ROW, COL); break; //标记雷 case 2: mark_mine(show_board, mine_board, ROW, COL); break; default: printf("输入错误,请重新输入!"); } return flag; }四、🐗埋雷(set_mine)

💪利用rand、srand与time函数生成的时间戳,生成随机数(srand在int main()主函数里一开始就设置好了)

void set_mine(char mine_board[ROWS][COLS], int row, int col) { int x, y; for (int i = 0;i < MINES; ) { x = rand() % row + 1; y = rand() % col + 1; if (mine_board[x][y] == '0') { //printf("%d %d\n", x, y);生成雷的坐标(调试检查用) mine_board[x][y] = '1'; i++; } } } 五、🐗排雷(demine)

排雷时如果排的是‘雷’话,那就game over😱

int demine(char show_board[ROWS][COLS], char mine_board[ROWS][COLS], int row, int col) { int x, y; int flag = 1; while (1) { printf("请输入你想排雷的坐标:"); scanf("%d %d", &x, &y); if (show_board[x][y] == '*') { if (mine_board[x][y] == '1') { printf("你被炸死了!!游戏结束\n"); return 0; } else if (mine_board[x][y] == '0') { over_mine(show_board, mine_board, x, y); return 1; } } else printf("坐标非法或已被占用,"); } }六、🐗排雷时不是雷,连续翻格子(over_mine)

💪1.我们要筛选一下不合法和已经翻过的坐标(因为“连续”翻会用到递归,可能会越界访问和重复去翻翻过的格子导致死循环)

 💪2.求该坐标(x,y)周围有几个雷

如图我们求(x,y)的坐标,该坐标就为周围8个格子雷数之和。                                                                      但是这里有个问题🤔:我们之前定义棋盘时用的是char而不是int及,字符 '0' ≠ 整形 0,如果直接把8个坐标对应的数加起来它(字符对应的ascii码加起来)肯定不对。                                                         

举2个列子:char  0 - char 0  = int 0         char  1 - char 0  = int 1                           

根据上面的例子我们可以得到:char x - char y =int(x,y的ASCII码之差)

解决方法:相加时,将每个格子与char 0('0')相减,最后将结果再加上char 0('0')

特别的:为啥不先加起来在直接减去多余的'0'呢?因为ACSII码,有上限为“127”,如果直接加会溢出的!!!☠☠☠

 💪2.连续的实现:

黄色周围没有雷

当(x,y)坐标周围一个雷都没有时,及该点为0,在展示面板(show)为空格 ,记录雷的面板(mine)上就为'0',

此时就该连续翻格子了

炸金花般的连锁反应

如左图:我们从(x,y)向周围蔓延开,并求周围格子它们周围的雷数量。在此我们使用一个循环加递归的方式去实现该功能(在 六大点的1小点中我们设好了第一个终止条件:翻过的就不翻),第二个终止条件当然就是周围雷的数量不为' 0 '辣🌶🌶🌶

效果预览

代码如下:

void over_mine(char show_board[ROWS][COLS], char mine_board[ROWS][COLS], int x, int y) { //判断坐标是否翻过与是否合法 if (show_board[x][y] != ' ' && (x >= 1 && y >= 1 && x


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有