原文地址:原生 Javascript 编写五子棋

博客地址:http://www.extlight.com

一、背景

近一个月没写 Javascript 代码,有点生疏。正好浏览网页时弹出五子棋的游戏广告,于是想通过编写这个小游戏练练手。

二、简单介绍

2.1 效果展示

2.2 实现思路

  1. 棋盘:通过图片(chessboard.png)和 div 标签渲染出棋盘。

  2. 棋子:通过图片(black_flag.png、white_flag.png等)渲染出黑白棋子。落子前,鼠标出会出现一个可以随鼠标移动的棋子。我们创建一个浮动的 div,动态设置其 top 和 left 。

  3. 落子:给容器(class="container")添加 click 事件,给其添加对应的 classname。即被点击的单元格设置棋子背景图片。此外,需要判断落子点是否存在棋子。

  4. 输赢:使用二维数组保存棋盘(棋子)状态,通过横向、纵向、左上到右下和右上到左下四个方向进行判断是否有 5 个以上连续同颜色(样式)的棋子。

2.3 涉及技术

DOM操作、面向对象、事件操作和间隔函数 setInterval

2.4 项目结构

三、实现步骤

3.1 绘制棋盘

style.css 内容:

html,body {
padding: 0;
margin: 0;
} .container {
position: relative;
width: 540px;
height: 540px;
margin: 10px auto;
padding-top: 7px;
padding-left: 7px;
background: url("../images/chessboard.png") no-repeat;
cursor: pointer;
} .none {
position: absolute;
width: 36px;
height: 36px;
box-sizing: border-box;
/*border: 1px solid #fff;*/
} .black_flag {
position: absolute;
width: 36px;
height: 36px;
background: url("../images/black_flag.png") no-repeat;
} .black_flag_cur {
position: absolute;
background: url("../images/black_flag_cur.png") no-repeat;
/*设置点击无效*/
pointer-events: none;
} .white_flag {
position: absolute;
width: 36px;
height: 36px;
background: url("../images/white_flag.png") no-repeat;
} .white_flag_cur {
position: absolute;
background: url("../images/white_flag_cur.png") no-repeat;
/*设置点击无效*/
pointer-events: none;
}

chessboard.js 代码:

var Chessboard = function() {
// 保存棋盘棋子状态
this.flagArr = [];
this.size = 36;
} // 初始化棋盘
Chessboard.prototype.init = function() {
var container = document.getElementById("container"); for (var i = 0; i < 15; i++) {
var arr = [];
for (var j = 0; j < 15; j++) {
var div = document.createElement("div");
div.className = "none";
div.style.top = (i * this.size) + "px";
div.style.left = (j * this.size) + "px";
container.appendChild(div);
arr.push(div);
}
this.flagArr.push(arr);
} }

game.js 代码:

var Game = function() {

}

Game.prototype.start = function() {
var chessboard = new Chessboard();
chessboard.init();
}

最终效果如下:

为了方便查看 div 与棋盘图片中格子之间的对应关系,笔者将 div 边框设置成白色。

从图中我们可以看到,div 大小正好对应棋盘的落子点。我们将 div 背景设置成棋子图片就实现了落子操作。

3.2 绘制棋子

chessboard.js 代码:

var Chessboard = function() {
// 保存棋盘棋子状态
this.flagArr = [];
this.size = 36; // 默认黑色为先手
this.currentFlag = true; // 保存落子前的样式映射
this.flagCurMap = [];
// 黑子
this.flagCurMap[true] = "black_flag_cur";
// 白子
this.flagCurMap[false] = "white_flag_cur";
} // 初始化棋盘
Chessboard.prototype.init = function() {
var container = document.getElementById("container"); for (var i = 0; i < 15; i++) {
var arr = [];
for (var j = 0; j < 15; j++) {
var div = document.createElement("div");
div.className = "none";
div.style.top = (i * this.size) + "px";
div.style.left = (j * this.size) + "px";
container.appendChild(div);
arr.push(div);
}
this.flagArr.push(arr);
} // 添加事件监听器
this.addListener(container);
} // 落子事件监听器
Chessboard.prototype.addListener = function() {
var that = this; // 设置落子前的鼠标样式
var mouse = document.createElement("div");
mouse.id = "mouse";
mouse.style.width = mouse.style.height = 36 + "px";
document.body.appendChild(mouse);
document.body.onmousemove = function(event) {
mouse.className = that.flagCurMap[that.currentFlag];
var x = event.clientX - 16;
var y = event.clientY - 16;
mouse.style.top = y + "px";
mouse.style.left = x + "px";
}
}

结果如下图:

3.3 落子

在 chessboard.js 的监听器方法中添加落子的点击事件:

