
c语言扫雷游戏,可以递归展开非雷位置,第一次不踩雷
发布日期:2021-05-07 22:55:42
浏览次数:13
分类:原创文章
本文共 5313 字,大约阅读时间需要 17 分钟。
一、 问题
c语言实现扫雷游戏,非雷位置可以递归展开,且为保证游戏体验,用户第一次扫雷时不能踩中雷。
二、解决思路
-
扫雷游戏大家都玩过,具体规则我也就不再赘述。要实现扫雷游戏,我们至少得需要两个棋盘,一张给用户展示,让用户输入在这张棋盘上进行扫雷,另一张为埋雷棋盘,这张棋盘上埋藏若干个雷,将用户输入的坐标与这张棋盘上对应的坐标进行对比,如果是雷,则游戏结束,如果不是雷则继续。
-
程序需要实现的功能以及实现该功能的函数。
-
menu函数,指引用户做出选择。
-
game函数,游戏从这里开始。
-
setmine函数,实现埋雷,并找到一个没有雷的坐标,用于保护用户第一次不能踩中雷。
-
show函数,展示棋盘。
-
minecount函数,计算该位置周围雷的个数。
-
open函数,对非雷位置进行递归展开。
-
judge函数,判断用户是否扫雷成功。
三、代码实现
- 第一步,编写game.h头文件,把需要用到的函数声明及一些宏定义写在里面。
#ifndef __GAME_H__#define __GAME_H__#include <stdio.h>#include <windows.h>#include <time.h>#pragma warning(disable:4996)#define ROW 12#define COL 12#define MINENUM 20void menu();void setmine(char mineboard[][COL],int * x, int * y);void show(char board[][COL]);int minecount(char mineboard[][COL], int x, int y);void game();void open(char mineboard[][COL], char sweepboard[][COL], int x, int y);int judge(char sweepboard[][COL]);#endif
- 第二步,编写main函数,从这里调用函数
#include "game.h"int main() { menu(); system("pause"); return 0;}
- 第三步,编写game.c,把需要用到的函数都写在里面。
- menu函数
void menu() //menu函数,指引用户做出选择。{ int quit = 1; while (quit) { printf("###############################\n"); printf("####### 欢迎来到扫雷 ########\n"); printf("###############################\n"); printf("#####1:play ####\n"); printf("#####2:exit ####\n"); printf("###############################\n"); printf("###############################\n"); int k = 0; scanf("%d", &k); switch (k) { case 1: game();//输入1,调用game函数,游戏开始。 break; case 2: quit = 0; printf("Bye bye!\n");//输入0,程序运行结束。 break; default: printf("输入有误,请重新输入:\n"); break; } }}
- game函数
void game()// game函数,游戏开始。{ int flag = 1; int x0 = 0; int y0 = 0; char sweepboard[ROW][COL];//第一个二维数组,扫描棋盘,用于给用户展示。为方便计算 // 定义数组为12 * 12,实际用到的是10 * 10的棋盘,后续棋盘均指10 * 10棋盘。 char mineboard[ROW][COL];//第二个二维数组,埋雷棋盘,用于埋雷。 memset(sweepboard, '*', sizeof(sweepboard));//扫描棋盘初始化均为‘*’ memset(mineboard, '0', sizeof(mineboard));//埋雷棋盘初始化均为‘0’ setmine(mineboard, &x0, &y0);//调用setmine函数,系统随机埋雷,整型变量x0和y0用于传回一个非雷的坐标。 while (1) { system("cls"); show(sweepboard); //show函数,展示棋盘。 printf("请输入坐标:"); int x = 0; int y = 0; scanf("%d %d", &x, &y); if (x < 1 || x > 10 || y < 1 || y > 10) { printf("输入坐标有误,请重新输入!\n"); Sleep(1500); continue; } if (sweepboard[x][y] != '*') { printf("该位置已被扫过,请重新输入!\n"); Sleep(1500); continue; } if (mineboard[x][y] == '1') { if (flag == 1) { mineboard[x][y] = '0'; mineboard[x0][y0] = '1'; flag = 0; }//用户踩到雷了,如果是第一次,就与x0,y0坐标进行交换。 else { printf("很遗憾,你输了!\n"); Sleep(1500); printf("雷达:(1代表有雷,0代表没雷)\n"); Sleep(1500); show(mineboard);//游戏结束,输出埋雷棋盘,让用户明白输在哪里。 break; } } open(mineboard, sweepboard, x, y);//若没有踩到雷,调用open函数,判定是否需要展开。 if (judge(sweepboard) == 1) { //调用judge函数,判定是否扫雷成功。 printf("恭喜你,扫雷成功!\n"); break; } flag = 0;//用户第一次扫完,不在有第一次不可能踩中雷的保护。 }}
- setmine函数
void setmine(char mineboard[][COL],int * x, int * y )//setmine函数,开始埋雷。{ int times = MINENUM;//循环执行次数,即雷的个数。 srand((unsigned long)time(NULL)); while (times) { int x = rand() % (ROW - 2) + 1; int y = rand() % (COL - 2) + 1; if (mineboard[x][y] != '1') { mineboard[x][y] = '1'; times--; } } while (1) { *x = rand() % (ROW - 2) + 1; *y = rand() % (COL - 2) + 1; if (mineboard[*x][*y] == '0') { break; } }//在埋雷棋盘中找到一个随机非雷坐标。}
- show函数
void show(char board[][COL])//show函数,展示棋盘。{ int i = 1; int j = 0; printf(" ");//调整列标位置。 for (; i < 11; i++) { printf("%d ", i);//输出列标。 } printf("\n"); for (i = 1; i < 11; i++) { printf(" ----------------------------------------\n");//输出每一行之间分割线。 printf("%2d|", i);//输出行标。 for (j = 1; j < 11; j++) { printf(" %c |", board[i][j]);//输出棋盘元素。 } printf("\n"); } printf(" ----------------------------------------\n");//输出最后一行分割线。}
- minecount函数
int minecount(char mineboard[][COL], int x, int y)//minecount函数,统计该坐标周围雷的个数。{ int c = mineboard[x - 1][y - 1] + mineboard[x - 1][y] + mineboard[x - 1][y + 1] +\ mineboard[x][y - 1] + mineboard[x][y + 1] + mineboard[x + 1][y - 1] +\ mineboard[x + 1][y] + mineboard[x + 1][y + 1] - 8 * '0';//棋盘是字符型的,把该坐标周围8个坐标里的字符加起来 //再减去8 * '0',计算时用的是acsii值,所得结果就是雷的个数。 return c;}
- open函数
void open(char mineboard[][COL], char sweepboard[][COL], int x, int y)//open函数,判断是否需要递归式展开。{ if (!minecount(mineboard, x, y))//调用minecount函数,计算周围雷的个数,若为0,则需要展开。 { sweepboard[x][y] = ' '; int i = 0; int j = 0; for (i = x - 1; i <= x + 1; i++) { for (j = y - 1; j <= y + 1; j++) { if (sweepboard[i][j] == '*' &&\ i > 0 && i < 11 && j > 0 && j < 11)//若该位置未被扫过且在棋盘范围内则继续递归调用open函数。 open(mineboard, sweepboard, i, j); } } } else { sweepboard[x][y] = minecount(mineboard, x, y) + '0';//若不需要展开,则为该位置赋值周围雷的个数, //棋盘是字符型的,需要加'0'才是对应数字的字符。 }}
- judge函数
int judge(char sweepboard[][COL]) //judge函数,判定用户是否扫雷成功。{ int i = 1; int j = 1; int count = 0; for (; i <= ROW - 2; i++) { for (j = 1; j <= COL - 2; j++) { if (sweepboard[i][j] == '*') { count++; }//遍历棋盘元素,若该位置未被扫过,则记录下来。 if (count > MINENUM) { return 0; }//若未被扫过的个数大于雷的个数,则游戏继续。 } } return 1;}
四、运行结果
- 开始界面:
- 扫雷过程:
空格部分就是递归展开的部分。 - 游戏结束:
五,思考
还是多动手吧,写的过程中好多小错误。如循环时不记得给循环变量赋值。还有就是这个程序还可以优化一下,比如做成闯关模式,或者让用户自己选择棋盘大小和雷的个数。应该会很有意思。
发表评论
最新留言
留言是一种美德,欢迎回访!
[***.207.175.100]2025年03月19日 09时01分16秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
webwxbatchgetcontact一个神奇的接口
2019-03-04
Edge浏览器:你的的内核我的芯
2019-03-04
【考研英语-基础-简单句】简单句的核心变化_谓语情态
2019-03-04
Jetson AGX Xavier硬件自启动
2019-03-04
统计字符数
2019-03-04
JS数据类型的判断
2019-03-04
实现一个简易Vue(三)Compiler
2019-03-04
仿小米商城(上)
2019-03-04
【30】kotlin 闭包
2019-03-04
自动安装服务2
2019-03-04
js的各种数据类型判断(in、hasOwnProperty)
2019-03-04
严格模式、混杂模式与怪异模式
2019-03-04
HTML 和 CSS 简单实现注册页面
2019-03-04
(SpringMVC)springMVC.xml 和 web.xml
2019-03-04
(LeetCode)Java 求解搜索旋转排序数组
2019-03-04
DP - Tickets - HDU - 1260
2019-03-04
Spring 与使用STOMP消息
2019-03-04
Java Swing JList:列表框组件
2019-03-04