博客
关于我
c语言扫雷游戏,可以递归展开非雷位置,第一次不踩雷
阅读量:358 次
发布时间:2019-03-04

本文共 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;}

四、运行结果

  • 开始界面:

在这里插入图片描述

  • 扫雷过程:
    空格部分就是递归展开的部分。在这里插入图片描述
  • 游戏结束:
    在这里插入图片描述
    在这里插入图片描述

五,思考

还是多动手吧,写的过程中好多小错误。如循环时不记得给循环变量赋值。还有就是这个程序还可以优化一下,比如做成闯关模式,或者让用户自己选择棋盘大小和雷的个数。应该会很有意思。

转载地址:http://ksug.baihongyu.com/

你可能感兴趣的文章
Extjs布局详解
查看>>
Android数据库
查看>>
C语言之指针再涉(二)
查看>>
application类
查看>>
Linux基础命令(十四)软件安装的后续
查看>>
Perl(二)Perl简介
查看>>
HTML基础,块级元素/行内元素/行内块元素辨析【2分钟掌握】
查看>>
keil左侧文件调整方法
查看>>
本地分支关联远程分支
查看>>
函数求偏移量
查看>>
STM8 GPIO模式
查看>>
python多态和封装
查看>>
STM32boot启动
查看>>
回调函数(callback function)
查看>>
omnet++
查看>>
23种设计模式一:单例模式
查看>>
Qt中的析构函数
查看>>
CSharp中委托(一)委托、匿名函数、lambda表达式、多播委托、窗体传值、泛型委托
查看>>
二叉堆的c++模板类实现
查看>>
C语言实现dijkstra(adjacence matrix)
查看>>