typescript版本的扫雷游戏设计(思路+代码)

思路:

	生成图片矩阵
	点击格子
	如果 第一次 且 新游戏:
		生成除该格子外的雷图
		统计数字
	如果 该格子是雷:
		爆炸
	否则:
		如果 格子数字是0:
			深度搜索0区域,加入展示区域
		如果格子已经打开:
			忽略
		如果格子标识旁边有雷
			把该格子加入展示区域
	打开展示区域

代码(typescript版本)

/**
 * 地图数字描述
 * 0 空格子,可批量打开
 * -1 雷区
 * -2 被打开的格子
 * >0 描述周围雷区个数
*/
class SaoLei {
	public map: any[] = [];
	public showRec: any[] = [];
	public initWidth: number = 10;//控制横坐标个数
	public initHeight: number = 50;//控制纵坐标个数
	public boomNum: number = 50;//设置随机雷数目
	public dirx = [-1, 0, 1, -1, 1, -1, 0, 1]; //八方向x坐标,用以统计旁边有雷的个数
	public diry = [-1, -1, -1, 0, 0, 1, 1, 1];//八方向y坐标,用以统计旁边有雷的个数
	public shows: number[] = []; //展示区域集合
	public deepOpen: number[] = []; //深搜节点集合
	public deepDirX = [-1, 1, 0, 0]; //四方向x坐标,用以深搜可批量打开区域
	public deepDirY = [0, 0, -1, 1];//四方向y坐标,用以深搜可批量打开区域
	public bcreateBoom: boolean = false; //是否生成雷图标识
	public booms: number[] = [] //雷区坐标
	public constructor() {
	}
	/**
	 * 全部初始化为0
	 * i ->y
	 * j ->x
	 */
	public init() {
		// console.log("init");

		for (let i = 0; i < this.initHeight; i++) {
			this.map[i] = [];
			for (let j = 0; j < this.initWidth; j++) {
				this.map[i][j] = 0;
				this.showRec[i][j] = 0;
			}
		}
		// console.log("init finish");

	}
	/**
	 * 除(X,Y)不可是雷,避免一点开就爆炸
	 */
	private createBoom(x, y) {
		/**
		 * 把坐标转化成id,公式是x+y*this.initWidth
		 */
		this.booms = [];
		let limit = x * this.initWidth + y;
		this.booms = this.getRandom(0, this.initWidth * this.initHeight, limit, this.boomNum);
		// console.log("target", target);

		for (let t of this.booms) {
			//id逆向为对应的坐标
			let tx = Math.floor(t / this.initWidth);
			let ty = Math.floor(t % this.initWidth);
			this.map[tx][ty] = -1;
		}
		this.bcreateBoom = true;
		this.calcMapnum();
		this.clickMap(x, y);
	}
	/**
	 * 点击地图响应
	 */
	public clickMap(x, y) {
		// console.log("click");

		if (!this.bcreateBoom) {//如果还没有创建雷图
			this.createBoom(x, y);//创建雷图
			return;
		}
		if (this.showRec[x][y] == 1) {//已经被打开了
			return;
		}

		this.shows = [];

		if (this.map[x][y] == -1) {
			//游戏结束响应
		} else if (this.map[x][y] > 0) {
			this.shows.push(x + y * this.initWidth);
		} else if (this.map[x][y] == 0) {
			this.deepOpen.push(x + y * this.initWidth);
			this.getShows();
		}
		for (let show of this.shows) {
			let sx = Math.floor(show / this.initWidth);
			let sy = Math.floor(show % this.initWidth);
			this.showRec[sx][sy] = 1;
		}
		console.log(this.map);

	}
	/**
	 * 深搜可以批量打开的格子
	 */
	private getShows() {
		while (this.deepOpen.length) {
			let open = this.deepOpen.shift();
			this.shows.push(open);
			let ox = Math.floor(open / this.initWidth);
			let oy = Math.floor(open % this.initWidth);
			for (let k = 0; k < this.deepDirX.length; k++) {
				let nearX = ox + this.deepDirX[k];
				let nearY = oy + this.deepDirY[k];
				if (!this.bOutOfBoundary(nearX, nearY)) {//是否超出边界
					let target = nearX + nearY * this.initWidth;
					if (this.map[nearX][nearY] == 0) { //为0的时候才考虑要不要加入
						if (this.showRec[nearX][nearY] == 0) {//没有打开的,实际上深度情况下可以不考虑这部分
							if (this.shows.indexOf(target) == -1) {//没有遍历过
								if (this.deepOpen.indexOf(target) == -1) {//没有在队列中
									this.deepOpen.push(target);
								}
							}
						}
					}
				}
			}
		}
	}
	/**
	 * 根据创建好的雷图,计算每个格子的数值
	 */
	public calcMapnum() {
		for (let boom of this.booms) {
			let bx = Math.floor(boom / this.initWidth);
			let by = Math.floor(boom % this.initWidth);
			if (this.map[bx][by] == -1) {//-1代表雷
				//如果有雷,则旁边8个非雷的格子个数都加1
				for (let k = 0; k < this.dirx.length; k++) {
					let nearX = bx + this.dirx[k];
					let nearY = by + this.diry[k];
					if (!this.bOutOfBoundary(nearX, nearY)) {//是否超出边界
						if (this.map[nearX][nearY] != -1) {
							this.map[nearX][nearY]++;
						}
					}
				}
			}
		}
	}
	/**
	 * 是否超出边界
	 */
	private bOutOfBoundary(x, y) {
		if (x >= 0 && x < this.initHeight && y >= 0 && y < this.initWidth) {
			return false;
		}
		return true;
	}

	/**
	 * 获取随机数值
	 */
	private getRandom(start, end, limit, num) {
		//获取随机数源
		let data = [];
		for (let i = start; i < end; i++) {
			if (i != limit && num > 0) {
				data.push(i);
			}
		}
		let DataLen = data.length
		let target = [];
		for (let i = 0; i < num; i++) {
			let randomInd = Math.floor(Math.random() * DataLen);
			let temp = data[randomInd];
			data[randomInd] = data[DataLen - 1];
			target.push(temp);
			DataLen--;
		}
		return target;
	}

}

说明1:只是写了游戏逻辑代码,没有写界面,具体的可以根据map的状态去实现界面逻辑,为什么要这样?懒~
说明2:重申没有做标识方面的工作,如果要实现,实际上就维护另一个标识矩阵,然后再click里面判定这个格子的状态,再实现对应的逻辑就好,为什么不顺便写了?懒~
说明3:代码未必正确,review代码的时候发现有不合逻辑的时候,会更新一遍,如果发现说这玩意怎么写得这么渣渣,有各种问题的时候,别急,别慌,看下是不是最新的代码,是的话。。。那也莫得法子~建议下方留言通知改正,感谢大佬!
说明4:仅做了简单测试,实际发现有什么bug的话,可探讨解决,不负责维护~(卒)

你可能感兴趣的:(小玩意,egret)