servlet实现网页版的猜数字_前端经典练手项目用 JavaScript 实现网页版扫雷

相信大家都玩过扫雷这个经典的小游戏,它规则简单但耐玩。你有没有想过自己动手开发一个呢?今天我们就教你做一个网页版的扫雷,先上一张效果截图:

f9ff06afe33e8b747be21fc13c52b828.gif

知识点

  • javascript

  • css3

  • 扫雷原理

实验原理

在开始开发之前,我们先来设计一下游戏算法。

扫雷游戏的规则很简单:

游戏面板上有一些格子,每个格子中有一个数字(空白表示数字为 0)或是地雷,格子中的数字表示格子周围格子中地雷的数量。玩家要做的就是把数字格子找出来,时间花的越少越好。

除边界上的格子外,每个格子周围有 8 个格子:上、下、左、右、4 个斜角。所以数字范围是 0~8。

所以我们的算法如下:

根据用户选择的难易程度(有初、中、高三个级别,级别越高地雷和格子数量越多),随机产生一定个数的地雷并随机放在格子中。然后遍历格子,计算每个格子中的数字,标记在格子上。玩家左键点击格子时显示格子内容(如果遇到地雷则挑战失败,游戏结束),右键点击格子时标记格子为地雷,真到正确标记所有地雷并打开所有非地雷格子,挑战成功,游戏结束。

小技巧:由于格子中数字范围是 0~8,所以为了便于计算,我们可以把地雷所在的格子中的数字记为 9。

代码获取

$ git clone https://github.com/shiyanlou/js-minesweeper

先建立下面的目录结构:

minesweeper

|__index.html

|__index.css

|__index.js

|__jms.js

然后我们需要在项目目录中放入实验要用到的地雷和旗帜的图片, 通过下面的命令下载图片:

$ wget http://labfile.oss.aliyuncs.com/courses/144/mine.png

$ wget http://labfile.oss.aliyuncs.com/courses/144/flag.png

实验步骤

下面将从页面布局开始,一步一步完成所有代码的编写。

页面布局

首先我们需要有一个面板来显示游戏信息,包括剩余地雷个数、所用时间、难度级别等。因为格子数量不是固定的,所以我们先不画格子,放在 JS 代码中绘制。

创建 index.html 文件

添加如下代码并保存:

charset="utf-8" />

JavaScript版扫雷

rel="stylesheet" type="text/css" href="index.css"/>

id="JMS_main" class="main">

id="landmine">

id="operation">

class="tip">剩余雷数: class="light red" id="landMineCount">0 个

class="tip">持续时间: class="light f60" id="costTime">0 秒

难度选择:

type="radio" name="level" id="llevel" checked="checked" value="10" /> for="llevel">初级(10*10) />

type="radio" name="level" id="mlevel" value="15" /> for="mlevel">中级(15*15) />

type="radio" name="level" id="hlevel" value="20" /> for="hlevel">高级(20*20) />

type="button" id="begin" value="开始游戏" /> />

class="tip txtleft">提示:

1、点击“开始游戏”游戏开始计时

2、游戏过程中点击“开始游戏”将开始新游戏

页面布局样式

然后需要调整面板上游戏信息的位置,添加一些样式,在 index.css 中添加如下代码并保存:

.main {

margin:10px auto;

padding:20px;

background:#EEE;

width:600px;

zoom:1;

}

.main table {

background:#CCC;

float:left;

}

.main table td {

border:2px outset #EEE;

font-size:20px;

width:32px;

height:32px;

text-align:center;

cursor:pointer;

}

.main table td:hover {

background-color:#AAA;

}

.main #operation {

width:180px;

float:right;

text-align:center;

}

.landMine {

background-image:url(mine.png);

background-position:center;

background-repeat:no-repeat;

}

.main table td.normal {

border:2px solid #EEE;

background-color:#AAA;

}

.main table td.normal:hover {

background-color:#AAA;

}

.flag {

background-image:url(flag.png);

background-position:center;

background-repeat:no-repeat;

}

.main:after {

clear: both;

display: block;

content: "";

line-height: 0;

height: 0;

visibility:hidden;

}

.main .tip {

font-size:14px;

margin:5px;

}

.main .tip ul {

}

.main .tip ul li {

margin:5px 0;

line-height:20px;

}

.main .light{

font-size:30px;

}

.main .red {

color:red;

}

.main .f60 {

color:#F60;

}

.main input[type=button] {

padding:2px 10px;

margin:5px;

font-size:20px;

cursor:pointer;

}

