HTML5下的扫雷游戏与自动扫雷算法

今年人工智能课的作业加了点料,一共三个题:五子棋对弈,自动扫雷,Wumpus怪兽世界游戏。今天这篇文章就来讲讲如何基于HTML5实现一个扫雷游戏,以及自动扫雷算法(在无法读取内存内布雷情况下)。

先甩DEMO: http://app.ichen.pw/Mine-Sweeping-HTML5-/index.html

github: https://github.com/Hurricane-Chen/Mine-Sweeping-HTML5-


界面设计:Canvas

扫雷界面是用Canvas写的。什么是Canvas?它是HTML5中支持的一个元素,通过JavaScript,我们可以给Canvas元素绘制不同的图案。我们可以给Canvas画上线段、图形……画个简单的扫雷界面不在话下。

通过如下HTML语句添加一个Canvas元素。

 <canvas id="board" width="200" height="100"></canvas>

我们要绘制一个10*10的扫雷棋盘。棋盘本质上是水平和垂直上纵横交错的各11条线构成的。我们只要用JavaScript操纵画笔绘制线段即可。

var ctx = this.ctx;
ctx.clearRect(0, 0, 620, 620);
for (var i = 0; i <= this.board_width; i++) {
    ctx.beginPath();
    ctx.moveTo(30, 30 + this.a_w * i);
    ctx.lineTo(590, 30 + this.a_w * i);
    ctx.moveTo(30 + this.a_w * i, 30);
    ctx.lineTo(30 + this.a_w * i, 590);
    ctx.lineWidth = 1;
    ctx.strokeStyle = "#000";
    ctx.stroke();
}

代码里采用了面向对象的方法,this.a_w是宽度,this.ctx对应的是

var c = document.getElementById("baord");
this.ctx = c.getContext("2d");

为了省事,用户标记为有雷的方格标为红色。用户点开的方格标记为淡粉色,同时如果它的四周有雷的话记上地雷个数。

给某个方格打上数字:

ctx.font="20px Georgia";
ctx.fillStyle = "#000";
ctx.fillText(number.toString(), 60 + i * this.a_w, 60 + j * this.a_w);

将某个方格标记为红色

ctx.fillStyle = "#FF4500";
ctx.fillRect(30 + i * this.a_w, 30 + j * this.a_w, this.a_w, this.a_w);
ctx.stroke();

其实感觉Canvas的操作就像画画一样,还是非常简单的。


用户交互功能

扫雷大家都玩过,左键点击打开方格,右键标记地雷。大部分浏览器里面点击右键打开菜单,我们首先禁用右键:

document.body.onselectstart=document.body.oncontextmenu=function(){ return false;}

绑定鼠标点击事件,同时需要计算出每次点击发生在页面的哪个位置:

self = this;
this.dom.onclick = function(e) {
    var _x = e.pageX - domLeft - 30,_y = e.pageY - domTop - 30;
    var i = Math.floor(_x / self.a_w), j = Math.floor(_y / self.a_w);
    console.log(i, j);
    self.open(i, j);
}

右击事件需要绑定的是this.dom.oncontextmenu。

游戏开始前我们还需要初始化一个10*10数组,并随机赋予地雷位置。


自动扫雷

假定机器并不知道实际地雷的位置,它能不能根据当前情况成功扫雷?

这是肯定的。细心的同学们会发现扫雷是一件及其有规律的事情:标记出附近地雷个数的方格,根据它的数字可以推断出附近是否存在地雷。机器根据逻辑推理即可得出地雷位置。即便无法推断,也可以根据数字选取不是地雷概率较大的位置。当然,也有一定概率扫雷失败。实际游戏通过单步扫雷让玩家一步步看到机器推断的过程,机器扫描当前棋盘上可能不存在地雷的位置并打开。

戳网页上的“单步扫雷”按钮,计算机扫描所有已打开的方格。方格标记的数字和它周边未打开的方格做比对就能很容易推出哪个未打开方格是有雷还是无雷的。每次点击扫描一次并打开对应方格。