扫雷类似于笔者发布的第一篇三子棋,不过还是有诸多细节需要注意。笔者技艺拙劣,仅能完成简易版扫雷,提前说明这个扫雷是没能实现递归(即类似于真正扫雷,点一个展开一片的功能)。
一.头文件
#pragma once #include<stdio.h> #include<stdlib.h> #include<time.h> #define Rows 11 #define Cols 11 #define Col 9 #define Row 9 #define Easy_Count 10//设置十个雷 void InitBoard(char Board[Rows][Cols], int rows, int cols, char set); void Disboard(char Board[Rows][Cols], int row, int col); void SetMine(char Board[Rows][Cols], int row, int col); void FindMine(char Mine[Rows][Cols], char Show[Rows][Cols], int row, int col);
头文件主要是宏的定义和函数声明。
这里为什么要这样定义宏呢?因为笔者设置了两个表格,而真实的表格是11*11的表格,只打印出来了9*9的玩家操作表格。这样设置是方便后续的判断胜利与失败,要是诸君有兴趣的话,可以往后继续看,笔者会做解释。
二.函数实现
先上代码:
#include"GAME.h" void InitBoard(char Board[Rows][Cols], int rows, int cols, char set) { int i = 0; int j = 0; for (i = 0; i < Rows;i++) { for (j = 0; j < Cols;j++) { Board[i][j] = set; } } } void Disboard(char Board[Rows][Cols], int row, int col) { //首先需要一个行号和列号 int i = 0; for (i = 0; i <=col; i++) { printf("%d ", i); } printf("\n"); int j = 0; for (i = 1; i <= row; i++) { printf("%d ", i); for (j = 1; j <= col; j++) { printf("%c ", Board[i][j]); } printf("\n"); } } void SetMine(char Board[Rows][Cols], int row, int col) { //设置地雷 int count = Easy_Count; while (count) { int x = rand() % row + 1; int y = rand() % col + 1; if (Board[x][y] == '0') { Board[x][y] = '1'; count--; } } } int get_mine_count(char Mine[Rows][Cols], int x, int y) { return Mine[x - 1][y] + Mine[x - 1][y - 1] + Mine[x - 1][y + 1] + Mine[x][y - 1] + Mine[x][y + 1] + Mine[x + 1][y] + Mine[x + 1][y + 1]+ Mine[x + 1][y - 1]-8*'0'; } void FindMine(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("请输入排查雷的坐标:>"); scanf("%d%d", &x, &y); if (x >= 1 && x <= row && y >= 1 && y <= col) { //坐标合法 //1.踩雷 if (Mine[x][y] == '1') { printf("很遗憾,你被炸死了\n"); Disboard(Mine, row, col); break; } else //不是雷 { //计算x,y坐标周围有几个雷 int count = get_mine_count(Mine, x, y); Show[x][y] = count + '0'; Disboard(Show, row, col); win++; } } else { printf("输入坐标非法,请重新输入\n"); } } if (win == row * col - Easy_Count) { printf("恭喜你,排雷成功\n"); Disboard(Mine, row, col); } }
1.雷包设置:
笔者在雷包设置时是取巧了,在初始化表格的时候,设置了两个表格,一个表格是给我们程序员看的,即Mine[][]='0',这是没有雷的地方,而给玩家看的那个表Show[][]='*'进行了遮蔽。把有雷的地方设置为字符'1'。这一步也是取巧,因为在显示所要位置处需要计算周遭8个格子(因为要计算8个格子所以如果只设置9*9的表格,那么边角的坐标在计算周遭的雷时是需要特殊处理的,会增加代码的负荷,故设置了11*11的表格而只显示9*9的表格)总共有几颗雷,而1和0无疑是极其好运算的。但是需要诸君注意的是,这里还是字符1和字符0.所以下一步
这一步,便是计算周围有几颗雷,需要注意字符'1'-字符'0'=1,所以便有了图中的-8*'0'也有了下图的+'0'.
三.主函数
#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 }; printf("扫雷\n"); //需要两个表格,一个表格负责展示,一个表格负责操作 InitBoard(Mine, Rows, Cols,'0');//由于两个一个负责自己看,但玩家不能看到 InitBoard(Show, Rows, Cols,'*');//初始化两个 //打印棋盘 //Disboard(Mine, Row, Col); Disboard(Show, Row, Col); SetMine(Mine, Row, Col); //扫雷 //mine 数组里找信息,显示在show FindMine(Mine, Show, Row, Col);//该数组问题是不能展开一片 } void test() { srand((unsigned int)time(NULL)); int input = 0; do { menu(); scanf("%d", &input); switch (input) { case 1: game(); break; case 0: printf("退出成功\n"); break; default: printf("选择错误,请重新选择\n"); break; } } while (input); } int main() { test(); return 0; }
四.函数问题
这个构造是比较取巧的,笔者认为是极其简易且失败的😂。
1.首先在设置雷包的时候便借助了字符'1'和字符'0',而非正统的雷。
2.无法实现输入一个坐标就展开一片的问题。就是说传统的扫雷游戏是输入一个坐标会对周遭8个坐标进行计算是否有雷,如果没有雷,那么会对周围8个坐标的周围8个坐标再次运算是否有雷,如此循环,便能看到传统扫雷的展开一片。而笔者所写的是简易的,坦白说是笔者技艺浅薄,无法实现这个递归。
3.不能简单只实现递归,递归后,判定条件就要发生改变。笔者的扫雷属实low,想要获胜需要输入71个坐标😂。所以这个递归的函数还是很能提升用户体验的。