编程之美里的挖雷游戏:

缘由

今天的新书:编程之美 到手了,随便读了翻了一下。就翻到一个有趣的问题,计算扫雷游戏中未知方块是雷的概率。

《编程之美里的挖雷游戏:》

看看图,就是那些还可以点的方块是雷的概率是多少。相信大家都玩过,我就不介绍游戏规则了。

思路

简单的思考之后,我有了一个思路:

  1. 对每一个出现的数字作如下计算
  2. 针对一个数字,统计数字周边可点击的方块的个数
  3. 数字的数值除以方块的个数,就是周边方块是雷的概率
  4. 如果多个数字计算了同一个方块的是雷的概率,则记录概率的高的那一个。

本来想看看参考答案的,翻过书的一页过去居然是空白,然后就是下一页,书上对这道题没有解答。

命令行的扫雷游戏

界面

为了验证我的想法是正确的,我决定自己先写一个命令行版扫雷游戏。

我打算用一个二维数组来来表示扫雷的界面:就16×16(书上的图的大小,但是为了和储存雷的数组统一,还是使用17×17)吧,再用一个17×17的数组存储雷的位置和各个方块的周边的雷的数量,第一列和第一行用于标识行列号。

用一些特别的符号来表示,

  1. 数字1-8已经被占了,用于表示周边方块的雷数
  2. +来表示可以点击的地方,空白的地方
  3. 空白 用来表示上图中空白的部分

流程

先对存储雷的位置和各个方块的周边的雷的数量的17×17(除去行列号应该是16×16)的数组赋值,如下

  1. 先随机生成雷的位置,雷就用99来代替吧,选用数字是为了打印方便
  2. 然后在雷的周边方块生成数字,就一个雷一个雷的计算吧,计算一个雷周边方便未变1,第二个雷计算的周边方块在原有的基础上增加1
  3. 没有雷也没有数字的地方就以0来表示。这是因为方便在第二步的时候直接加起来
  4. 界面就按上面所说的字符代表,通过输入行和列来表示点击了哪个雷
  5. 每输入一对数相当于点击了一下方块,只有+号才可以被点击
  6. 直到界面中只剩下雷没有被点的时候,游戏结束。

代码


#include <stdlib.h>
#include <stdio.h>
#include "time.h"


#define HEXASCII(val) ((val)>0 && (val)<10)?'0'+(val):\
                      ((val)>9 && (val)<16)?'A'+(val)-10:'0'  //将十进制转化为ASCII,在printf打印的时候方便处理


#define MAXTHUNDERCOUNT 10      //产生最大的地雷数

static char thunder[17][17];
static char view[17][17];

void initThunder(char thunder[17][17]) {
	int i, j;
	//循环变量
	int x, y;
	//x,y的坐标
	for (i = 0; i < 17; i++) {
		thunder[0][i] = i;
		//设置行号
		thunder[i][0] = i;
		//设置列号
	}
	for (i = 1; i < 17; i++) {
		for (j = 1; j < 17; j++) {
			thunder[i][j] = 0; //全部设置为0
		}
	}

	srand (time(NULL));
	//产生随机种子,每次产生的随机数都不一样
	for(i=0;i<MAXTHUNDERCOUNT;i++) {
		x=rand()%16+1;
		y=rand()%16+1;
		thunder[x][y]=99; //用99代表雷

		//将周围雷周围的数字加1
		if(thunder[x-1][y]>=0&&thunder[x-1][y]<=8) {
			thunder[x-1][y]++;
		}
		if(thunder[x+1][y]>=0&&thunder[x+1][y]<=8) {
			thunder[x+1][y]++;
		}
		if(thunder[x][y-1]>=0&&thunder[x][y-1]<=8) {
			thunder[x][y-1]++;
		}
		if(thunder[x][y+1]>=0&&thunder[x][y+1]<=8) {
			thunder[x][y+1]++;
		}

		if(thunder[x-1][y-1]>=0&&thunder[x-1][y-1]<=8) {
			thunder[x-1][y-1]++;
		}
		if(thunder[x-1][y+1]>=0&&thunder[x-1][y+1]<=8) {
			thunder[x-1][y+1]++;
		}
		if(thunder[x+1][y-1]>=0&&thunder[x+1][y-1]<=8) {
			thunder[x+1][y-1]++;
		}
		if(thunder[x+1][y+1]>=0&&thunder[x+1][y+1]<=8) {
			thunder[x+1][y+1]++;
		}
	}
}

void printView(char view[17][17]) {
	int i;
	int j;
	for (i = 0; i < 17; i++) {
		for (j = 0; j < 17; j++) {
			if (i == 0 || j == 0) {
				printf(" %2d", view[i][j]); //打印行列号,必须用%d
			} else {
				printf(" %2c", view[i][j]);
			}
		}

		printf("\n");
	}

}

