5.1 井字棋游戏介绍
井字棋游戏在九宫方格内进行,如果一方首先沿某方向(横、竖、斜)连成 3 子,则获
取胜利。本游戏有人人对战和人机对战两种模式。游戏开始时从图 5-1(a)中选择对战模式,如
果是人人对战模式,两个玩家轮流下棋。如果是人机对战模式,游戏开始玩家(X 方)先走,
计算机(O 方)智能对弈下棋。游戏运行界面如图 5-1(b)所示。
图 5-1 井字棋游戏运行效果
5.2 程序设计的思路
5.2.1 计算机智能下棋
在游戏中,pos 数组存储玩家、计算机的落子信息,未落子处存储 0。X 方落子存储 1,
145
第 5 章 井字棋游戏
O 方落子存储 2。
由于人机对战,需要实现计算机的智能性,下面是为计算机设计的简单策略。
(1)如果有一步棋可以让计算机在本轮获胜,就选那一步。
(2)否则,如果有一步棋可以让玩家在本轮获胜,就选那一步。
(3)否则,计算机应该选择最佳空位置来走。最优位置就是中间那个,次优位置是四个
角,剩下的就都算第三优。
假设游戏中方格位置代号形式如图 5-2 所示。
0 1 2
3 4 5
6 7 8
图 5-2 方格位置
在程序中定义一个数组 BEST_MOVES 存储最佳方格位置,代码如下。
#按优劣顺序排序的下棋位置
var BEST_MOVES = [4, 0, 2, 6, 8, 1, 3, 5, 7];
按上述规则设计程序,就可以实现计算机的智能性。
5.2.2 井字棋输赢判断
井字棋输赢判断比较简单,这里横斜竖赢(即三颗同色的棋子排成一条直线)的情况只
有 8 种。通过遍历,就可以判断哪一方是否获胜。
//输赢判断
Iswin: function() {
//判定(纵)
for (var i = 0; i < 3; i++) {
if (pos[i][0] == pos[i][1] && pos[i][1] == pos[i][2] &&
pos[i][1] != 0)
return pos[i][1];
}
//判定(横)
for (var i = 0; i < 3; i++) {
if (pos[0][i] == pos[1][i] && pos[1][i] == pos[2][i] &&
pos[1][i] != 0)
return pos[1][i];
}
//判定(斜)
if (pos[0][0] == pos[1][1] && pos[1][1] == pos[2][2] &&
pos[1][1] != 0) {
return pos[1][1];
}
if (pos[0][2] == pos[1][1] && pos[1][1] == pos[2][0] &&
146
pos[1][1] != 0) {
return pos[1][1];
}
return 0;
},
5.3 关 键 技 术
5.3.1 画布 canvas
微信小程序画布 canvas 组件的属性如表 5-1 所示。
表 5-1 canvas 的属性
属 性 名 类 型 默 认 值 说 明
canvas-id String canvas 组件的唯一标识符
disable-scroll Boolean false
当在 canvas 中移动时且有绑定手势事件时,禁止屏幕
滚动以及下拉刷新
bindtouchstart EventHandle 手指触摸动作开始
bindtouchmove EventHandle 手指触摸后移动
bindtouchend EventHandle 手指触摸动作结束
bindtouchcancel EventHandle 手指触摸动作被打断,如来电提醒、弹窗
bindlongtap EventHandle
手指长按 500ms 之后触发,触发了长按事件后进行移
动不会触发屏幕的滚动
binderror EventHandle 当发生错误时触发 error 事件,detail={errMsg:'something
wrong'}
注意:canvas 标签默认宽度 300px、高度 225px。在同一页面中的 canvas-id 不可重复,
如果使用一个已经出现过的 canvas-id,该 canvas 标签对应的画布将被隐藏并不再正常工作。
示例代码:
// canvas.js
Page({
canvasIdErrorCallback: function (e) {
console.error(e.detail.errMsg)
},
onReady: function (e) {
//使用wx.createContext获取绘图上下文context
147
第 5 章 井字棋游戏
var context = wx.createCanvasContext('firstCanvas')
context.setStrokeStyle("#00ff00")
context.setLineWidth(5)
context.rect(0,0,200,200)
context.stroke()
context.setStrokeStyle ("#ff0000")
context.setLineWidth(2)
context.moveTo(160,100)
context.arc(100,100,60,0,2*Math.PI,true)
context.moveTo(140,100)
context.arc(100,100,40,0,Math.PI,false)
context.moveTo(85,80)
context.arc(80,80,5,0,2*Math.PI,true)
context.moveTo(125,80)
context.arc(120,80,5,0,2*Math.PI,true)
context.stroke()
context.draw()
}
})
5.3.2 响应 canvas 组件事件
canvas 组件可以响应手指触摸动作。可以在