前言

想学习下vue中使用canvas,直接学习感觉太无聊,通过实现五子棋增加些乐趣,过程中发现规则算法实现起来还是有一些复杂度的

代码实现

初步代码结构

<template><canvas ref="myCanvas" width="640" height="640" @click="func.next"></canvas><div><button @click="func.start">开始</button><span style="color: red">{{property.message}}</span></div>
</template><script>
import {ref, reactive, onMounted} from 'vue'
export default {name: "GoBang",setup(){const myCanvas = ref(null)const property = reactive({size: 40, //棋盘每格宽高rowNum: 15, //棋盘行数列数message: '',})const ai = reactive({})const func = reactive({start: () => {},next: () => {}})onMounted(() => {})return{myCanvas,property,func}}
}
</script><style scoped></style>

canvas组件context要在所有组件加载完才能调用,所以要放到onMunted中

let ctx = ref(null)
const func = reactive({init: () => {ctx = myCanvas.value.getContext('2d')},drawChessBoard: () => {ctx.beginPath()ctx.rect(0, 0, (property.size * (property.rowNum + 1)), (property.size * (property.rowNum + 1)))ctx.strokeStyle = 'green'ctx.stroke()//棋盘for(let i = 1; i <= property.rowNum; i++){ctx.moveTo(i * property.size, property.size)ctx.lineTo(i * property.size, property.size * property.rowNum)}for(let j = 1; j <= property.rowNum; j++){ctx.moveTo(property.size, property.size * j)ctx.lineTo(property.size * property.rowNum, property.size * j)}ctx.stroke()ctx.closePath()},start: () => {},next: () => {}
})
onMounted(() => {func.init()func.drawChessBoard()
})

效果图

画棋子

const property = reactive({size: 40, //棋盘每格宽高rowNum: 15, //棋盘行数列数message: '',validRange: 0.3  //棋子的半径占每格比
})
//func中
drawChess: (x, y, color) => {ctx.beginPath()ctx.moveTo(x+ property.size * property.validRange, y )ctx.arc(x, y, property.size * property.validRange, 0, 2 * Math.PI)ctx.strokeStyle = colorctx.fillStyle = colorctx.fill()ctx.stroke()ctx.closePath()
}

ai逻辑

const operate = reactive({computer: 1,people: 2
})
const ai = reactive({//检测是否五子checkFive: () => {},//查找单4的位置findBySingleFour: () => {},//查找下一步棋后将会双4的位置findWillBeDoubleFour: () => {},//查找下一步棋后将会单4且双三的位置 暂不实现findWillBeSingleFourAndDoubleThree: () => {},//查找下一步棋后将会两个双三的位置 暂不实现findWillBeTwoDoubleThree: () => {},//查找下两步棋后将会是双4的位置 代替上面两个未实现的方法,但减少了智能findWillBeDoubleFourStep2: () => {},//查找跟随位置,跟随人下棋的位置 落子到旁边findFollowPosition:() => {},//周边找不到位置 随机findRandomPosition: () => {}
})

checkFive

checkFive: (a, rowNum, operator) => {for(let i = 0; i < rowNum; i++){for(let j = 0; j < rowNum ; j++){if(i >= 2 && i < (rowNum - 2) && (a[i][j] & a[i + 1][j] & a[i + 2][j] & a[i - 1][j] & a[i - 2][j]) == operator ||j >= 2 && j < (rowNum - 2) && (a[i][j] & a[i][j + 1] & a[i][j + 2] & a[i][ j - 1] & a[i][j - 2]) == operator ||i >= 2 && j >= 2 && i < (rowNum - 2) && j < (rowNum - 2) && (a[i][j] & a[i + 1][j + 1] & a[i + 2][j + 2] & a[i - 1][j - 1] & a[i - 2][j - 2]) == operator ||i >= 2 && j >= 2 && i < (rowNum - 2) && j < (rowNum - 2) && (a[i][j] & a[i - 1][j + 1] & a[i - 2][j + 2] & a[i + 1][j - 1] & a[i + 2][j - 2]) == operator){return true}}}return false
}

findBySingleFour

//查找单4的位置
findBySingleFour: (a, rowNum, operator) => {let sum = 4 * operatorfor(let i = 0; i < rowNum; i++){for(let j = 0; j < rowNum; j++){//横向判断if(i >= 2 && i < rowNum - 2 && (a[i][j] + a[i + 1][j] + a[i + 2][j] + a[i - 1][j] + a[i - 2][j]) == sum &&(a[i][j] | a[i + 1][j] | a[i + 2][j] | a[i - 1][j] | a[i - 2][j]) == operator){for(let index = 0; index < 5; index++){if(a[i - 2 + index][j] == 0){return {x: i - 2 + index,y: j}}}}//纵向判断if(j >= 2 && j < rowNum - 2 && (a[i][j] + a[i][j + 1] + a[i][j + 2] + a[i][ j - 1] + a[i][j - 2]) == sum &&(a[i][j] | a[i][j + 1] | a[i][j + 2] | a[i][j - 1] | a[i][j - 2]) == operator){for(let index = 0; index < 5; index++){if(a[i][j - 2 + index] == 0){return {x: i,y: j - 2 + index}}}}//正斜向判断if(i >= 2 && i < rowNum - 2 && j >= 2 && j < rowNum - 2 && (a[i][j] + a[i + 1][j + 1] + a[i + 2][j + 2] + a[i - 1][j - 1] + a[i - 2][j - 2]) == sum &&(a[i][j] | a[i + 1][j + 1] | a[i + 2][j + 2] | a[i - 1][j - 1] | a[i - 2][j - 2]) == operator){for(let index = 0; index < 5; index++){if(a[i - 2 + index][j - 2 + index] == 0){return {x: i - 2 + index,y: j - 2 + index}}}}//反斜向判断if(i >= 2 && i < rowNum - 2 && j >= 2 && j < rowNum - 2 && (a[i][j] + a[i - 1][j + 1] + a[i - 2][j + 2] + a[i + 1][j - 1] + a[i + 2][j - 2]) == sum &&(a[i][j] | a[i - 1][j + 1] | a[i - 2][j + 2] | a[i + 1][j - 1] | a[i + 2][j - 2]) == operator){for(let index = 0; index < 5; index++){if(a[i - 2 + index][j + 2 - index] == 0){return {x: i - 2 + index,y: j + 2 - index}}}}}}return null
}

findWillBeDoubleFour

findWillBeDoubleFour: (a, rowNum, operator) => {let sum = 3 * operatorfor(let i = 0; i < rowNum; i++){for(let j = 0; j < rowNum; j++){if(i >= 2 && i < rowNum - 2 && (a[i][j] + a[i + 1][j] + a[i + 2][j] + a[i - 1][j] + a[i - 2][j]) == sum &&(a[i][j] | a[i + 1][j] | a[i + 2][j] | a[i - 1][j] | a[i - 2][j]) == operator && (a[i - 2][j] == 0 || a[i + 2][j] == 0)){//两边界必须为空if(a[i - 2][j] == 0 && i < rowNum - 3 && a[i + 3][j] == 0 ||a[i + 2][j] == 0 && i > 2 && a[i - 3][j] == 0){for(let index = 0; index < 3; index++){if(a[i - 1 + index][j] == 0){return {x: i - 1 + index,y: j}}}//中间三个满了return a[i - 2][j] == 0 && i < rowNum - 3 && a[i + 3][j] == 0 ?{x: i + 2,y: j} :{x: i - 2,y: j}}}//纵向判断if(j >= 2 && j < rowNum - 2 && (a[i][j] + a[i][j + 1] + a[i][j + 2] + a[i][ j - 1] + a[i][j - 2]) == sum &&(a[i][j] | a[i][j + 1] | a[i][j + 2] | a[i][j - 1] | a[i][j - 2]) == operator && (a[i][j - 2] == 0 || a[i][j + 2] == 0)){//两边界必须为空if(a[i][j - 2] == 0 && j < rowNum - 3 && a[i][j + 3] == 0 ||a[i][j + 2] == 0 && j > 2 && a[i][j - 3] == 0){for(let index = 0; index < 3; index++){if(a[i][j - 1 + index] == 0){return {x: i,y: j - 1 + index}}}//中间三个满了return a[i][j - 2] == 0 && j < rowNum - 3 && a[i][j + 3] == 0 ?{x: i,y: j + 2} :{x: i,y: j - 2}}}//正斜向判断if(i >= 2 && i < rowNum - 2 && j >= 2 && j < rowNum - 2 && (a[i][j] + a[i + 1][j + 1] + a[i + 2][j + 2] + a[i - 1][j - 1] + a[i - 2][j - 2]) == sum &&(a[i][j] | a[i + 1][j + 1] | a[i + 2][j + 2] | a[i - 1][j - 1] | a[i - 2][j - 2]) == operator && (a[i - 2][j - 2] == 0 || a[i + 2][j + 2] == 0)){//两边界必须为空if(a[i - 2][j - 2] == 0 && i < rowNum - 3 && j < rowNum - 3 && a[i + 3][j + 3] == 0 ||a[i + 2][j + 2] == 0 && i > 2 && j > 2 && a[i - 3][j - 3] == 0){for(let index = 0; index < 3; index++){if(a[i - 1 + index][j - 1 + index] == 0){return {x: i - 1 + index,y: j - 1 + index}}}//中间三个满了return a[i - 2][j - 2] == 0 && i < rowNum - 3 && j < rowNum - 3 && a[i + 3][j + 3] == 0 ?{x: i + 2,y: j + 2} :{x: i - 2,y: j - 2}}}//反斜向判断if(i >= 2 && i < rowNum - 2 && j >= 2 && j < rowNum - 2 && (a[i][j] + a[i - 1][j + 1] + a[i - 2][j + 2] + a[i + 1][j - 1] + a[i + 2][j - 2]) == sum &&(a[i][j] | a[i - 1][j + 1] | a[i - 2][j + 2] | a[i + 1][j - 1] | a[i + 2][j - 2]) == operator && (a[i + 2][j - 2] == 0 || a[i - 2][j + 2] == 0)){//两边界必须为空if(a[i - 2][j + 2] == 0 && i < rowNum - 3 && j > 2 && a[i + 3][j - 3] == 0 ||a[i + 2][j - 2] == 0 && i > 2 && j < rowNum - 3 && a[i - 3][j + 3] == 0){for(let index = 0; index < 3; index++){if(a[i - 1 + index][j + 1 - index] == 0){return {x: i - 1 + index,y: j + 1 - index}}}//中间三个满了return a[i - 2][j + 2] == 0 && i < rowNum - 3 && j > 2 && a[i + 3][j - 3] == 0 ?{x: i - 2,y: j + 2} :{x: i + 2,y: j - 2}}}}}return null
}

findWillBeDoubleFourStep2

//查找下两步棋后将会是双4的位置 代替上面两个未实现的方法,但减少了智能
findWillBeDoubleFourStep2: (a, rowNum, operator) => {for(let i = 0; i < rowNum; i++){for(let j = 0; j < rowNum; j++){if(a[i][j] == 0){a[i][j] = operatorlet p = ai.findWillBeDoubleFour(a, rowNum, operator)a[i][j] = 0if(p){return {x: i,y: j}}}}}
}

findFollowPosition

//查找跟随位置,跟随人下棋的位置 落子到旁边
findFollowPosition: (a, i, j, rowNum) => {if(i >= 1 && a[i - 1][j] == 0){return {x: i - 1,y: j}}if(j >= 1 && a[i][j - 1] == 0){return {x: i,y: j - 1}}if(i < rowNum - 1 && a[i + 1][j] == 0){return {x: i + 1,y: j}}if(j < rowNum - 1 && a[i][j + 1] == 0){return {x: i,y: j + 1}}if(i >= 1 && j >= 1 && a[i - 1][j - 1] == 0){return {x: i - 1,y: j - 1}}if(i >= 1 && j < rowNum - 1 && a[i - 1][j + 1] == 0){return {x: i - 1,y: j + 1}}if(i < rowNum - 1 && j >= 1 && a[i + 1][j - 1] == 0){return {x: i + 1,y: j - 1}}if(i < rowNum - 1 && j < rowNum - 1 && a[i + 1][j + 1] == 0){return {x: i + 1,y: j + 1}}
}

findRandomPosition

//周边找不到位置 随机
findRandomPosition: (rowNum, dressNum) => {let value = 0let totalNum = rowNum * rowNumwhile(dressNum < totalNum){value = Math.floor(Math.random() * rowNum * rowNum)let i = Math.floor(value / rowNum)let j = value % property.rowNumif(property.data[x][y] == 0){return {x : i,y : j}}}return null
}

人落子相关

const property = reactive({size: 40, //棋盘每格宽高rowNum: 15, //棋盘行数列数message: '',validRange: 0.3,  //棋子的半径占每格比canMove: false,data: [],dressNum: 0
})//人最后落子的位置
const lastPosition = {i: 0,j: 0
}start: () => {property.canMove = true
},
next: (p) => {if(!property.canMove){return}property.canMove = falselet x = p.offsetXlet y = p.offsetYx = func.calcPosition(x, property.validRange, property.size)y = func.calcPosition(y, property.validRange, property.size)if(x == -1 || y == -1){return}func.drawChess(x, y, 'red')//记忆落子位置let i = x / property.size - 1let j = y / property.size - 1lastPosition.i = ilastPosition.j = jproperty.data[i][j] = operate.peopleif(ai.checkFive(property.data, property.rowNum, operate.people)){func.win(operate.people)return}func.aiNext()
},
calcPosition: (x, validRange, size) => {let xRemainder = x % sizereturn xRemainder < validRange * size ? (x - xRemainder) :(xRemainder < (1 - validRange) * size ? - 1 : (x + size - xRemainder))
},

ai落子

aiNext: () => {//检查自己单4let p = ai.findBySingleFour(property.data, property.rowNum, operate.computer)if(p){func.drawChess((p.x + 1) * property.size, (p.y + 1) * property.size, 'black')func.win(operate.computer)return}//查找对方单4p = ai.findBySingleFour(property.data, property.rowNum, operate.people)if(p){func.drawBlackChess(p)return}//查找自己将要双4的位置p = ai.findWillBeDoubleFour(property.data, property.rowNum, operate.computer)if(p){func.drawBlackChess(p)return}//查找对方将要双4的位置p = ai.findWillBeDoubleFour(property.data, property.rowNum, operate.people)if(p){func.drawBlackChess(p)return}//查找对方两步将要双4的位置p = ai.findWillBeDoubleFourStep2(property.data, property.rowNum, operate.people)if(p){func.drawBlackChess(p)return}//查找自己两步将要双4的位置p = ai.findWillBeDoubleFourStep2(property.data, property.rowNum, operate.computer)if(p){func.drawBlackChess(p)return}//跟随位置p = ai.findFollowPosition(property.data, lastPosition.i, lastPosition.j, property.rowNum)if(p){func.drawBlackChess(p)return}p = ai.findRandomPosition(property.rowNum, property.dressNum)func.drawBlackChess(p)},
win: (operator) => {property.message = operator == 1 ? "黑方胜" : "红方胜"property.canMove = false
},
drawBlackChess: (p) => {func.drawChess((p.x + 1) * property.size, (p.y + 1) * property.size, 'black')property.data[p.x][p.y] = 1property.canMove = true
},
checkDressNum: () => {if(property.dressNum == property.rowNum * property.rowNum){property.message = "和棋了"}
},
drawChess: (x, y, color) => {ctx.beginPath()ctx.moveTo(x+ property.size * property.validRange, y )ctx.arc(x, y, property.size * property.validRange, 0, 2 * Math.PI)ctx.strokeStyle = colorctx.fillStyle = colorctx.fill()ctx.stroke()ctx.closePath()property.dressNum++func.checkDressNum()
}

最终效果

canvas学习之五子棋规则法部分实现相关推荐

  1. canvas学习笔记

    canvas学习笔记 canvas API中文网 - Canvas API中文文档首页地图 使用canvas来绘制图形 - Web API 接口参考 | MDN 什么是Canvas? Canvas是H ...

  2. java五子棋项目创新点_五子棋规则的改革创新方法

    五子棋规则最近几年来,关于五子棋规则改革的讨论掀起了一阵阵高潮,形态各异的新规则层出无穷,可谓是对各种规则改革方案的大胆设想.下面小编给你介绍五子棋规则的改革创新,欢迎阅读. 五子棋大多数新规则跟流星 ...

  3. HTML5 Canvas 学习日志(三)

    2019独角兽企业重金招聘Python工程师标准>>>  HTML5 Canvas 学习日志(三) Canvas的11种合成 蓝色为destination,粉色为source 1 ...

  4. Canvas 学习笔记1

    #Canvas 学习笔记1 @[Canvas,Nunn,HTML5,javascript] ##前言 相信大家多多少少都有了解过`Canvas`,这里我就不多做解释了,网上也充斥了这方面的知识,很多人 ...

  5. canvas学习和滤镜实现

    最近学习了 HTML5 中的重头戏-- canvas .利用 canvas,前端人员可以很轻松地.进行图像处理.其 API 繁多,这次主要学习常用的 API,并且完成以下两个代码: 实现去色滤镜 实现 ...

  6. Canvas学习:封装Canvas绘制基本图形API

    Canvas学习:封装Canvas绘制基本图形API Canvas Canvas学习 从前面的文章中我们了解到,通过Canvas中的CanvasRenderingContext2D对象中的属性和方法, ...

  7. canvas学习绘制渐变色

    1.createLinearGradient() 创建线性渐变 //Linear adj. 直线的 线性的 //Gradient n. 梯度 变化率 createLinearGradient(x1,y ...

  8. 第六节 电子学习 二极管档测量法 细讲

    二极管档测量法非常重要,维修过程中,作者是用的最多的方法, 第四节讲了一些,但是图示仍不明确,可能很多实践少的朋友不理解. 这里绘图更详细的讲解. 见上图, 现代集成电路工艺,每个引脚内部都有一个保护 ...

  9. Canvas学习笔记之画线

    Canvas学习笔记之画线 步骤 1.使用getElementById()获取canvas元素. 2.获取canvas的绘制环境getContext(). 3.进行绘制画笔的粗细和颜色定义,分别是li ...

最新文章

  1. OpenCV中与matlab中相对应的函数
  2. mysql 相关命令
  3. 【Codeforces】401C Team (01010110...)
  4. 彻底取代Redis+数据库架构,京东618稳了!
  5. 推荐算法炼丹笔记:序列化推荐算法Bert4Rec
  6. CPU方案简介 RK3308 - 智能音响
  7. LiveVideoStack线上分享第三季(九):《街舞》《长安十二时辰》背后的文娱大脑...
  8. dos输入java Hello,出现错误: 找不到或无法加载主类 Hello
  9. SAP License:你是怎么理解ERP的?
  10. 【报告分享】2020年抖音美妆直播报告.pdf(附下载链接)
  11. linux识别设备插槽,你如何确定linux计算机的CPU插槽类型?
  12. 西数linux驱动程序,下载:西数移动硬盘WD SES Driver驱动更新
  13. Flutter修改App名称(Android+IOS)
  14. 当网页无法正常显示时更换浏览器
  15. 鱼眼和全向视图的图像深度学习方法
  16. BioBERT: a pre-trained biomedical language representation model for biomedical text mining
  17. 华为大数据研发第3轮面试
  18. 什么是地理信息系统(GIS)?
  19. python读取word内容复制粘贴_如何复制word文档的内容?
  20. ubuntu展示点云使用boost::this_thread报错

热门文章

  1. 计算机辅助测试技术最近的发展,CAT_计算机辅助测试_技术_第六讲_CAT的发展_郑叔芳...
  2. 技法の穴をふさぐ:規模編--技法のルールは分かりにくい数え方の“迷い”をなくす
  3. Lagrangian乘子法与对偶上升法(Dual Ascent)
  4. matlab绘制线性回归_如何在Excel中绘制线性校准曲线
  5. 简单几个设置教会你更好的保护Mac!不让你的Mac中毒小妙招!
  6. 【Educoder】密码学理论与实战 30+完整过题代码
  7. Python 数据分析学习笔记(一):Pandas 入门
  8. CRM系统需具有的九大功能
  9. 怎么让Java系统的手机连WiFi_Java-Jain Sip如何在Android中连接WiFi
  10. Cryp.1.大整数相乘---分治法