var Chessboard = function() {
// 保存棋盘棋子状态
this.flagArr = [];
this.size = 36; // 默认黑色为先手
this.currentFlag = true; // 保存落子前的样式映射
this.flagCurMap = [];
// 黑子
this.flagCurMap[true] = "black_flag_cur";
// 白子
this.flagCurMap[false] = "white_flag_cur"; // 保存落子后的样式映射
this.flagMap = [];
// 黑子
this.flagMap[true] = "black_flag";
// 白子
this.flagMap[false] = "white_flag"; // 保存结果映射关系
this.resultMap = [];
this.resultMap[true] = "黑子胜利";
this.resultMap[false] = "白子胜利";
} // 初始化棋盘
Chessboard.prototype.init = function() {
var container = document.getElementById("container"); for (var i = 0; i < 15; i++) {
var arr = [];
for (var j = 0; j < 15; j++) {
var div = document.createElement("div");
div.className = "none";
div.style.top = (i * this.size) + "px";
div.style.left = (j * this.size) + "px";
container.appendChild(div);
arr.push(div);
}
this.flagArr.push(arr);
} // 添加事件监听器
this.addListener(container);
} // 落子事件监听器
Chessboard.prototype.addListener = function(container) {
var that = this; // 设置落子前的鼠标样式
var mouse = document.createElement("div");
mouse.id = "mouse";
mouse.style.width = mouse.style.height = 36 + "px";
document.body.appendChild(mouse);
document.body.onmousemove = function(event) {
mouse.className = that.flagCurMap[that.currentFlag];
var x = event.clientX - 16;
var y = event.clientY - 16;
mouse.style.top = y + "px";
mouse.style.left = x + "px";
} // 落子监听
container.onclick = function(event) {
// 判断落子点是否存在棋子
if (event.target.className != "none") {
alert("此处不能落子!");
return;
} // 落子,设置棋子图片
event.target.className = that.flagMap[that.currentFlag]; // 换棋手
that.currentFlag = !that.currentFlag;
}
}

运行结果如下:

3.4 判断输赢

在 chessboard.js 的落子监听实践代码中,判断是否五连子:

// 落子事件监听器
Chessboard.prototype.addListener = function(container) {
var that = this; // 设置落子前的鼠标样式
var mouse = document.createElement("div");
mouse.id = "mouse";
mouse.style.width = mouse.style.height = 36 + "px";
document.body.appendChild(mouse);
document.body.onmousemove = function(event) {
mouse.className = that.flagCurMap[that.currentFlag];
var x = event.clientX - 16;
var y = event.clientY - 16;
mouse.style.top = y + "px";
mouse.style.left = x + "px";
} // 落子监听
container.onclick = function(event) {
// 判断落子点是否存在棋子
if (event.target.className != "none") {
alert("此处不能落子!");
return;
} // 落子,设置棋子图片
event.target.className = that.flagMap[that.currentFlag]; // 当前落子坐标
var x = Math.floor(event.target.offsetLeft / that.size);
var y = Math.floor(event.target.offsetTop / that.size); // 判断是否胜利
if (that._checkSuccess(x, y)) {
document.getElementById("mouse").style.display = "none";
container.onclick = null;
document.body.onmousemove = null;
alert(that.resultMap[that.currentFlag]);
return;
} // 换棋手
that.currentFlag = !that.currentFlag;
}
} // 判断棋局
Chessboard.prototype._checkSuccess = function(x, y) {
var result = false;
// 当前落子的样式/颜色
var className = this.flagArr[y][x].className; // 横向判断
var count = 0;
for (var i = 0; i < 15; i++) {
if (className == this.flagArr[y][i].className) {
count++;
if (count >= 5) {
return true;
}
} else {
count = 0;
}
} // 纵向判断
for (var j = 0; j < 15; j++) {
if (className == this.flagArr[j][x].className) {
count++;
if (count >= 5) {
return true;
}
} else {
count = 0;
}
} // 左上到右下判断
var a = y - x;
var index = 0;
if (a > 0) {
for (a; a < 15; a++) {
if (className == this.flagArr[a][index++].className) {
count++;
if (count >= 5) {
return true;
}
} else {
count = 0;
}
}
} else {
a = Math.abs(a);
for (a; a < 15; a++) {
if (className == this.flagArr[index++][a].className) {
count++;
if (count >= 5) {
return true;
}
} else {
count = 0;
}
}
} // 右上到左下判断
var b = 14 - y -x;
var index2 = 14;
if (b > 0) {
b = 14 - b;
index2 = 0;
for (b; b >= 0; b--) {
if (className == this.flagArr[index2++][b].className) {
count++;
if (count >= 5) {
return true;
}
} else {
count = 0;
}
}
} else {
b = Math.abs(b);
for (b; b < 15; b++) {
if (className == this.flagArr[index2--][b].className) {
count++;
if (count >= 5) {
return true;
}
} else {
count = 0;
}
}
} if (count >= 5) {
result = true;
} return result;
}

演示结果:

剩余的一些文本提示,倒计时就不在此处介绍。具体代码可以在下边提供的链接中下载。

四、源码下载

