vue实现五子棋游戏


Posted in Javascript onMay 28, 2020

本文实例为大家分享了vue实现五子棋游戏的具体代码,供大家参考,具体内容如下

思路

1.vue实现五子棋

空棋盘开局。

画网格:网格有 15 行 15 列,共有 225 个交叉点
黑先、白后,交替下子,每次只能下一子
胜负判定
按照简单的规则,从当前下子点位的方向判断()。如果有一个方向满足连续5个黑子或白子,游戏结束。

2.支持dom和canvas切换

判断浏览器是否支持canvas:

false: 不支持 切换dom方式
true:  支持 使用canvas

3.实现悔棋功能

4.实现撤销悔棋

例子:

为了简便,我就把所有写在一起了,按理来说是要分文件写的;

GitHub IO:链接

<!DOCTYPE html>
<html>
 <head>
 <meta charset="utf-8">
 <title>简易五子棋</title>
 <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
 <style>
 body {
 margin: 0;
 padding: 0;
 }
 #app{
 padding-left: 30%;
 width: 500px;
 }
 .h2Title{
 text-align: center;
 }
 #app h3{
 color: red;
 }
 .Fbuttons{
 margin-bottom: 1rem;
 }
 .main{
 background-color: bisque;
 width: 30rem;
 }
 .restart,.regret,.undo{
 background: bisque;
 padding: 6px 10px;
 border-radius: 6px;
 font-size: 12px;
 cursor: pointer;
 }
 #chess {
 position: relative;
 width: 440px;
 height: 450px;
 padding-left: 30px;
 padding-top: 30px;
 background-color: bisque; 
 }
 
 #chess .squre { 
 width: 28px;
 height: 28px;
 border: 1px solid #666;
 float: left;
 }
 
 #box01 .squre:hover {
 background-color: pink;
 }
 
 #box01 { 
 position: absolute;
 margin: 0 auto;
 width: 450px;
 height: 450px;
 top: 15px;
 left: 15px;
 }
 
 #box01 .qz {
 /* width: 28px;
 height: 28px; */
 width: 30px;
 height: 30px;
 border: 0px solid #C7C7C7;
 float: left;
 border-radius: 50%;
 /* margin: 1px; */
 }
 
 #box01 .qz:hover {
 background-color: pink;
 }
 .toggle{
 float: right;
 }
 
 </style>
 </head>
 <body>
 <div id="app">
 <h2 class="h2Title">五子棋</h2>
 <h3>{{victory}}</h3>
 <div class="Fbuttons">
 <input type="button" value="重新开始" class="restart" @click="restartInit()" />
 <input type="button" value="悔棋" class="regret" @click="regret()" />
 <input type="button" value="撤销悔棋" class="undo" @click="undo()" />
 <input type="button" :value="toggle?'切换dom':'切换canvas'" class="toggle" @click="toggleF()" />
 </div>
 <div class="main">
 <canvas v-show="toggle" id="myCanvas" ref="canvas" width="480" height="480">当前浏览器不支持Canvas</canvas>
 <div v-show="!toggle" id="chess" ref="chessBox">
 <!-- <div id="box01"></div>
 <div id="box02"></div> -->
 </div>
 </div>

 </div>
 <!-- -->
 <script>
 var app = new Vue({
 el: "#app",
 data: {
 pieceMapArr: [], //记录棋盘落子情况
 pieceColor: ["black", "white"], //棋子颜色
 step: 0, //记录当前步数
 checkMode: [ //输赢检查方向模式
 [1, 0], //水平
 [0, 1], //竖直
 [1, 1], //左斜线
 [1, -1], //右斜线
 ],
 flag: false,
 victory: '',
 history: [], //历史记录位置
 historyVal: [], //历史记录不被删除数组
 stepHistory: 0,
 domPiece:[], //
 toggle: true //true为canvas,false为dom
 },
 mounted(){
 const myCanvas = document.getElementById("myCanvas");
 if (!myCanvas.getContext) {
 alert("当前浏览器不支持Canvas.");
 this.toggle = false;
 this.drawpieceBoardDom();
 } else {
 console.log("当前浏览器支持Canvas", this.toggle)
 this.drawpieceBoard();
 const canvas = this.$refs.canvas;
 // 添加点击监听事件 
 canvas.addEventListener("click", e => {
 if (this.flag) {
 alert("游戏结束,请重新开始~");
 return;
 }
 //判断点击范围是否越出棋盘
 if (e.offsetX < 25 || e.offsetX > 450 || e.offsetY < 25 || e.offsetY > 450) {
 return;
 }
 let dx = Math.floor((e.offsetX + 15) / 30) * 30;
 let dy = Math.floor((e.offsetY + 15) / 30) * 30;
 console.log('this.pieceMapArr 数组', this.pieceMapArr)
 if (this.pieceMapArr[dx / 30 - 1][dy / 30 - 1] == 0) {
 console.log('落下棋子', dx, dy, this.pieceColor[this.step % 2])
 this.drawPiece(dx, dy, this.pieceColor[this.step % 2]); //落下棋子
 this.pieceMapArr[dx / 30 - 1][dy / 30 - 1] = this.pieceColor[this.step % 2];

 //历史记录位置
 this.history.length = this.step;
 this.history.push({
  dx,
  dy,
  color: this.pieceColor[this.step % 2]
 });
 this.historyVal.push({
  dx,
  dy,
  color: this.pieceColor[this.step % 2]
 });
 this.stepHistory++
 console.log('this.history', this.history);
 //检查当前玩家是否赢了游戏
 for (var i = 0; i < 4; i++) {
  this.checkWin(dx / 30 - 1, dy / 30 - 1, this.pieceColor[this.step % 2], this.checkMode[i]);
 }
 this.step++;
 } else {
 alert("不能落在有棋子的地方!");
 }
 });


 }
 },
 methods: {
 toggleF() {
 this.toggle = !this.toggle;
 if (!this.toggle) {
 // console.log("当前---------------1")
 // let elem = document.getElementById('box01');
 // if (elem !== null) {
 // elem.parentNode.removeChild(elem);
 // let elem02 = document.getElementById('box02');
 // elem02.parentNode.removeChild(elem02);
 // }
 // this.drawpieceBoardDom();
 this.restartInit()
 } else {
 this.restartInit()
 // this.drawpieceBoard();
 }
 },
 //初始化棋盘数组
 pieceArr() {
 for (let i = 0; i < 15; i++) {
 this.pieceMapArr[i] = [];
 for (let j = 0; j < 15; j++) {
 this.pieceMapArr[i][j] = 0;
 }
 }
 },
 //重新开始
 restartInit() {
 if (!this.toggle) {
 // console.log("-----dom-------")
 var elem = document.querySelector('#box01');
 // console.log("elem",elem)
 if (elem != null ) {
 elem.parentNode.removeChild(elem);
 let elem02 = document.querySelector('#box02');
 elem02.parentNode.removeChild(elem02);
 }
 this.drawpieceBoardDom();
 this.flag = false;
 this.step = 0;
 this.stepHistory = 0;
 this.historyVal = [];
 this.history = [];
 } else {
 //重画
 this.repaint();
 // 绘制棋盘
 this.drawpieceBoard();
 this.flag = false;
 this.step = 0;
 this.stepHistory = 0;
 this.historyVal = [];
 this.history = [];
 }
 },
 //---------canvas----------
 // 绘制棋盘
 drawpieceBoard() {
 //初始化棋盘数组
 this.pieceArr();
 //canvas 绘制
 let canvas = this.$refs.canvas
 // 调用canvas元素的getContext 方法访问获取2d渲染的上下文
 let context = canvas.getContext("2d");
 context.strokeStyle = '#666'
 for (let i = 0; i < 15; i++) {
 //落在方格(canvas 的宽高是450)
 // context.moveTo(15 + i * 30, 15)
 // context.lineTo(15 + i * 30, 435)
 // context.stroke()
 // context.moveTo(15, 15 + i * 30)
 // context.lineTo(435, 15 + i * 30)
 // context.stroke()
 //落在交叉点(480)
 context.beginPath();
 context.moveTo((i + 1) * 30, 30);
 context.lineTo((i + 1) * 30, canvas.height - 30);
 context.closePath();
 context.stroke();
 context.beginPath();
 context.moveTo(30, (i + 1) * 30);
 context.lineTo(canvas.width - 30, (i + 1) * 30);
 context.closePath();
 context.stroke();
 }
 },
 //绘制棋子
 drawPiece(x, y, color) {
 let canvas = this.$refs.canvas
 let context = canvas.getContext("2d");
 context.beginPath(); //开始一条路径或重置当前的路径
 context.arc(x, y, 15, 0, Math.PI * 2, false);
 context.closePath();
 context.fillStyle = color;
 context.fill();
 },
 //胜负判断函数
 checkWin(x, y, color, mode) {
 let count = 1; //记录
 for (let i = 1; i < 5; i++) {
 if (this.pieceMapArr[x + i * mode[0]]) {
 if (this.pieceMapArr[x + i * mode[0]][y + i * mode[1]] == color) {
  count++;
 } else {
  break;
 }
 }
 }
 for (let j = 1; j < 5; j++) {
 if (this.pieceMapArr[x - j * mode[0]]) {
 if (this.pieceMapArr[x - j * mode[0]][y - j * mode[1]] == color) {
  count++;
 } else {
  break;
 }
 }
 }
 // console.log('胜负判断函数', count)
 // console.log('color', color)
 if (count >= 5) {
 if (color == 'black') {
 this.victory = "黑子棋方胜利!";
 } else {
 this.victory = "白子棋方胜利!";
 }
 // 游戏结束
 // console.log('游戏结束')
 this.flag = true;
 }
 },
 //重画函数
 repaint() {
 //重画
 let canvas = this.$refs.canvas;
 let context = canvas.getContext("2d");
 context.fillStyle = "bisque";
 context.fillRect(0, 0, canvas.width, canvas.height);
 context.beginPath();
 context.closePath();
 },

 //悔棋: 
 // canvas 创建一个二维数组,下棋或者悔棋都操作这个数组。操作完数据,把画布全清,重新用数据画一个棋盘。
 // dom 二维数组删除数组最后一项, 先清空棋子的填充颜色,在渲染上颜色
 regret() {
 if (!this.toggle) {
 // console.log("-----dom------this.domPiece",this.domPiece)
 if (this.history.length && !this.flag) {
 this.history.pop(); //删除数组最后一项 
 console.log("-----dom------this.history", this.history)
 //重画
 this.pieceArr();
 // let elem = document.getElementById('box01');
 // if (elem !== null) {
 // elem.parentNode.removeChild(elem);
 // let elem02 = document.getElementById('box02');
 // elem02.parentNode.removeChild(elem02);
 // } //这个太耗性能了
 // this.drawpieceBoardDom();
 // 清空棋子的填充颜色
 this.domPiece.forEach(e => { 
  e.forEach(qz => {
  qz.style.backgroundColor = '';
  })  
 });
 // 渲染棋子颜色
 this.history.forEach(e => {
  this.domPiece[e.m][e.n].style.backgroundColor = e.color
  this.pieceMapArr[e.m][e.n] = e.color;
 });
 this.step--
 } else {
 alert("已经不能悔棋了~")
 }

 } else {
 if (this.history.length && !this.flag) {
 this.history.pop(); //删除数组最后一项 
 //重画
 this.repaint();
 // 绘制棋盘
 this.drawpieceBoard();
 //绘制棋子
 this.history.forEach(e => {
  this.drawPiece(e.dx, e.dy, e.color)
  this.pieceMapArr[e.dx / 30 - 1][e.dy / 30 - 1] = e.color;
 });
 this.step--
 } else {
 alert("已经不能悔棋了~")
 }
 }
 },
 //撤销悔棋 
 undo() {
 if (!this.toggle) {
 // console.log("-----dom------this.domPiece",this.domPiece)
 if ((this.historyVal.length > this.history.length) && !this.flag) {
 this.history.push(this.historyVal[this.step])
 console.log("-----dom------this.history", this.history)
 // 清空棋子的填充颜色
 this.domPiece.forEach(e => { 
  e.forEach(qz => {
  qz.style.backgroundColor = '';
  })  
 });
 // 渲染棋子颜色
 this.history.forEach(e => {
  this.domPiece[e.m][e.n].style.backgroundColor = e.color
  this.pieceMapArr[e.m][e.n] = e.color;
 });
 this.step++
 } else {
 alert("不能撤销悔棋了~")
 }
 
 } else {
 if ((this.historyVal.length > this.history.length) && !this.flag) {
 this.history.push(this.historyVal[this.step])
 //重画
 this.repaint();
 // 绘制棋盘
 this.drawpieceBoard();
 this.history.forEach(e => {
  this.drawPiece(e.dx, e.dy, e.color)
  this.pieceMapArr[e.dx / 30 - 1][e.dy / 30 - 1] = e.color;
 });
 this.step++
 } else {
 alert("不能撤销悔棋了~")
 }
 }
 },
 
 // -----------dom-----------
 drawpieceBoardDom() {
 // console.log("this", this)
 let that = this;
 //调用初始化棋盘数组函数
 that.pieceArr();
 //创建一个容器
 const box = document.querySelector("#chess");
 const box01 = document.createElement("div");
 box01.setAttribute("id", "box01");
 box.appendChild(box01);
 //画棋盘
 const chess01 = document.querySelector("#box01");
 const box02 = document.createElement("div");
 box02.setAttribute("id", "box02");
 box.appendChild(box02);
 let arr = new Array();
 for (let i = 0; i < 14; i++) {
 arr[i] = new Array();
 for (let j = 0; j < 14; j++) {
 arr[i][j] = document.createElement("div");
 arr[i][j].setAttribute("class", "squre");
 box02.appendChild(arr[i][j]);
 }
 }
 //画棋子
 let arr01 = this.domPiece; 
 for (let i = 0; i < 15; i++) {
 arr01[i] = new Array();
 for (let j = 0; j < 15; j++) {
 arr01[i][j] = document.createElement("div");
 arr01[i][j].setAttribute("class", "qz");
 chess01.appendChild(arr01[i][j]);
 }
 }
 // console.log("this.domPiece",this.domPiece)
 // 填充颜色和判断
 for (let m = 0; m < 15; m++) {
 for (let n = 0; n < 15; n++) {
 arr01[m][n].onclick = function() {
  //判断游戏是否结束
  if (!that.flag) {
  if (that.pieceMapArr[m][n] == 0) {
  //黑白交换下棋
  // console.log(this);
  // console.log('落下棋子', that.pieceColor[that.step % 2])
  //确保填充颜色正确进行了判断
  if (this.className == "qz" && that.step % 2 == 0 && this.style.backgroundColor == "") {
  //下棋填充黑颜色
  this.style.backgroundColor = that.pieceColor[that.step % 2];
  //写入棋盘数组
  that.pieceMapArr[m][n] = that.pieceColor[that.step % 2];
  //历史记录位置
  that.history.length = that.step;
  that.history.push({
  m,
  n,
  color: that.pieceColor[that.step % 2]
  });
  that.historyVal.push({
  m,
  n,
  color: that.pieceColor[that.step % 2]
  });
  that.stepHistory++
  console.log('this.history', that.history);
  } else if (this.className == "qz" && that.step % 2 != 0 && this.style.backgroundColor == "") {
  //下棋填充白颜色
  this.style.backgroundColor = that.pieceColor[that.step % 2];
  //写入棋盘数组
  that.pieceMapArr[m][n] = that.pieceColor[that.step % 2];
  //历史记录位置
  that.history.length = that.step;
  that.history.push({
  m,
  n,
  color: that.pieceColor[that.step % 2]
  });
  that.historyVal.push({
  m,
  n,
  color: that.pieceColor[that.step % 2]
  });
  that.stepHistory++
  console.log('this.history', that.history);
  }
  //检查当前是否赢了
  for (var i = 0; i < 4; i++) {
  that.checkWin(m, n, that.pieceColor[that.step % 2], that.checkMode[i]);
  }
  that.step++;
  // console.log('that.step', that.step);
  } else {
  alert("不能落在有棋子的地方!");
  return;
  }
  } else {
  // that.flag = true;
  alert("游戏结束,请重新开始~");
  return;
  }
 }
 }
 }
 
 },

 }
 });
 </script>
 </body>