.main .txtleft {

text-align:left;

}

.main input[type='radio'],

.main fieldset label {

cursor:pointer;

}

.main fieldset {

margin:10px 0;

line-height:25px;

}

完成这步后,在 Preview 或 Mini Browser 中打开 index.html,效果如下:

cc930ebcf1accfe4ef723fa670ddcf30.png

左边空白处用于显示格子。

绘制格子

完成上面的步骤后,下面就要画格子了,为了让代码更清晰,我们把游戏实现部分和调用部分分开,游戏实现部分放在跟 index.html 同目录下的 jms.js 中,游戏调用部分放在同目录下的 index.js 中。

画格子需要传入一些参数,如放格子的表格的 id,格子的数量(用行数和列数表示)。另外,游戏的其他数据也要进行初始化。

//在jms.js中

(function () {

// 初始化扫雷对象,初始化数据

var JMS = function (id,rowCount,colCount, minLandMineCount, maxLandMineCount) {

if (!(this instanceof JMS))

return new JMS(id, rowCount, colCount, minLandMineCount, maxLandMineCount);

this.doc = document;

this.table = this.doc.getElementById(id);//画格子的表格

this.cells = this.table.getElementsByTagName("td");//小格子

this.rowCount = rowCount || 10;//格子行数

this.colCount = colCount || 10;//格子列数

this.landMineCount = 0;//地雷个数

this.markLandMineCount = 0;//标记的地雷个数

this.minLandMineCount = minLandMineCount || 10;//地雷最少个数

this.maxLandMineCount = maxLandMineCount || 20;//地雷最多个数

this.arrs = [];//格子对应的数组

this.beginTime = null;//游戏开始时间

this.endTime = null;//游戏结束时间

this.currentSetpCount = 0;//当前走的步数

this.endCallBack = null;//游戏结束时的回调函数

this.landMineCallBack = null;//标记为地雷时更新剩余地雷个数的回调函数

this.doc.oncontextmenu = function () {//禁用右键菜单

return false;

};

this.drawMap();

};

// 在 JMS 的原型中创建格子

JMS.prototype = {

//画格子

drawMap: function () {

var tds = [];

// 为了兼容浏览器

if (window.ActiveXObject && parseInt(navigator.userAgent.match(/msie ([\d.]+)/i)[1]) < 8) {

// 创建引入新的 css 样式文件

var css = '#JMS_main table td{background-color:#888;}',

// 获取 head 标签

head = this.doc.getElementsByTagName("head")[0],

// 创建 style 标签

style = this.doc.createElement("style");

style.type = "text/css";

if (style.styleSheet) {

// 将 css 样式赋给 style 标签

style.styleSheet.cssText = css;

} else {

// 在 style 标签中创建节点

style.appendChild(this.doc.createTextNode(css));

}

// 再将 style 标签创建为 head 标签的子标签

head.appendChild(style);

}

// 循环创建表格

for (var i = 0; i < this.rowCount; i++) {

tds.push("");

for (var j = 0; j < this.colCount; j++) {

tds.push("");

}

tds.push("

");

}

this.setTableInnerHTML(this.table, tds.join(""));

},

//添加HTML到Table

setTableInnerHTML: function (table, html) {

if (navigator && navigator.userAgent.match(/msie/i)) {

// 在 table 的 owner document 内创建 div

var temp = table.ownerDocument.createElement('div');

// 创建表格的 tbody 内容

temp.innerHTML = '

' + html + '';

if (table.tBodies.length == 0) {

var tbody = document.createElement("tbody");

table.appendChild(tbody);

}

table.replaceChild(temp.firstChild.firstChild, table.tBodies[0]);

} else {

table.innerHTML = html;

}

}

};

window.JMS = JMS;

})();

上面的代码中,部分代码是为了兼容 IE 浏览器,可忽略。

在 index.js 的调用代码中,我们需要绑定难度选择按钮的事件,然后调用上面定义的 JMS,开始绘制格子。

index.js 中添加如下代码并保存:

//在index.js中

var jms = null,

timeHandle = null;

window.onload = function () {

var radios = document.getElementsByName("level");

for (var i = 0, j = radios.length; i < j; i++) {

radios[i].onclick = function () {

if (jms != null)

if (jms.landMineCount > 0)

if (!confirm("确定结束当前游戏?"))

return false;

var value = this.value;

init(value, value, value * value / 5 - value, value * value / 5);

document.getElementById("JMS_main").style.width = value * 40 + 180 + 60 + "px";

}

}

init(10, 10);

};

function init(rowCount, colCount, minLandMineCount, maxLandMineCount) {

var doc = document,

landMineCountElement = doc.getElementById("landMineCount"),

timeShow = doc.getElementById("costTime"),

beginButton = doc.getElementById("begin");

if (jms != null) {

clearInterval(timeHandle);

timeShow.innerHTML = 0;

landMineCountElement.innerHTML = 0;

}

jms = JMS("landmine", rowCount, colCount, minLandMineCount, maxLandMineCount);

}

然后在浏览器中打开 index.html,格子已经可以显示出来了,效果如下:

13fa1ed10b730cdfd03e4fe5beedae01.png

点击右边的难度选择,可以看到格子的数量变化。

游戏初始化

现在,我们开始对游戏初始化,主要分三步:
  1. 把所有格子(代码中用一个数组表示)初始化为 0

  2. 随机生成地雷个数,把地雷随机放到数组中,数组项值设置为 9

  3. 计算其他格子中的数字,值放入数组中

在 jms.js 中 JMS.prototype 内加入如下代码:

//在jms.js中JMS.prototype内加入

//初始化,一是设置数组默认值为0,二是确定地雷个数

init: function () {

for (var i = 0; i < this.rowCount; i++) {

this.arrs[i] = [];

for (var j = 0; j < this.colCount; j++) {

this.arrs[i][j] = 0;

}

}

this.landMineCount = this.selectFrom(this.minLandMineCount, this.maxLandMineCount);

this.markLandMineCount = 0;

this.beginTime = null;

this.endTime = null;

this.currentSetpCount = 0;

},

//把是地雷的数组项的值设置为9

landMine: function () {

var allCount = this.rowCount * this.colCount - 1,

tempArr = {};

for (var i = 0; i < this.landMineCount; i++) {

var randomNum = this.selectFrom(0, allCount),

rowCol = this.getRowCol(randomNum);

if (randomNum in tempArr) {

i--;

continue;

}

this.arrs[rowCol.row][rowCol.col] = 9;

tempArr[randomNum] = randomNum;

}

},

//计算其他格子中的数字

calculateNoLandMineCount: function () {

for (var i = 0; i < this.rowCount; i++) {

for (var j = 0; j < this.colCount; j++) {

if (this.arrs[i][j] == 9)

continue;

if (i > 0 && j > 0) {

if (this.arrs[i - 1][j - 1] == 9)

this.arrs[i][j]++;

}

if (i > 0) {

if (this.arrs[i - 1][j] == 9)

this.arrs[i][j]++;

}

if (i > 0 && j < this.colCount - 1) {

if (this.arrs[i - 1][j + 1] == 9)

this.arrs[i][j]++;

}

if (j > 0) {

if (this.arrs[i][j - 1] == 9)

this.arrs[i][j]++;

}

if (j < this.colCount - 1) {

if (this.arrs[i][j + 1] == 9)

this.arrs[i][j]++;

}

if (i < this.rowCount - 1 && j > 0) {

if (this.arrs[i + 1][j - 1] == 9)

this.arrs[i][j]++;

}

if (i < this.rowCount - 1) {

if (this.arrs[i + 1][j] == 9)

this.arrs[i][j]++;

}

if (i < this.rowCount - 1 && j < this.colCount - 1) {

if (this.arrs[i + 1][j + 1] == 9)

this.arrs[i][j]++;

}

}

}

},

//获取一个随机数

selectFrom: function (iFirstValue, iLastValue) {

var iChoices = iLastValue - iFirstValue + 1;

return Math.floor(Math.random() * iChoices + iFirstValue);

},

//通过数值找到行数和列数

getRowCol: function (val) {

return {

row: parseInt(val / this.colCount),

col: val % this.colCount

};

},

给格子添加点击事件

现在,该给格子添加点击事件了,当左键点击时,显示出格子中的数字(如果是地雷就挑战失败,结束游戏),右键点击时标记为地雷。另外,第一次点击格子(往往带有运气成分)如果周围有空白区域会直接展开。 我们还为你准备了在线的实验环境,点击一下即可开始体验这个项目。学编程,当然要边练边学了~ PC 端登陆,开始学习之旅 https://www.shiyanlou.com/courses/144 935870e6a92ae2030a20e2c24f719035.png 74a86e10ee6d40fbae5ce0d4c41d61a1.png
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值