用Vue实现井字棋
用Vue实现井字棋
今天,有兴趣来写一下这个井字棋,并记录一下这一路进行更新扩展的过程。
大家应该都玩过井字棋,棋手分为O
、X
,在一个*
的格子中落子,只要能连成一条线,则代表获胜。
规则非常简单,我们直接用html
+Vue
的方式来进行
首先,如何在html
中使用vue
这个就不多说了,可以看看我的这篇文章
里面除了有引入Vue
,还引入了antd
、elementUI
两个UI
框架的示例
如何在html中使用Vue-腾讯云开发者社区-腾讯云
那么在本篇文章中,我们简单点,主要完成功能,就不再引入UI
框架了
好的继续,我们先把结构给整了,我们整简单点
一个标题,一个九宫格,一个重置按钮
那么结构代码如下
代码语言:javascript代码运行次数:0运行复制 <!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>井字棋</title>
<style>
.tic-tac-toe {
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
}
.board {
display: grid;
grid-template-columns: repeat(, 100px);
grid-gap: 5px;
}
.cell {
width: 100px;
height: 100px;
border: 1px solid #000;
display: flex;
align-items: center;
justify-content: center;
font-size: 2em;
cursor: pointer;
}
.winner {
color: green;
margin-top: 20px;
}
.resetGame {
margin: 20px;
}
</style>
</head>
<body>
<div id="app" v-cloak>
<div class="tic-tac-toe">
<h1>井字棋</h1>
<div class="board">
<div v-for="(cell, index) in board" :key="index" class="cell">
{{ cell }}
</div>
</div>
<button class="resetGame">Reset Game</button>
</div>
</div>
<script src="js/vue@..0.js"></script>
<script>
ct { createApp, ref } = Vue;
ct app = ({
setup() {
ct board = ref(Array(9).fill(null));
return {
board
};
},
});
("#app");
</script>
</body>
</html>
运行看下效果,我们得到下面这样的结构
非常简单,现在我们需要给九宫格添加点击事件,
当奇数次点击的落子,我们认为是X
玩家,偶数次落子我们视为O
玩家
点击事件,就给对应的数组赋值即可
同时,我们在落子完成后,需要进行两个判断
- 检查玩家落子是否获胜,就是看是否练成一条线
- 看看还有没有空余的格子,如果没有了,则代表平局
ct app = ({
setup() {
ct board = ref(Array(9).fill(null));
ct currentPlayer = ref('X');
ct winner = ref(null);
ct makeMove = (index) => {
// 检查格子情况
if (board.value[index] || winner.value)
return;
// 填充数组落子
board.value[index] = currentPlayer.value;
// 检查是否获胜
winner.value = checkWinner(board.value);
// 检查是否平局
if (!winner.value && !board.value.includes(null)) {
alert('平局!');
}
// 落完子后,玩家切换,变为另一位
currentPlayer.value = currentPlayer.value === 'X' ? 'O' : 'X';
};
ct checkWinner = (board) => {
// 确定所有获胜可能性的数组情况
ct lines = [
[0, 1, 2],
[, 4, 5],
[6, 7, 8],
[0, , 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];
// 通过上面的数组来判断是否获胜
for (let line of lines) {
ct [a, b, c] = line;
if (board[a] && board[a] === board[b] && board[a] === board[c]) {
return board[a];
}
}
return null;
};
return {
board,
makeMove,
winner,
};
},
});
还有我们点击九宫格,要调用makeMove()
,这在Vue
中非常简单,来添加一下
<div class="board">
<div v-for="(cell, index) in board" :key="index" class="cell" @click="makeMove(index)">
{{ cell }}
</div>
</div>
再次运行查看效果,可以看到能够正常下棋了,但还缺少了获胜提示,以及重置棋盘
我们来添加一下,首先是结构,变化成这样了
代码语言:javascript代码运行次数:0运行复制 <div id="app" v-cloak>
<div class="tic-tac-toe">
<h1>井字棋</h1>
<div class="board">
<div v-for="(cell, index) in board" :key="index" class="cell" @click="makeMove(index)">
{{ cell }}
</div>
</div>
<div v-if="winner" class="winner">
{{ winner }} wins!
</div>
<button @click="resetGame" class="resetGame">Reset Game</button>
</div>
</div>
再然后是重置棋盘事件,就是将数组清空,获胜者清空,将玩家变为X
ct resetGame = () => {
board.value = Array(9).fill(null);
winner.value = null;
currentPlayer.value = 'X';
};
对这样之后,我再看看效果,已经完成了井字棋小游戏的效果了
不知道大家有没有发现,玩井字棋很容易平局,毕竟规则太过于简单,你看上面也就百行的代码,就实现了效果
那么我们能否进行一次优化,效果如下
当对局进行第七次落子的时候,第一次的落子将会消失,如此一来将部分加大井字棋的游戏难度
说干就干,主要就是这个makeMove()
方法,同时还需要维护一个队列,用来记录前面落子的顺序,以便消除
// 落子历史队列
ct moveHistory = ref([]);
ct makeMove = (index) => {
// 检查格子情况
if (board.value[index] || winner.value)
return;
// 如果是第七次落子,移除第一次落子
if (moveHistory.value.length === 6) {
ct firstMoveIndex = moveHistory.value.shift();
board.value[firstMoveIndex] = null;
}
// 记录本次落子
moveHistory.value.push(index);
// 填充数组落子
board.value[index] = currentPlayer.value;
// 检查是否获胜
winner.value = checkWinner(board.value);
// 检查是否平局
if (!winner.value && !board.value.includes(null)) {
alert('平局!');
}
// 落完子后,玩家切换,变为另一位
currentPlayer.value = currentPlayer.value === 'X' ? 'O' : 'X';
};
当对局进行到第七次落子的时候,我们并不清楚即将消除的是哪个棋子,需要将其标记红棋子,以示提醒
我们直接来看下,完整的代码把
代码语言:javascript代码运行次数:0运行复制 <!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>井字棋</title>
<style>
.tic-tac-toe {
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
}
.board {
display: grid;
grid-template-columns: repeat(, 100px);
grid-gap: 5px;
}
.cell {
width: 100px;
height: 100px;
border: 1px solid #000;
display: flex;
align-items: center;
justify-content: center;
font-size: 2em;
cursor: pointer;
}
.cell.removing {
color: red;
}
.winner {
color: green;
margin-top: 20px;
}
.resetGame {
margin: 20px;
}
</style>
</head>
<body>
<div id="app" v-cloak>
<div class="tic-tac-toe">
<h1>井字棋</h1>
<div class="board">
<div v-for="(cell, index) in board" :key="index" class="cell" :class="{ removing: isRemoving(index) }" @click="makeMove(index)">
{{ cell }}
</div>
</div>
<div v-if="winner" class="winner">
{{ winner }} wins!
</div>
<button @click="resetGame" class="resetGame">Reset Game</button>
</div>
</div>
<script src="js/vue@..0.js"></script>
<script>
ct { createApp, ref } = Vue;
ct app = ({
setup() {
ct board = ref(Array(9).fill(null));
ct currentPlayer = ref('X');
ct winner = ref(null);
ct moveHistory = ref([]);
ct makeMove = (index) => {
if (board.value[index] || winner.value)
return;
// 如果是第七次落子,移除第一次落子
if (moveHistory.value.length === 6) {
ct firstMoveIndex = moveHistory.value.shift();
board.value[firstMoveIndex] = null;
}
// 记录本次落子
moveHistory.value.push(index);
board.value[index] = currentPlayer.value;
winner.value = checkWinner(board.value);
if (!winner.value && !board.value.includes(null)) {
alert('平局!');
}
currentPlayer.value = currentPlayer.value === 'X' ? 'O' : 'X';
};
ct checkWinner = (board) => {
ct lines = [
[0, 1, 2],
[, 4, 5],
[6, 7, 8],
[0, , 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];
for (let line of lines) {
ct [a, b, c] = line;
if (board[a] && board[a] === board[b] && board[a] === board[c]) {
return board[a];
}
}
return null;
};
ct resetGame = () => {
board.value = Array(9).fill(null);
winner.value = null;
currentPlayer.value = 'X';
moveHistory.value = [];
};
ct isRemoving = (index) => {
return moveHistory.value.length === 6 && moveHistory.value[0] === index;
};
return {
board,
makeMove,
winner,
resetGame,
isRemoving
};
},
});
("#app");
</script>
</body>
</html>
再来运行一下,查看下效果
通过这个案例,可以了解队列可以消除早的落子,这样的一个数据结构,主要就是先进先出;最早的落子,会优先处理
还有一个悔棋的功能,是如何做呢?
这时候要用到一个栈的数据结构,它主要是后进先出,也就是最近的一次落子,会优先处理,用来处理悔棋最合适不过了
#感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格
上一篇:【详解】Redis配置文件详解
下一篇:Go程序例子(58):时间格式化
推荐阅读
留言与评论(共有 11 条评论) |
本站网友 保险业前景 | 8分钟前 发表 |
});还有我们点击九宫格 | |
本站网友 强盗逻辑 | 23分钟前 发表 |
column; align-items | |
本站网友 玉米须的副作用 | 12分钟前 发表 |
就给对应的数组赋值即可同时 | |
本站网友 天下3冰心技能加点 | 6秒前 发表 |
flex; align-items | |
本站网友 长治美食 | 2分钟前 发表 |
makeMove | |
本站网友 国债怎么买 | 15分钟前 发表 |
要调用makeMove() | |
本站网友 永安房屋出租 | 7分钟前 发表 |
100px; border | |
本站网友 今天是农历几号 | 4分钟前 发表 |
2] | |
本站网友 鱼泡避孕 | 30分钟前 发表 |
5 | |
本站网友 狗钩虫病 | 2分钟前 发表 |
我们直接用html+Vue的方式来进行二 |