</html>

更多文章可以点击《Vue.js前端组件学习教程》学习阅读。

关于vue.js组件的教程,请大家点击专题vue.js组件学习教程进行学习。

更多vue学习教程请阅读专题《vue实战教程》

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JQuery+DIV自定义滚动条样式的具体实现
Jun 25 Javascript
基于jquery编写的横向自适应幻灯片切换特效的实例代码
Aug 06 Javascript
类似天猫商品详情随浏览器移动的示例代码
Feb 27 Javascript
jquery form 加载数据示例
Apr 21 Javascript
使用js获取图片原始尺寸
Dec 03 Javascript
js实现iframe自动自适应高度的方法
Feb 17 Javascript
Vue2实时监听表单变化的示例讲解
Aug 30 Javascript
Bootstrap fileinput 上传新文件移除时触发服务器同步删除的配置
Oct 08 Javascript
JS+html5实现异步上传图片显示上传文件进度条功能示例
Nov 09 Javascript
Vue实现图片轮播组件思路及实例解析
May 11 Javascript
js仿京东放大镜效果
Aug 09 Javascript
实现一个简单得数据响应系统
Nov 11 Javascript
用vue 实现手机触屏滑动功能
May 28 #Javascript
Jquery高级应用Deferred对象原理及使用实例
May 28 #jQuery
JQuery插件tablesorter表格排序实现过程解析
May 28 #jQuery
JS替换字符串中指定位置的字符(多种方法)
May 28 #Javascript
js实现九宫格布局效果
May 28 #Javascript
微信小程序实现电子签名并导出图片
May 27 #Javascript
JS 逻辑判断不要只知道用 if-else 和 switch条件判断(小技巧)
May 27 #Javascript
You might like
精致的人儿就要挑杯子喝咖啡
2021/03/03 冲泡冲煮
基于magic_quotes_gpc与magic_quotes_runtime的区别与使用介绍
2013/04/22 PHP
php通过隐藏表单控件获取到前两个页面的url
2014/09/09 PHP
Laravel中基于Artisan View扩展包创建及删除应用视图文件的方法
2016/10/08 PHP
JavaScript 事件的一些重要说明
2009/10/25 Javascript
location.href用法总结(最主要的)
2013/12/27 Javascript
JS判断变量是否为空判断是否null
2014/07/25 Javascript
JavaScript实现在标题栏上显示当前日期的方法
2015/03/19 Javascript
解决angular的post请求后SpringMVC后台接收不到参数值问题的方法
2015/12/10 Javascript
js实现当鼠标移到表格上时显示这一格全部内容的代码
2016/06/12 Javascript
面试常见的js算法题
2017/03/23 Javascript
jQuery实现的背景颜色渐变动画效果示例
2017/03/24 jQuery
AngularJS之自定义服务详解(factory、service、provider)
2017/04/14 Javascript
angular过滤器实现排序功能
2017/06/27 Javascript
Vee-Validate的使用方法详解
2017/09/22 Javascript
详解Angular5 服务端渲染实战
2018/01/04 Javascript
Vue中插入HTML代码的方法
2018/09/21 Javascript
vue项目中实现图片预览的公用组件功能
2018/10/26 Javascript
js中的深浅拷贝问题简析
2019/05/10 Javascript
微信小程序框架的页面布局代码
2019/08/17 Javascript
vue中监听路由参数的变化及方法
2019/12/06 Javascript
详解vue中在循环中使用@mouseenter 和 @mouseleave事件闪烁问题解决方法
2020/04/07 Javascript
在vue中动态修改css其中一个属性值操作
2020/12/07 Vue.js
在Windows中设置Python环境变量的实例讲解
2018/04/28 Python
django+tornado实现实时查看远程日志的方法
2019/08/12 Python
Python实现捕获异常发生的文件和具体行数
2020/04/25 Python
使用pymysql查询数据库,把结果保存为列表并获取指定元素下标实例
2020/05/15 Python
澳大利亚运动鞋零售商:The Athlete’s Foot
2018/11/04 全球购物
Bonami斯洛伐克:购买家具和家居饰品
2019/07/02 全球购物
继承公证书样本
2014/04/04 职场文书
户籍证明模板
2014/09/28 职场文书
部门2014年度工作总结
2014/11/12 职场文书
好媳妇事迹材料
2014/12/24 职场文书
Nginx安装完成没有生成sbin目录的解决方法
2021/03/31 Servers
MySQL连表查询分组去重的实现示例
2021/07/01 MySQL
MySQL的InnoDB存储引擎的数据页结构详解
2022/03/03 MySQL