void initView( char view[17][17]) {
	//输出thunder
	/*
	 for(i=0;i<17;i++){
	 for(j=0;j<17;j++){
	 printf(" %2d",thunder[i][j]);//打印行列号,必须用%d
	 }
	 printf("\n");
	 }*/
	int i, j;
	//循环变量
	int x, y;
	//x,y的坐标
	for (i = 0; i < 17; i++) {
		view[0][i] = i;
		//设置行号
		view[i][0] = i;
		//设置列号
	}
	for (i = 1; i < 17; i++) {
		for (j = 1; j < 17; j++) {
			view[i][j] = '+';
		}
	}

	printView(view);

}

void recursionToSpace( int x, int y) {
	view[x][y] = ' ';
	if(x - 1 > 0){												//第一个是为了防止出界
		if ( thunder[x - 1][y] == 0 && view[x - 1][y] == '+') {	//最后一个表示这个已经变过了,已经是空格的话,就不用再变了
				recursionToSpace(x - 1,y);
			}else if(thunder[x - 1][y] > 0) {
				view[x - 1][y]=HEXASCII(thunder[x - 1][y]);
			}
	}

	if(x + 1 < 17 ){
		if (thunder[x + 1][y] == 0 && view[x + 1][y] == '+') {
			recursionToSpace(x + 1,y);
		}else if(thunder[x + 1][y] > 0 ){
			view[x + 1][y]=HEXASCII(thunder[x + 1][y]);
		}
	}
	if(y - 1 > 0){
		if ( thunder[x][y - 1] == 0 && view[x][y - 1] == '+') {
			recursionToSpace(x,y - 1);
		}else if(thunder[x][y - 1] > 0){
			view[x][y - 1]=HEXASCII(thunder[x][y - 1]);
		}
	}
	if(y + 1 < 17){
		if (thunder[x][y + 1] == 0 && view[x][y + 1] == '+') {
			recursionToSpace(x,y + 1);
		}else if( thunder[x][y + 1] >0){
			view[x][y + 1]=HEXASCII(thunder[x][y + 1]);
		}
	}

	if(x-1 > 0 && y-1 > 0){
		if (thunder[x - 1][y - 1] == 0 && view[x - 1][y - 1] == '+') {
			recursionToSpace(x - 1,y - 1);
		}else if( thunder[x - 1][y - 1] > 0){
			view[x - 1][y - 1] =HEXASCII(thunder[x - 1][y - 1] );
		}
	}

	if(x - 1> 0 && y + 1 < 17){
		if (thunder[x - 1][y + 1] == 0 && view[x - 1][y + 1] == '+') {
			recursionToSpace(x - 1,y + 1);
		}else if(thunder[x - 1][y + 1] > 0){
			view[x - 1][y + 1]=HEXASCII(thunder[x - 1][y + 1]);
		}
	}

	if(x + 1<17 && y-1 > 0){
		if (thunder[x + 1][y - 1] == 0 && view[x + 1][y - 1] == '+') {
			recursionToSpace(x + 1,y - 1);
		}else if(thunder[x + 1][y - 1] > 0){
			view[x + 1][y - 1]=HEXASCII(thunder[x + 1][y - 1]);
		}

	}
	if(x+1<17 && y+1 <17){
		if (thunder[x + 1][y + 1] == 0 && view[x + 1][y + 1] == '+') {
			recursionToSpace(x + 1,y + 1);
		}else if(thunder[x + 1][y + 1] > 0){
			view[x + 1][y + 1]=HEXASCII(thunder[x + 1][y + 1]);
		}
	}

}

int main(){

    initThunder(thunder);
	initView(view);

	int x,y,i,j;
	while(1){
		printf("想点击的坐标:\n");
		scanf("%d %d",&x,&y);
		printf("你选择的是结果是:%d\n",thunder[x][y]);
		if(thunder[x][y]==99){		//如果点到了雷
			printf("踩到雷了,输了\n");
	        for(i=0;i<17;i++){
	            for(j=0;j<17;j++){
	            	printf(" %2d",thunder[i][j]);//打印行列号,必须用%d
	            }
	            printf("\n");
	        }
		}else if(thunder[x][y]==0){	//如果点到的是空白
									//就要这个空白周边的8个不是雷的方块也显示出来
									//并且如果周边是空白,也会类似方式传染开,相信玩过扫雷的都明白
			recursionToSpace(x, y);
			printView(view);
		}else{						//如果点到是数字
			view[x][y]=HEXASCII(thunder[x][y]);
			printView(view);
		}
		int VictoryFlag=0;
									//那么只有遍历才知道有多少加号
		for (i = 1; i < 17; i++) {
			for (j = 1; j < 17; j++) {
				if(view[i][j] == '+')
					VictoryFlag++;
			}
		}
		if(VictoryFlag==MAXTHUNDERCOUNT){//胜利条件,view中的+号等于MAXTHUNDERCOUNT即胜利了
			printf("胜利了,游戏结束\n");
			break;
		}

	}
}

游戏胜利的截图

《编程之美里的挖雷游戏:》

    原文作者:zy825316
    原文地址: https://blog.csdn.net/zy825316/article/details/21101345
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