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的话,可探讨解决,不负责维护~(卒)

已标记关键词 清除标记
课程简介: 历经半个多月的时间,Debug亲自撸的 “企业员工角色权限管理平台” 终于完成了。正如字面意思,本课程讲解的是一个真正意义上的、企业级的项目实战,主要介绍了企业级应用系统中后端应用权限的管理,其中主要涵盖了六大核心业务模块、十几张数据库表。 其中的核心业务模块主要包括用户模块、部门模块、岗位模块、角色模块、菜单模块和系统日志模块;与此同时,Debug还亲自撸了额外的附属模块,包括字典管理模块、商品分类模块以及考勤管理模块等等,主要是为了更好地巩固相应的技术栈以及企业应用系统业务模块的开发流程! 核心技术栈列表: 值得介绍的是,本课程在技术栈层面涵盖了前端和后端的大部分常用技术,包括Spring Boot、Spring MVC、Mybatis、Mybatis-Plus、Shiro(身份认证与资源授权跟会话等等)、Spring AOP、防止XSS攻击、防止SQL注入攻击、过滤器Filter、验证码Kaptcha、热部署插件Devtools、POI、Vue、LayUI、ElementUI、JQuery、HTML、Bootstrap、Freemarker、一键打包部署运行工具Wagon等等,如下图所示: 课程内容与收益: 总的来说,本课程是一门具有很强实践性质的“项目实战”课程,即“企业应用员工角色权限管理平台”,主要介绍了当前企业级应用系统中员工、部门、岗位、角色、权限、菜单以及其他实体模块的管理;其中,还重点讲解了如何基于Shiro的资源授权实现员工-角色-操作权限、员工-角色-数据权限的管理;在课程的最后,还介绍了如何实现一键打包上传部署运行项目等等。如下图所示为本权限管理平台的数据库设计图: 以下为项目整体的运行效果截图: 值得一提的是,在本课程中,Debug也向各位小伙伴介绍了如何在企业级应用系统业务模块的开发中,前端到后端再到数据库,最后再到服务器的上线部署运行等流程,如下图所示:
©️2020 CSDN 皮肤主题: Age of Ai 设计师:meimeiellie 返回首页