摘要:废话不多说上代码完整项目地址项目地址棋盘样式棋盘元素初始化初始化角色黑旗子白旗是否已分出胜负走棋记录当前步清空棋子和事件初始化棋盘矩阵刻画棋盘棋盘网格刻画棋子每次落子结束都要判断输赢落子如果点击的是棋子则中断空的棋位才可落子落
废话不多说上代码!
完整项目地址:GitHub项目地址
class Gobang {
constructor(options) {
this.options = options
this.gobang = document.getElementById(options.canvas || "gobang")
this.chessboard = this.gobang.children[0]
this.chessmans = this.gobang.children[1]
// 棋盘样式
this.gobangStyle = Object.assign({
padding: 30,
count: 15
}, options.gobangStyle || {})
// 棋盘元素
this.lattice = {
width: (this.gobang.clientWidth - this.gobangStyle.padding * 2) / this.gobangStyle.count,
height: (this.gobang.clientHeight - this.gobangStyle.padding * 2) / this.gobangStyle.count
}
// 初始化
this.resetAndInit()
}
// 初始化
resetAndInit() {
const {options} = this
// 角色 => 1黑旗子 2白旗
this.role = options.role || this.role || 1
// 是否已分出胜负
this.win = false
// 走棋记录
this.history = []
// 当前步
this.currentStep = 0
// 清空棋子和事件
this.chessmans.onclick = null
this.chessmans.innerHTML = ""
// 初始化
this.drawChessboard()
this.listenDownChessman()
this.initChessboardMatrix()
}
// 棋盘矩阵
initChessboardMatrix() {
const checkerboard = []
for(let x = 0; x < this.gobangStyle.count + 1; x++) {
checkerboard[x] = []
for(let y = 0; y < this.gobangStyle.count + 1; y++) {
checkerboard[x][y] = 0
}
}
this.checkerboard = checkerboard
}
// 刻画棋盘
drawChessboard() {
const {
gobangStyle,
gobang
} = this
// 棋盘网格
const lattices = Array.from({
length: gobangStyle.count * gobangStyle.count
}, () => ``).join("")
this.chessboard.className = `chessboard lattice-${gobangStyle.count}`
this.chessboard.innerHTML = lattices
this.gobang.style.border = `${gobangStyle.padding}px solid #ffffd`
}
// 刻画棋子
drawChessman(x, y, isBlack) {
const {
gobangStyle,
lattice,
gobang
} = this
const newChessman = document.createElement("div")
newChessman.setAttribute("id", `x${x}-y${y}-r${isBlack ? 1 : 2}`)
newChessman.className = isBlack ? "chessman black" : "chessman white"
newChessman.style.width = lattice.width * 0.6
newChessman.style.height = lattice.height * 0.6
newChessman.style.left = (x * lattice.width) - lattice.width * 0.3
newChessman.style.top = (y * lattice.height) - lattice.height * 0.3
this.chessmans.appendChild(newChessman)
// 每次落子结束都要判断输赢
setTimeout(() => {
this.checkReferee(x, y, isBlack ? 1 : 2)
}, 0)
}
// 落子
listenDownChessman(isBlack = false) {
this.chessmans.onclick = event => {
// 如果点击的是棋子则中断
if(event.target.className.includes("chessman ")) {
return false
}
let {
offsetX: x,
offsetY: y
} = event
x = Math.round(x / this.lattice.width)
y = Math.round(y / this.lattice.height)
// 空的棋位才可落子
if(this.checkerboard[x][y] !== undefined &&
Object.is(this.checkerboard[x][y], 0)) {
// 落子后,更新矩阵,切换角色,并记录
this.checkerboard[x][y] = this.role
this.drawChessman(x, y, Object.is(this.role, 1))
// 落子完毕后,有可能是悔棋之后落子的,这种情况下就该重置历史记录
this.history.length = this.currentStep
this.history.push({
x,
y,
role: this.role
})
// 保存坐标,角色,快照
this.currentStep++
this.role = Object.is(this.role, 1) ? 2 : 1
}
}
}
// 判断输赢
checkReferee(x, y, role) {
if((x == undefined) || (y == undefined) || (role == undefined)) return
// 连杀分数
let countContinuous = 0
// 所在矩阵数据
const XContinuous = this.checkerboard.map(x => x[y])
const YContinuous = this.checkerboard[x]
const S1Continuous = []
const S2Continuous = []
this.checkerboard.forEach((_y, i) => {
// 左斜线
const S1Item = _y[y - (x - i)]
// alert(S1Item)
if(S1Item !== undefined) {
S1Continuous.push(S1Item)
}
// 右斜线
const S2Item = _y[y + (x - i)]
if(S2Item !== undefined) {
S2Continuous.push(S2Item)
}
})
// 当前落棋点所在的X轴/Y轴/交叉斜轴,只要有能连起来的5个子的角色即有胜者
;
[XContinuous, YContinuous, S1Continuous, S2Continuous].forEach(axis => {
if(axis.some((x, i) => axis[i] !== 0 &&
axis[i - 2] === axis[i - 1] &&
axis[i - 1] === axis[i] &&
axis[i] === axis[i + 1] &&
axis[i + 1] === axis[i + 2])) {
countContinuous++
}
})
// 如果赢了,则解绑事件
if(countContinuous) {
this.chessmans.onclick = null
this.win = true
alert((role == 1 ? "黑" : "白") + "子胜")
}
}
// 悔棋
regretChess() {
// 找到最后一次的记录,回滚UI,更新矩阵
if(this.history.length && !this.win) {
const prev = this.history[this.currentStep - 1]
if(prev) {
const {
x,
y,
role
} = prev
const targetChessman = document.getElementById(`x${x}-y${y}-r${role}`)
targetChessman.parentNode.removeChild(targetChessman)
this.checkerboard[prev.x][prev.y] = 0
this.currentStep--
this.role = Object.is(this.role, 1) ? 2 : 1
}
}
}
// 撤销悔棋
revokedRegretChess() {
const next = this.history[this.currentStep]
if(next) {
this.drawChessman(next.x, next.y, next.role === 1)
this.checkerboard[next.x][next.y] = next.role
this.currentStep++
this.role = Object.is(this.role, 1) ? 2 : 1
}
}
}
// 实例化游戏
const gobangGame = new Gobang({
role: 2,
canvas: "game",
gobangStyle: {
padding: 30,
count: 16
}
})
console.log(gobangGame)
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/88325.html
摘要:这是我在一次面试中,被面试官所提问的一道题在这次面试题中相等指的是对象的属性个数值相等有这样两个李德华张德华我能想到的一种方案解答过程的思考由于没有,我只能通过转化成数组进入第二步,对象中的属性在另一个中是否存在。 这是我在一次面试中,被面试官所提问的一道题 在这次面试题中 相等:指的是对象的属性个数值相等 有这样两个obj let obj1 = { name:李德华, ...
摘要:前端日报精选专题之跟着学节流冴羽的博客全家桶仿微信项目,支持多人在线聊天和机器人聊天腾讯前端团队社区编码的奥秘模块实现入门浅析知乎专栏前端每周清单发布新版本提升应用性能的方法中文寇可往吾亦可往用实现对决支付宝的微信企业付款到零 2017-06-20 前端日报 精选 JavaScript专题之跟着 underscore 学节流 - 冴羽的JavaScript博客 - SegmentFau...
摘要:前言很认真的说吧,在和腾讯面试官的面试的过程。腾讯二面自我介绍二面的面试官和一面不是同一个面试官,所以在这个时候,我的基本介绍还是和一面一样,介绍自己的基本信息,以及怎么想到学习前端和怎么学习前端。 前言 很认真的说吧,在和腾讯面试官的面试的过程。有点感觉是在聊天一样,他们是面试官,但是感觉更像是引路人,不管结果的好坏,在腾讯面试的过程,只要你认真去听去问,就可以学到很多东西吧。 如果...
摘要:拥有两个版本,无依赖的独立版和版本。除了对象,也可监听内元素的手势需要引擎内置对象支持绑定相关事件。据不完全统计,目前服务于兴趣部落群动漫腾讯学院腾讯等多个部门团队和项目。也可以在事件回调里根据携带的信息使用去操作。 简介 针对多点触控设备编程的Web手势组件,快速帮助你的web程序增加手势支持,也不用再担心click 300ms的延迟了。拥有两个版本,无依赖的独立版和react版本。...
阅读 3445·2021-11-24 10:24
阅读 3356·2021-11-11 16:54
阅读 3403·2021-09-22 15:55
阅读 2328·2019-08-30 15:44
阅读 2187·2019-08-29 18:41
阅读 2991·2019-08-29 13:43
阅读 3331·2019-08-29 12:51
阅读 1584·2019-08-26 12:19