<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>