zoukankan      html  css  js  c++  java
  • 原生js扫雷代码

    思路要点:

    1. 随机地雷放到一个二维数组中;

    2. 每一个格子要统计周围有几颗雷;

    3. 每一个格子是否处于打开状态,用于判断是否赢得游戏;

    4. 如果点击到周围没有雷的地方,把周围的打开;

    具体的见代码

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="UTF-8">
    		<title></title>
    		<style>
    			*{padding: 0;margin: 0;}
    			canvas{margin: 0 auto;display: block;}
    			.btns{margin: 0 auto;text-align: center;padding: 10px 0;}
    		</style>
    	</head>
    	<body>
    		<canvas id="mineMap"></canvas>
    		<div class="btns">
    			<button id="playAgain">再来一局</button>
    		</div>
    		
    		<script src="mineClearance.js" type="text/javascript" charset="utf-8"></script>
    		<script type="text/javascript">
    			
    			var game = new MineClearance("mineMap", 15, 0.15);
    			var restart = document.getElementById("playAgain");
    			restart.onclick = function (){
    				game.resetData();
    			}
    		</script>
    	</body>
    </html>
    

      

    class MineClearance{
    	constructor(canvasId, rowCount, mineRate){
    		this.rowCount = rowCount || 10;
    		this.mineRate = mineRate || 0.1; // 地雷所占的百分比
    		this.canvasId = canvasId;
    		this.resetData();
    	}
    	
    	// 重置数据
    	resetData(){
    		this.mines = []; // 所有地雷的数组
    		this.mineCount = 0; // 地雷总数量,由地雷百分比算出
    		// this.mineRate = 0.15; // 地雷所占的百分比
    		this.minePositions = []; // 所有地雷的坐标
    		this.mineTip = []; // 地雷的提示数组
    		this.openStatus = []; // 所有位置的打开状态
    		this.mineFlag = [];
              this.gameOver = false; this.cellWidth = 0; this.initMines(); this.initCanvas(); } // 初始化canvas initCanvas(){ var width = document.documentElement.clientWidth ||document.body.clientWidth; var height = document.documentElement.clientHeight || document.body.clientHeight; var minWidth = Math.min(width, (height - 50)); this.cellWidth = Math.floor(minWidth / this.rowCount); this.canvas = document.getElementById(this.canvasId); this.ctx = this.canvas.getContext("2d"); this.canvas.width = this.cellWidth * this.rowCount; this.canvas.height = this.cellWidth * this.rowCount; this.ctx.fillStyle = "yellow"; this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); this.ctx.beginPath(); for(var i = 0; i <= this.rowCount; i ++){ this.ctx.moveTo(i * this.cellWidth, 0); this.ctx.lineTo(i * this.cellWidth, this.rowCount * this.cellWidth); } for(var i = 0; i <= this.rowCount; i ++){ this.ctx.moveTo(0, i * this.cellWidth); this.ctx.lineTo(this.rowCount * this.cellWidth, i * this.cellWidth); } this.ctx.strokeStyle = '#e73480'; this.ctx.stroke(); // this.ctx.closePath(); this.bindEvent(); } // 初始化地雷 initMines(){ this.mines = []; for(var i = 0; i < this.rowCount; i ++){ this.mines[i] = []; for(var j = 0; j < this.rowCount; j ++){ this.mines[i][j] = 0; } } // 随机地雷坐标 this.mineCount = parseInt(this.rowCount * this.rowCount * this.mineRate); var minePositions = []; console.time(); while(this.mineCount){ var x = parseInt(Math.random() * this.rowCount); var y = parseInt(Math.random() * this.rowCount); if(minePositions.indexOf(x + "," + y) == -1){ minePositions.push(x + "," + y); this.mineCount --; } } console.timeEnd(); this.minePositions = minePositions; // 地雷按号入座 for(var i = 0; i < this.minePositions.length; i ++){ var p = this.minePositions[i].split(","); this.mines[p[0]][p[1]] = 1; } console.log(this.mines); // 统计数组 var countArr = []; for(var i = 0; i < this.mines.length; i ++){ countArr[i] = []; for(var j = 0; j < this.mines[i].length; j ++){ var sum = 0; for(var ii = -1; ii <= 1; ii ++){ for(var jj = -1; jj <= 1; jj ++){ if(ii == 0 && jj == 0){ continue; } if(this.mines[i + ii] && this.mines[i + ii][j + jj]){ sum += this.mines[i + ii][j + jj]; } } } if(this.mines[i][j] == 1){ countArr[i][j] = 9; // 雷 此处用9代表地雷,反正周围有9个雷的话说明你必踩雷了,这里是为了数组输出时显示整齐 }else{ countArr[i][j] = sum; } } } this.mineTip = countArr; console.log(this.mineTip) // 每个格子的打开情况 for(var i = 0; i < this.rowCount; i ++){ this.openStatus[i] = []; for(var j = 0; j < this.rowCount; j ++){ this.openStatus[i][j] = false; } } // 标记数组(插旗情况) for(var i = 0; i < this.rowCount; i ++){ this.mineFlag[i] = []; for(var j = 0; j < this.rowCount; j ++){ this.mineFlag[i][j] = false; } } } // 绑定事件 bindEvent(){ var that = this; document.body.oncontextmenu = function (){ return false; } this.canvas.onmousedown = function(evt){ var e = evt || window.event; // console.log(this.getBoundingClientRect().left,e.clientX,that.cellWidth); // x,y与数组中的位置对应位置,请注意 var x = Math.floor((e.clientX - this.getBoundingClientRect().left) / that.cellWidth); var y = Math.floor((e.clientY - this.getBoundingClientRect().top) / that.cellWidth); console.log(x,y) if(e.which == 3){ // 1左键 2滚轮 3右键 // 插旗或取消插旗 that.changeFlag(x,y); }else if(e.which == 1){ // 打开格子 that.openCell(x, y); } } } // 画一个地雷 drawOneMine(x,y){ var xx = this.cellWidth * x; var yy = this.cellWidth * y; this.ctx.fillStyle = "#fff"; this.ctx.fillRect(xx, yy, this.cellWidth, this.cellWidth); // 写对应的数字 this.ctx.font = `${this.cellWidth*0.75}px 方正舒体`; // 隶书 方正舒体 this.ctx.fillStyle = "red"; this.ctx.textBaseline = "middle"; this.ctx.textAlign = "center"; this.ctx.fillText("雷", xx + this.cellWidth / 2, yy + this.cellWidth / 2); this.drawBorder(x,y); } // 画雷区标记 drawFlag(x, y){ var xx = this.cellWidth * x; var yy = this.cellWidth * y; this.ctx.fillStyle = "#fff"; this.ctx.fillRect(xx, yy, this.cellWidth, this.cellWidth); // 写对应的数字 this.ctx.font = `${this.cellWidth*0.75}px 方正舒体`; // 隶书 方正舒体 this.ctx.fillStyle = "blue"; this.ctx.textBaseline = "middle"; this.ctx.textAlign = "center"; this.ctx.fillText("旗", xx + this.cellWidth / 2, yy + this.cellWidth / 2); this.drawBorder(x,y); } // 取消雷区标记 cancelFlag(x, y){ var xx = this.cellWidth * x; var yy = this.cellWidth * y; this.ctx.fillStyle = "yellow"; this.ctx.fillRect(xx, yy, this.cellWidth, this.cellWidth); this.drawBorder(x,y); } // 插旗或取消插旗 changeFlag(x,y){ // 更改数据 if(this.mineFlag[x][y]){ console.log("取消插旗"); this.mineFlag[x][y] = false; this.openStatus[x][y] = false; this.cancelFlag(x, y);// 渲染canvas }else{ console.log("插旗"); this.mineFlag[x][y] = true; this.openStatus[x][y] = true; this.drawFlag(x, y);// 渲染canvas } } // 打开一个格子 openCell(x, y){ if(this.gameOver){ return; } if(!this.openStatus[x] || typeof this.openStatus[x][y] !== "boolean"){ return; } if(this.openStatus[x][y]){ console.warn("此位置已打开"); return; }else{ this.openStatus[x][y] = true; } var xx = this.cellWidth * x; var yy = this.cellWidth * y; // console.log(x,y,xx,yy) if(!this.mines[x][y]){ // 空位置 if(this.mineTip[x][y]){ // 有数字的位置 // this.ctx.clearRect(xx, yy, xx + this.cellWidth, yy + this.cellWidth); this.ctx.fillStyle = "#fff"; this.ctx.fillRect(xx, yy, this.cellWidth, this.cellWidth); // 写对应的数字 this.ctx.font = `${this.cellWidth*0.75}px 方正舒体`; // 隶书 方正舒体 this.ctx.fillStyle = "#e73480"; this.ctx.textBaseline = "middle"; this.ctx.textAlign = "center"; this.ctx.fillText(this.mineTip[x][y], xx + this.cellWidth / 2, yy + this.cellWidth / 2); this.drawBorder(x,y); this.isWin(); }else{ // 无数字的位置 console.log("周围无雷"); this.ctx.fillStyle = "#fff"; this.ctx.fillRect(xx, yy, this.cellWidth, this.cellWidth); this.drawBorder(x,y); // this.openCell(x - 1, y - 1); // 左上 this.openCell(x - 1, y); // 左 // this.openCell(x - 1, y + 1); // 左下 this.openCell(x, y - 1); // 上 this.openCell(x, y + 1); // 下 // this.openCell(x + 1, y - 1); // 右上 this.openCell(x + 1, y); // 右 // this.openCell(x + 1, y + 1); // 右下 } }else{ // 踩地雷了 console.log("gameOver"); this.gameOver = true; for(var i = 0, len = this.mines.length; i < len; i++){ for(var j = 0, jlen = this.mines[i].length; j < jlen; j++){ if(this.mines[i][j]){ this.drawOneMine(i,j); } } } this.toast("game over"); // alert("game over"); } } // 画一格格子的边框 drawBorder(x,y){ var xx = this.cellWidth * x; var yy = this.cellWidth * y; this.ctx.moveTo(xx, yy); this.ctx.lineTo(xx + this.cellWidth, yy); this.ctx.lineTo(xx + this.cellWidth, yy + this.cellWidth); this.ctx.lineTo(xx, yy + this.cellWidth); this.ctx.strokeStyle = "#e73480"; this.ctx.stroke(); } // 判断赢 isWin(){ var openCount = 0; this.openStatus.reduce(function (pre, cur){ cur.reduce(function(pre1,cur1){ if(cur1){ openCount ++; } },0); },0); // console.log(openCount); if(this.rowCount * this.rowCount - this.mineCount == openCount){ this.toast("恭喜过关"); } } toast(text){ setTimeout(function(){ alert(text); },30); } // 数组乱序 disorder(arr){ } }

      

  • 相关阅读:
    老陌与博客
    有关模式窗体和无(非)模式窗体的区别
    10月9日至10月22日备忘录
    9月4日至9月10日备忘录
    VS2015 远程调试:Remote Debugger
    8月28日至9月3日备忘录
    8月21日至8月27日技术积累
    用函数方法实现迭代器
    python中eval, exec, execfile,和compile(转载)
    dev 中的GridControl中的行实现选择的功能实现
  • 原文地址:https://www.cnblogs.com/zhaodesheng/p/10485050.html
Copyright © 2011-2022 走看看