五子棋对弈、悔棋DEMO
效果图
分析
- 采用微信小程序的canvas制作五子棋;
- 确定棋盘大小及格数;
- 绘制棋盘----通过棋盘宽高和格数计算间距,同时保存坐标点;
- 黑方和白方下子----定义一个布尔变量代表各自的身份;
- 重置棋盘----重新开始;
- 通过判断当前棋手,悔棋时进行改变。
绘制棋盘
代码语言:javascript复制drawLine(arr){
arr.forEach(current => {
this.ctx.setFillStyle(this.lineColor);
this.ctx.beginPath();
this.ctx.lineWidth = 1;
this.ctx.moveTo(current[0].x, current[0].y);
for (var i = 1; i < current.length; i ) {
this.ctx.lineTo(current[i].x, current[i].y);
}
this.ctx.stroke();
this.ctx.closePath();
this.ctx.draw(true);
});
}
drawChessboard(){
// 每个格子的宽高
var everyLen = this.everyLen;
// 标记坐标的个数
var count = 0;
// 从纵向保存坐标
var arrY = [];
// 双循环计算每个坐标的横纵坐标
for(var i = 0;i <= this.type; i ){
var arr = [],arr0 = [];
for(var j = 0;j <= this.type; j ){
count ;
arr.push({
y: this.margin i * everyLen,
x: this.margin j * everyLen,
pointX: j,
pointY: i,
index: count
});
arr0.push({
x: this.margin i * everyLen,
y: this.margin j * everyLen
})
}
// 清空canvas
this.ctx.clearRect(0, 0, this.width, this.height);
// 保存横线坐标和竖线坐标
this.everyPoint.push(arr);
arrY.push(arr0);
}
// 绘制横向线
this.drawLine(this.everyPoint);
// 绘制竖向线
this.drawLine(arrY);
}
绘制当前点击坐标的棋子
代码语言:javascript复制// 获取当前点击位置的坐标
getPosition(e){
return {
x: e.touches[0].x,
y: e.touches[0].y
};
}
// 将当前坐标和棋盘坐标数组对比,找到精确坐标
checkPoint(arr,po){
for (var i = 0; i < this.everyPoint.length; i ){
for (var j = 0; j < this.everyPoint[i].length; j ){
if (Math.abs(this.everyPoint[i][j].x - po.x) < this.everyLen/2 && Math.abs(this.everyPoint[i][j].y - po.y) < this.everyLen/2){
// 将棋盘精确坐标保存到当前持棋方数组
arr.push(this.everyPoint[i][j]);
// 同时删除棋盘坐标数组的该值,表示当前位置已经存在棋子
this.everyPoint[i].splice(j,1);
break;
}
}
}
}
// 绘制当前坐标棋子
drawCle(opts,color){
this.ctx.setFillStyle(color);
this.ctx.beginPath();
this.ctx.arc(opts.x, opts.y, this.r, 0, Math.PI * 2, true);
this.ctx.closePath();
this.ctx.fill();
this.ctx.draw(true);
}
drawLastPoint(type){
// 判断是黑方持棋还是白方持棋,进行绘制棋子
if(type == 'AI'){
this.AIPoint.forEach((current, index) => {
this.drawCle(current, '#000000');
});
}else{
this.myPoint.forEach((current, index) => {
this.drawCle(current, '#ffffff');
});
}
}
this.page.changeTouchStart = function (e) {
// 判断游戏是否开始
if (self.START_GAME){
// 获取当前坐标
var newPo = self.getPosition(e);
// 获取棋盘精确坐标
if (!self.boolAI && self.boolMy) {
self.checkPoint(self.myPoint, newPo);
} else if (self.boolAI && !self.boolMy) {
self.checkPoint(self.AIPoint, newPo);
}
}
}
this.page.changeTouchEnd = function (e) {
if (self.START_GAME) {
// 绘制棋子
if (!self.boolAI && self.boolMy) {
self.boolAI = !self.boolAI;
self.boolMy = !self.boolMy;
self.drawLastPoint('PO');
// 判断白棋是否五子胜利
if (self.myPoint.length >= 5 && self.checkWinner(self.myPoint)){
wx.showToast({title: '白棋胜利!'});
self.START_GAME = false;
}
} else if (self.boolAI && !self.boolMy) {
self.boolAI = !self.boolAI;
self.boolMy = !self.boolMy;
self.drawLastPoint('AI');
// 判断黑棋是否五子胜利
if(self.AIPoint.length >= 5 && self.checkWinner(self.AIPoint)){
wx.showToast({ title: '黑棋胜利!' });
self.START_GAME = false;
}
}
}
}
五子棋胜利方判断
代码语言:javascript复制五子棋胜利就是横向、纵向、45度斜线方向、135度斜线方向连成五个颜色相同的棋子,为了更加清楚的表示,我将四个方向的判断做四个函数处理。
checkTransverse(arr,po){//横向检查
var len = arr.length - 1;
var count = 1;
// 东
for(var i = 1; i < this.CHESS_LEN ; i ){
for (var j = 0; j < len; j ){
if(arr[j].pointX == po.pointX - i && arr[j].pointY == po.pointY){
count ;
}
}
}
if (count == this.CHESS_LEN) { return true;}
// 西
for (var i = 1; i < this.CHESS_LEN; i ) {
for (var j = 0; j < len; j ) {
if (arr[j].pointX == po.pointX i && arr[j].pointY == po.pointY) {
count ;
}
}
}
if (count == this.CHESS_LEN) { return true; }
}
checkPortrait(arr,po){//纵向检查
var len = arr.length - 1;
var count = 1;
// 南
for (var i = 1; i < this.CHESS_LEN; i ) {
for (var j = 0; j < len; j ) {
if (arr[j].pointX == po.pointX && arr[j].pointY == po.pointY - i) {
count ;
}
}
}
if (count == this.CHESS_LEN) { return true; }
// 北
for (var i = 1; i < this.CHESS_LEN; i ) {
for (var j = 0; j < len; j ) {
if (arr[j].pointX == po.pointX && arr[j].pointY == po.pointY i) {
count ;
}
}
}
if (count == this.CHESS_LEN) { return true; }
}
checkNortheast(arr,po){//45度
var len = arr.length - 1;
var count = 1;
// 西南
for (var i = 1; i < this.CHESS_LEN; i ) {
for (var j = 0; j < len; j ) {
if (arr[j].pointX == po.pointX - i && arr[j].pointY == po.pointY - i) {
count ;
}
}
}
if (count == this.CHESS_LEN) { return true; }
// 东北
for (var i = 1; i < this.CHESS_LEN; i ) {
for (var j = 0; j < len; j ) {
if (arr[j].pointX == po.pointX i && arr[j].pointY == po.pointY i) {
count ;
}
}
}
if (count == this.CHESS_LEN) { return true; }
}
checkNorthwest(arr,po){//135度
var len = arr.length - 1;
var count = 1;
// 西北
for (var i = 1; i < this.CHESS_LEN; i ) {
for (var j = 0; j < len; j ) {
if (arr[j].pointX == po.pointX - i && arr[j].pointY == po.pointY i) {
count ;
}
}
}
if (count == this.CHESS_LEN) { return true; }
// 东南
for (var i = 1; i < this.CHESS_LEN; i ) {
for (var j = 0; j < len; j ) {
if (arr[j].pointX == po.pointX i && arr[j].pointY == po.pointY - i) {
count ;
}
}
}
if (count == this.CHESS_LEN) { return true; }
}
checkWinner(arr){
var currentPo = arr[arr.length - 1];
var win1 = this.checkTransverse(arr, currentPo);
var win2 = this.checkPortrait(arr, currentPo);
var win3 = this.checkNortheast(arr, currentPo);
var win4 = this.checkNorthwest(arr, currentPo);
if (win1 || win2 || win3 || win4){
return true;
}else{
return false;
}
}
重置棋盘
代码语言:javascript复制resetChessBoard(){
this.page.setData({ isHide: false });
this.init();
}
this.page.changeReset = function(e){
self.resetChessBoard();
}
注意
- 绘制棋盘前必须清空canvas,方便最后的重新开始和重置棋盘;
- 对当前棋子的坐标四个方向的判断,采用的原始坐标而不是计算后的绘制坐标;
- 在判断持棋人时,各自采用一个值,方便添加悔棋功能。