原生 Javascript 编写五子棋的更多相关文章

  1. canvas :原生javascript编写动态时钟

    canvas :原生javascript编写动态时钟     此时针是以画布的中心为圆心: g.translate(width/2,width/2); 此函数是将画布的原点移到(width/2,wid ...

  2. 原生javascript模仿win8等待进度条。

    一.序言 一直很中意win8等待提示圆圈进度条.win8刚出来那会,感觉好神奇!苦于当时没思路,没去研究.通过最近网上找找资料,终于给搞出来了!先上Demo,献丑了!预览请看:win8进度条. 二.简 ...

  3. 原生javascript写的侧栏跟随效果

    浏览网站时经常看到有的网站上,当一个页面很长的时候,设定侧栏内容会跟随滚动条滚动,我们把这种效果叫做“侧栏跟随滚动”.这种特效对提高网站浏览量.文章点击率.广告点击量都有一定效果. 侧栏跟随滚动的实现 ...

  4. 你可能不需要 jQuery!使用原生 JavaScript 进行开发

    很多的 JavaScript 开发人员,包括我在内,都很喜欢 jQuery.因为它的简单,因为它有很多丰富的插件可供使用,和其它优秀的工具一样,jQuery 让我们开发人员能够更轻松的开发网站和 We ...

  5. artDialog是一个基于javascript编写的对话框组件,它拥有精致的界面与友好的接口

    artDialog是一个基于javascript编写的对话框组件,它拥有精致的界面与友好的接口 自适应内容 artDialog的特殊UI框架能够适应内容变化,甚至连外部程序动态插入的内容它仍然能自适应 ...

  6. 四种常见的提示弹出框(success,warning,error,loading)原生JavaScript和jQuery分别实现

    原文:四种常见的提示弹出框(success,warning,error,loading)原生JavaScript和jQuery分别实现 虽然说现在官方的自带插件已经有很多了,但是有时候往往不能满足我们 ...

  7. JavaScript常用,继承,原生JavaScript实现classList

    原文链接:http://caibaojian.com/8-javascript-attention.html 基于 Class 的组件最佳实践(Class Based Components) 基于 C ...

  8. 原生 JavaScript 实现 state 状态管理系统

    原生 JavaScript 实现 state 状态管理系统 Build a state management system with vanilla JavaScript | CSS-Tricks 在 ...

  9. C#构造方法(函数) C#方法重载 C#字段和属性 MUI实现上拉加载和下拉刷新 SVN常用功能介绍(二) SVN常用功能介绍(一) ASP.NET常用内置对象之——Server sql server——子查询 C#接口 字符串的本质 AJAX原生JavaScript写法

    C#构造方法(函数)   一.概括 1.通常创建一个对象的方法如图: 通过  Student tom = new Student(); 创建tom对象,这种创建实例的形式被称为构造方法. 简述:用来初 ...

随机推荐

  1. JS判断键盘上的上下左右键

    document.onkeydown=function(event){ var e = event || window.event || arguments.callee.caller.argumen ...

  2. 【Error】2003 - Can't connect to MySQL server on 'localhost' (10038)

    此错误主要是连接MySQL地址的地址搞错了. 可以看下 MySQL 的配置文件 /etc/mysql/my.cnf, 其中绑定的本地地址如下: bind-address=127.0.0.1 将其注释掉 ...

  3. UML类图几种关系

    (转自:http://www.open-open.com/lib/view/open1328059700311.html) 在UML类图中,常见的有以下几种关系: 泛化(Generalization) ...

  4. 使用aidl的项目结构以及小的注意事项

    在app的build.gradle里面添加: sourceSets{ main{ java.srcDirs = ['src/main/java','src/main/aidl'] } }

  5. Java线程的五种状态详解

    状态转换图 1.new状态:通过new关键字创建了Thread或其子类的对象 2.Runnable状态:即就绪状态.可从三种状态到达,new状态的Thread对象调用start()方法,Running ...

  6. 职责链模式(Chain of Responsibility)

    一.责任链模式介绍 责任链模式:将能够处理同一类请求的对象连成一条链,使这些对象都有机会处理请求,所提交的请求沿着链传递.从而避免请求的 发送者和接受者之间的耦合关系.链上的对象逐个判断是否有能力处理 ...

  7. fidder设置断点,修改请求参数等

    设置断点(来自:http://jingyan.baidu.com/article/17bd8e52216c8d85ab2bb8e9.html): 可以看到当前有一个抓取的很多的包的链接的地址的信息,那 ...

  8. JDBC的步骤

    使用jdbc步骤 a.导入数据库厂商提供的驱动程序(导入jar包) b.加载驱动程序 Class.forName("驱动程序类") c.获得连接 Connection conn=D ...

  9. SpreadJS 在 Angular2 中支持哪些事件?

    SpreadJS 纯前端表格控件是基于 HTML5 的 JavaScript 电子表格和网格功能控件,提供了完备的公式引擎.排序.过滤.输入控件.数据可视化.Excel 导入/导出等功能,适用于 .N ...

  10. C# OPC UA服务器 OPC UA网关 三菱 西门子 欧姆龙 Modbus转OPC UA 服务器 可配置的OPC UA服务器网关 HslSharp软件文档

    前言 本文将使用一个基于开源项目HslCommunication创建的OPC UA网关,方便通过配置创建一个OPC UA的网关中心.具体的操作及支持的设备信息项目参照下面: 开源项目HslCommun ...