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的話,可探討解決,不負責維護~(卒)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章