vue實現(xiàn)五子棋游戲
本文實例為大家分享了vue實現(xiàn)五子棋游戲的具體代碼,供大家參考,具體內(nèi)容如下
思路
1.vue實現(xiàn)五子棋
空棋盤開局。
畫網(wǎng)格:網(wǎng)格有 15 行 15 列,共有 225 個交叉點
黑先、白后,交替下子,每次只能下一子
勝負判定
按照簡單的規(guī)則,從當(dāng)前下子點位的方向判斷()。如果有一個方向滿足連續(xù)5個黑子或白子,游戲結(jié)束。
2.支持dom和canvas切換
判斷瀏覽器是否支持canvas:
false: 不支持 切換dom方式
true: 支持 使用canvas
3.實現(xiàn)悔棋功能
4.實現(xiàn)撤銷悔棋
例子:
為了簡便,我就把所有寫在一起了,按理來說是要分文件寫的;
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">當(dāng)前瀏覽器不支持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, //記錄當(dāng)前步數(shù)
checkMode: [ //輸贏檢查方向模式
[1, 0], //水平
[0, 1], //豎直
[1, 1], //左斜線
[1, -1], //右斜線
],
flag: false,
victory: '',
history: [], //歷史記錄位置
historyVal: [], //歷史記錄不被刪除數(shù)組
stepHistory: 0,
domPiece:[], //
toggle: true //true為canvas,false為dom
},
mounted(){
const myCanvas = document.getElementById("myCanvas");
if (!myCanvas.getContext) {
alert("當(dāng)前瀏覽器不支持Canvas.");
this.toggle = false;
this.drawpieceBoardDom();
} else {
console.log("當(dāng)前瀏覽器支持Canvas", this.toggle)
this.drawpieceBoard();
const canvas = this.$refs.canvas;
// 添加點擊監(jiān)聽事件
canvas.addEventListener("click", e => {
if (this.flag) {
alert("游戲結(jié)束,請重新開始~");
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 數(shù)組', 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);
//檢查當(dāng)前玩家是否贏了游戲
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("當(dāng)前---------------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();
}
},
//初始化棋盤數(shù)組
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() {
//初始化棋盤數(shù)組
this.pieceArr();
//canvas 繪制
let canvas = this.$refs.canvas
// 調(diào)用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(); //開始一條路徑或重置當(dāng)前的路徑
context.arc(x, y, 15, 0, Math.PI * 2, false);
context.closePath();
context.fillStyle = color;
context.fill();
},
//勝負判斷函數(shù)
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('勝負判斷函數(shù)', count)
// console.log('color', color)
if (count >= 5) {
if (color == 'black') {
this.victory = "黑子棋方勝利!";
} else {
this.victory = "白子棋方勝利!";
}
// 游戲結(jié)束
// console.log('游戲結(jié)束')
this.flag = true;
}
},
//重畫函數(shù)
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 創(chuàng)建一個二維數(shù)組,下棋或者悔棋都操作這個數(shù)組。操作完數(shù)據(jù),把畫布全清,重新用數(shù)據(jù)畫一個棋盤。
// dom 二維數(shù)組刪除數(shù)組最后一項, 先清空棋子的填充顏色,在渲染上顏色
regret() {
if (!this.toggle) {
// console.log("-----dom------this.domPiece",this.domPiece)
if (this.history.length && !this.flag) {
this.history.pop(); //刪除數(shù)組最后一項
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("已經(jīng)不能悔棋了~")
}
} else {
if (this.history.length && !this.flag) {
this.history.pop(); //刪除數(shù)組最后一項
//重畫
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("已經(jīng)不能悔棋了~")
}
}
},
//撤銷悔棋
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;
//調(diào)用初始化棋盤數(shù)組函數(shù)
that.pieceArr();
//創(chuàng)建一個容器
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() {
//判斷游戲是否結(jié)束
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];
//寫入棋盤數(shù)組
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];
//寫入棋盤數(shù)組
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);
}
//檢查當(dāng)前是否贏了
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("游戲結(jié)束,請重新開始~");
return;
}
}
}
}
},
}
});
</script>
</body>
</html>
更多文章可以點擊《Vue.js前端組件學(xué)習(xí)教程》學(xué)習(xí)閱讀。
關(guān)于vue.js組件的教程,請大家點擊專題vue.js組件學(xué)習(xí)教程進行學(xué)習(xí)。
更多vue學(xué)習(xí)教程請閱讀專題《vue實戰(zhàn)教程》
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
一步步教你搭建VUE+VScode+elementUI開發(fā)環(huán)境
這篇文章主要給大家介紹了關(guān)于搭建VUE+VScode+elementUI開發(fā)環(huán)境的相關(guān)資料,近期被配置環(huán)境的事情弄得整個人都要炸了,現(xiàn)在整理如下,希望有相同需求的朋友可以不用走彎路,需要的朋友可以參考下2023-07-07
Vue 集成 PDF.js 實現(xiàn) PDF 預(yù)覽和添加水印的步驟
這篇文章主要介紹了如何在 Vue 中集成 Mozilla/PDF.js ,實現(xiàn)自定義的 PDF 預(yù)覽器,以及給被預(yù)覽的 PDF 添加水印2021-01-01
vue watch監(jiān)聽取不到this指向的數(shù)問題
這篇文章主要介紹了vue watch監(jiān)聽取不到this指向的數(shù)問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-09-09
簡單實現(xiàn)Vue的observer和watcher
這篇文章主要教大家如何簡單實現(xiàn)Vue的observer和watcher,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-12-12
vue-i18n結(jié)合Element-ui的配置方法
這篇文章主要介紹了vue-i18n結(jié)合Element-ui的配置方法,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2019-05-05

