<script lang="ts" setup>
import { nextTick, onMounted, ref } from 'vue';
// contrants
const BORDER_LINES_NUM_FIFTEEN = 15;
const BORDER_PADDING_TWENTY = 20;
const BORDER_GRID_LENGTH_FORTY = 40;
const BORDER_LENGTH = 600 - BORDER_PADDING_TWENTY;
// variable
const borderRef = ref<HTMLCanvasElement>();
const context = ref<CanvasRenderingContext2D>()
const borderTop = ref(0);
const borderLeft = ref(0)
onMounted(() => {
drawBorder()
initChecks()
const rect = borderRef.value.getBoundingClientRect();
borderTop.value = rect.top;
borderLeft.value = rect.left;
})
function getContext() {
context.value = (borderRef.value as HTMLCanvasElement).getContext('2d') as CanvasRenderingContext2D;
}
function drawBorder() {
getContext();
// 画竖线
for (let i = 0; i < BORDER_LINES_NUM_FIFTEEN; i++) {
const positionY = BORDER_PADDING_TWENTY + i * BORDER_GRID_LENGTH_FORTY
context.value.beginPath();
context.value.moveTo(BORDER_PADDING_TWENTY, positionY);
context.value.lineTo(BORDER_LENGTH, positionY);
context.value.stroke();
context.value.closePath();
}
// 画横线
for (let index = 0; index < BORDER_LINES_NUM_FIFTEEN; index++) {
const positionX = BORDER_PADDING_TWENTY + index * BORDER_GRID_LENGTH_FORTY;
context.value.beginPath();
context.value.moveTo(positionX, 20);
context.value.lineTo(positionX, BORDER_LENGTH);
context.value.stroke();
context.value.closePath();
}
}
const isBlack = ref(true);
const cheeks = ref<number[][]>([]);
function initChecks() {
for(let i = 0; i < BORDER_LINES_NUM_FIFTEEN; i++) {
cheeks.value[i] = new Array(BORDER_LINES_NUM_FIFTEEN).fill(0);
}
}
async function handleClick(e: MouseEvent) {
const { clientX, clientY } = e;
const x = Math.round((clientX - borderLeft.value - 20) / 40) * 40 + 20
const y = Math.round((clientY - borderTop.value - 20) / 40) * 40 + 20
//
const cheeksX = (x - 20) / 40;
const cheeksY = (y - 20) / 40;
if (cheeks.value[cheeksY][cheeksX]) {
return
}
cheeks.value[cheeksY][cheeksX] = isBlack.value ? 1 : 2;
context.value?.beginPath();
context.value?.arc(x, y, 20, 0, 2 * Math.PI);
context.value!.fillStyle = (isBlack.value ? 'black' : 'white');
context.value?.fill()
context.value?.closePath();
if (isWin(cheeksX, cheeksY)) {
console.log('赢了!')
// 重新开局
context.value?.clearRect(0, 0, 600, 600)
drawBorder();
initChecks();
if (!isBlack.value) {
isBlack.value = true
}
} else {
isBlack.value = !isBlack.value;
}
}
function isWin(x: number, y: number) {
const flag = isBlack.value ? 1 : 2;
// 竖排五子
if (up_down(x, y, flag)) {
return true;
}
// 横排五子
if (left_right(x, y, flag)) {
return true;
}
// /斜线五子 TODO
// \斜线五子 TODO
}
function up_down(x: number, y: number, flag: number) {
let num = 1;
for (let i = 1; i < 5; i++) {
let temY = y - i;
if (temY < 0 || cheeks.value[temY][x] !== flag) {
break;
}
if (cheeks.value[temY][x] === flag) {
num += 1
}
}
for (let i = 1; i < 5; i++) {
let temY = y + i;
if (temY > 14 || cheeks.value[temY][x] !== flag) {
break;
}
if (cheeks.value[temY][x] === flag) {
num += 1;
}
}
return num >= 5;
}
function left_right(x: number, y: number, flag: number) {
let num = 1;
for (let i = 1; i < 5; i++) {
let temX = x - i;
if (temX < 0 || cheeks.value[y][temX] !== flag) {
break;
}
if (cheeks.value[y][temX] === flag) {
num += 1
}
}
for (let i = 1; i < 5; i++) {
let temX = x + i;
if (y > 14 || cheeks.value[y][temX] !== flag) {
break;
}
if (cheeks.value[y][temX] === flag) {
num += 1;
}
}
return num >= 5;
}
</script>
<template>
<div class="demo">
<!-- TODO 按钮组 -->
<canvas ref="borderRef" id="border-canvas" width="600" height="600" @click="handleClick"></canvas>
</div>
</template>
<style>
#border-canvas {
background-color: #e3cdb0;
}
</style>