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 相关文章推荐
JavaScript学习笔记记录我的旅程
May 23 Javascript
javascript基本类型详解
Nov 28 Javascript
JS实现向表格中动态添加行的方法
Mar 30 Javascript
jquery模拟进度条实现方法
Aug 03 Javascript
js实现内容显示并使用json传输数据
Mar 16 Javascript
Javascript必知必会(四)js类型转换
Jun 08 Javascript
javascript this详细介绍
Sep 19 Javascript
vue加载自定义的js文件方法
Mar 13 Javascript
js遍历添加栏目类添加css 再点击其它删除css【推荐】
Jun 12 Javascript
vue实现压缩图片预览并上传功能(promise封装)
Jan 10 Javascript
vue根据条件不同显示不同按钮的操作
Aug 04 Javascript
antd vue 刷新保留当前页面路由,保留选中菜单,保留menu选中操作
Aug 06 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
php 字符转义 注意事项
2009/05/27 PHP
PHP 文件上传全攻略
2010/04/28 PHP
Trying to clone an uncloneable object of class Imagic的解决方法
2012/01/11 PHP
PHP实现采集中国天气网未来7天天气
2014/10/15 PHP
使用PHP把HTML生成PDF文件的几个开源项目介绍
2014/11/17 PHP
非常有用的9个PHP代码片段
2016/04/06 PHP
PHP简单日历实现方法
2016/07/20 PHP
Thinkphp5 微信公众号token验证不成功的原因及解决方法
2017/11/12 PHP
php获得刚插入数据的id 的几种方法总结
2018/05/31 PHP
网页中CDATA标记的说明
2010/09/12 Javascript
在JQuery dialog里的服务器控件 事件失效问题
2010/12/08 Javascript
探讨JavaScript中声明全局变量三种方式的异同
2013/12/03 Javascript
jquery实现标题字体变换的滑动门菜单效果
2015/09/07 Javascript
简单实现限制uploadify上传个数
2015/11/16 Javascript
详解js中class的多种函数封装方法
2016/01/03 Javascript
关于安卓手机微信浏览器中使用XMLHttpRequest 2上传图片显示字节数为0的解决办法
2016/05/17 Javascript
validationEngine 表单验证插件使用实例代码
2017/06/15 Javascript
windows下更新npm和node的方法
2017/11/30 Javascript
JS实现获取自定义属性data值的方法示例
2018/12/19 Javascript
详解vue-cli+es6引入es5写的js(两种方法)
2019/04/19 Javascript
微信小程序实现音乐播放器
2019/11/20 Javascript
Python中用startswith()函数判断字符串开头的教程
2015/04/07 Python
Python统计纯文本文件中英文单词出现个数的方法总结【测试可用】
2018/07/25 Python
numpy 计算两个数组重复程度的方法
2018/11/07 Python
详解CSS3 用border写 空心三角箭头 (两种写法)
2017/09/29 HTML / CSS
ManoMano英国:欧洲第一家专注于DIY和园艺市场的电商平台
2020/03/12 全球购物
北大青鸟学生求职信
2013/09/24 职场文书
机械工程系毕业生求职信
2013/09/27 职场文书
酒店值班经理的工作职责范本
2014/02/18 职场文书
运动会口号大全
2014/06/07 职场文书
镇政府副镇长群众路线专题民主生活会对照检查材料
2014/09/19 职场文书
2014年档案管理工作总结
2014/11/17 职场文书
2014年药店工作总结
2014/11/20 职场文书
2017元旦晚会开幕词
2016/03/03 职场文书
分析Netty直接内存原理及应用
2021/06/14 Java/Android
python数字转对应中文的方法总结
2021/08/02 Python