<template>
<card>
<h1>五子棋</h1>
<div class="board">
<div v-for="(row, rowIndex) in board" :key="rowIndex" class="row">
<div v-for="(cell, colIndex) in row" :key="colIndex" class="cell"
@click="handleCellClick(rowIndex, colIndex)">
<div v-if="cell === 1" class="black-stone"></div>
<div v-else-if="cell === 2" class="white-stone"></div>
</div>
</div>
</div>
<button @click="undoMove" :disabled="moves.length === 0">
悔棋
</button>
<button @click="restartGame">
重开游戏
</button>
<div v-if="winner !== 0" class="winner-message">
{{ winner === 1 ? "黑棋" : '白棋' }}获胜!
</div>
</card>
</template>
<script setup>
import { ref, onMounted } from 'vue';
const boardSize = 15; // 棋盘大小
const board = ref([]); // 棋盘数组
const currentPlayer = ref(1); // 当前玩家(1代表黑子,2代表白子)
const moves = ref([]); // 落子记录
const winner = ref(0); // 获胜方(0代表无)
const winCount = 5; // 连续多少子获胜
// 初始化棋盘数组
const initBoard = () => {
for (let i = 0; i < boardSize; i++) {
const row = [];
for (let j = 0; j < boardSize; j++) {
row.push(0);
}
board.value.push(row);
}
};
// 处理落子事件
const handleCellClick = (row, col) => {
if (board.value[row][col] === 0 && winner.value === 0) {
board.value[row][col] = currentPlayer.value;
moves.value.push({ row, col });
checkWin(row, col);
currentPlayer.value = currentPlayer.value === 1 ? 2 : 1;
}
};
// 悔棋
const undoMove = () => {
if (moves.value.length > 0 && winner.value === 0) {
const lastMove = moves.value.pop();
const { row, col } = lastMove;
board.value[row][col] = 0;
currentPlayer.value = currentPlayer.value === 1 ? 2 : 1;
winner.value = 0;
}
};
// 检查是否获胜
const checkWin = (row, col) => {
const directions = [
[1, 0], // 水平方向
[0, 1], // 垂直方向
[1, 1], // 正斜方向
[1, -1] // 反斜方向
];
for (const direction of directions) {
const count = countStones(row, col, direction[0], direction[1]) +
countStones(row, col, -direction[0], -direction[1]) + 1;
if (count >= winCount) {
winner.value = currentPlayer.value;
break;
}
}
};
// 计算某个方向上的连续子数
const countStones = (row, col, dx, dy) => {
const stoneType = board.value[row][col];
let count = 0;
let newRow = row + dx;
let newCol = col + dy;
while (newRow >= 0 && newRow < boardSize &&
newCol >= 0 && newCol < boardSize &&
board.value[newRow][newCol] === stoneType) {
count++;
newRow += dx;
newCol += dy;
}
return count;
};
// 重开游戏
const restartGame = () => {
board.value = [];
moves.value = [];
currentPlayer.value = 1;
winner.value = 0;
initBoard();
};
onMounted(() => {
initBoard();
});
</script>
<style scoped>
.board {
display: flex;
flex-direction: column;
align-items: center;
background-color: bisque;
overflow: hidden;
}
.row {
display: flex;
}
.cell {
width: 30px;
height: 30px;
/* border: 1px solid #000; */
cursor: pointer;
position: relative;
margin: 4px;
}
.cell::before,
.cell::after {
content: "";
position: absolute;
background-color: #000;
}
.cell::before {
width: 2px;
height: 150%;
left: 50%;
top: 0;
transform: translateX(-50%);
}
.cell::after {
width: 150%;
height: 2px;
left: 0;
top: 50%;
transform: translateY(-50%);
}
.black-stone {
width: 100%;
height: 100%;
background-color: #000;
border-radius: 50%;
position: absolute;
z-index: 9;
}
.white-stone {
width: 100%;
height: 100%;
background-color: #fff;
border-radius: 50%;
border: #aaa 1px solid;
position: absolute;
z-index: 9;
}
button {
margin-top: 10px;
}
.winner-message {
margin-top: 10px;
font-weight: bold;
}
</style>