五子棋
demo
源码
vue
<script setup>
import { ref } from 'vue'
const data = ref([])
initData()
const player = ref(1)
function trigglePlayer() {
player.value = player.value === 1 ? 2 : 1
}
function handlePlay(rowIdx, colIdx) {
if (data.value[rowIdx][colIdx]) return
data.value[rowIdx][colIdx] = player.value
if (checkWin()) {
handleGameOver()
return
}
trigglePlayer()
}
function handleGameOver() {
setTimeout(() => {
alert(`Player ${player.value} win!`)
initData()
}, 50)
}
function initData() {
data.value = Array.from({ length: 15 }).map(_ => Array.from({ length: 15 }).fill(0))
}
function checkWin() {
if (data.value.some(checkRow)) return true
if (transMatrix(data.value).some(checkRow)) return true
if (checkDiagonal()) return true
return false
}
function checkRow(row) {
let count = 0
for (let i = 0; i < row.length; i++) {
const cell = row[i]
if (cell === player.value) {
count++
if (count === 5) return true
} else {
count = 0
}
}
return false
}
function transMatrix(arr) {
const res = []
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr[i].length; j++) {
if (!res[j]) res[j] = []
res[j][i] = arr[i][j]
}
}
return res
}
function checkDiagonal() {
// 右上 -> 左下
for (let i = 4; i < 15; i++) {
const row = []
let rowIdx = 0, colIdx = i
while(colIdx >= 0) {
row.push(data.value[rowIdx++][colIdx--])
}
if (checkRow(row)) return true
}
for (let i = 1; i < 11; i++) {
const row = []
let rowIdx = i, colIdx = 14
while(rowIdx < 15) {
row.push(data.value[rowIdx++][colIdx--])
}
if (checkRow(row)) return true
}
// 左上 -> 右下
for (let i = 10; i >= 0; i--) {
const row = []
let rowIdx = 0, colIdx = i
while(colIdx < 15) {
row.push(data.value[rowIdx++][colIdx++])
}
if (checkRow(row)) return true
}
for (let i = 1; i < 11; i++) {
const row = []
let rowIdx = i, colIdx = 0
while(rowIdx < 15) {
row.push(data.value[rowIdx++][colIdx++])
}
if (checkRow(row)) return true
}
return false
}
</script>
<template>
<div id="panel">
<template v-for="(row, rowIdx) in data">
<div class="cell-wrap" @click="handlePlay(rowIdx, colIdx)" v-for="(cell, colIdx) in row">
<div class="cell" :class="{ black: cell === 2, white: cell === 1 }"></div>
</div>
</template>
</div>
</template>
<style>
#panel {
--cellLen: 30px;
position: relative;
display: grid;
grid-template-columns: repeat(15, var(--cellLen));
}
#panel::before {
content: '';
position: absolute;
top: calc(var(--cellLen) / 2);
left: calc(var(--cellLen) / 2);
width: calc(var(--cellLen) * 14 + 1px);
height: calc(var(--cellLen) * 14 + 1px);
background-image: linear-gradient(to right, rgba(0,0,0,0.4) 1px, transparent 1px), linear-gradient(to bottom, rgba(0,0,0,0.4) 1px, transparent 1px);
background-size: var(--cellLen) var(--cellLen);
z-index: -1;
}
.cell-wrap {
display: flex;
justify-content: center;
align-items: center;
height: var(--cellLen);
width: var(--cellLen);
min-width: 0;
min-height: 0;
}
.cell {
height: 70%;
width: 70%;
border-radius: 50%;
cursor: pointer;
user-select: none;
}
.cell.black {
background-color: #1e1e1e;
box-shadow: 0 0 4px 2px rgba(0,0,0,0.4);
}
.cell.white {
background-color: #fff;
box-shadow: 0 0 4px 2px rgba(0,0,0,0.4);
}
</style>
Last updated: