返回顶部

vue3单页应用 - 五子棋

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


暂无评论