Mon Jun 26 02:15:00 UTC 2023 inscode

上级 2cfbc79d
<script setup>
import { onMounted, ref } from "vue"
import { checkWin } from "./utils"
import { is_empty, checkWin, robotPlay, is_black, is_white } from "./utils"
// 配置
const size = ref(20)
const winSize = ref(5)
const win_size = ref(5)
const lattices = ref([])
let nextPlay = 'isBlack' // isWhite
let nextPlay = is_black // is_white
// 5 连珠的下标
let isWin = []
......@@ -13,25 +13,26 @@ onMounted(confirm)
function confirm() {
isWin = []
nextPlay = 'isBlack';
lattices.value = Array(size.value).fill([]).map(() => Array(size.value).fill(null))
nextPlay = is_black;
lattices.value = Array(size.value).fill([]).map(() => Array(size.value).fill(is_empty))
}
// 玩家下棋
function playChess(item, r_i, c_i) {
function playChess(item, row, col) {
if (isWin.length || item) return
lattices.value[r_i][c_i] = nextPlay
const test = checkWin({ row: r_i, col: c_i, board: lattices.value, player: nextPlay, winSize: winSize.value })
lattices.value[row][col] = nextPlay
const test = checkWin({ row, col, board: lattices.value, player: nextPlay, win_size: win_size.value })
if (test) {
isWin = test
return
} else {
}
nextPlay = nextPlay == 'isWhite' ? 'isBlack' : 'isWhite'
nextPlay = nextPlay == is_white ? is_black : is_white
}
function getStyle(item, r_i, c_i) {
function getStyle(item, row, col) {
if (isWin.length) {
return isWin.map(([r, c]) => `${r}_${c}`).includes(`${r_i}_${c_i}`) ? 'isWin' : item
return isWin.map(([r, c]) => `${r}_${c}`).includes(`${row}_${col}`) ? 'isWin' : item
}
return item
}
......@@ -40,14 +41,14 @@ function getStyle(item, r_i, c_i) {
<template>
<div class="content flex-start">
<p class="flex-between mr-6px">
<label>棋盘大小:</label>
<input v-model="size" type="number">
<label for="size" class="space-nowrap">棋盘大小:</label>
<input v-model="size" id="size" type="number">
</p>
<p class="flex-between mr-6px">
<label>胜利棋数:</label>
<input v-model="winSize" type="number">
<label for="win_size" class="space-nowrap">胜利棋数:</label>
<input v-model="win_size" id="win_size" type="number">
</p>
<button @click="confirm">重新开始</button>
<button @click="confirm" class="space-nowrap">重新开始</button>
</div>
<div class="content border-top content-lattice">
<p class="row" v-for="(lattice, r_i) in lattices" :key="r_i">
......
......@@ -114,6 +114,6 @@ input {
border: 1px solid red;
}
label {
.space-nowrap {
white-space: nowrap;
}
\ No newline at end of file
export const is_empty = null;
export const is_white = 'isWhite';
export const is_black = 'isBlack';
export function checkWin({ row, col, board, player, winSize }) {
/**
* 检查四个方向连续的棋子数
* @param {object} param
* @param {number} param.row 行
* @param {number} param.col 列
* @param {(null|is_white|is_black)[]} param.board 棋盘
* @param {is_white|is_black} [param.player] 当前棋子类型
* @param {number} param.win_size 需要几个棋子才赢
* @returns
*/
export function checkWin({ row, col, board, player, win_size }) {
const _row = board.length;
const _col = board[0].length
const pieceType = player ?? board[row][col]
......@@ -32,10 +45,107 @@ export function checkWin({ row, col, board, player, winSize }) {
y -= dy;
}
if (res.length >= winSize) {
if (res.length >= win_size) {
return res; // 出现五连珠,返回胜利
}
}
return false; // 未出现五连珠
}
// 机器人下棋
export function robotPlay(board, player, win_size) {
const maxScorePos = {};
let maxScore = -1;
const opponent = (player === is_black) ? is_white : is_black;
// 空格位置
const empty_points = board.map((item, row) => {
return item.flatMap((_item, col) => _item === is_empty ? [row, col] : [])
}).flat(2)
// 对每个空位进行评分
empty_points.forEach((point) => {
let score = 0;
const [i, j] = point;
// 判断下子后是否获胜
board[i][j] = player;
const win = checkWin({ row: i, col: j, board, player, win_size });
if (win) {
score = Infinity;
} else {
// 判断对手是否能在下一步获胜,如果能,则这个点的分数为 0
board[i][j] = opponent;
const oppWin = checkWin({ row: i, col: j, board, player: opponent, win_size });
if (oppWin) {
score = 0;
} else {
// 计算当前棋盘局面的得分
const horizontal = countPieces({ row: i, col: j, board, player, win_size, direction: "horizontal" });
const vertical = countPieces({ row: i, col: j, board, player, win_size, direction: "vertical" });
const diagonalDown = countPieces({ row: i, col: j, board, player, win_size, direction: "diagonalDown" });
const diagonalUp = countPieces({ row: i, col: j, board, player, win_size, direction: "diagonalUp" });
score = Math.max(horizontal, vertical, diagonalDown, diagonalUp);
}
}
board[i][j] = null; // 恢复棋盘状态
// 选取分数最高的空位
if (score > maxScore) {
maxScorePos.x = i;
maxScorePos.y = j;
maxScore = score;
}
});
return [maxScorePos.x, maxScorePos.y];
}
// 计算某个位置在某个方向上的连续棋子个数
function countPieces({ row, col, board, player, win_size, direction }) {
const _row = board.length;
const _col = board[0].length;
const pieceType = player ?? board[row][col];
const [dx, dy] = getDirection(direction);
let x = row + dx;
let y = col + dy;
let count = 0;
while (x >= 0 && x < _row && y >= 0 && y < _col && board[x][y] === pieceType) {
count++;
x += dx;
y += dy;
}
x = row - dx;
y = col - dy;
while (x >= 0 && x < _row && y >= 0 && y < _col && board[x][y] === pieceType) {
count++;
x -= dx;
y -= dy;
}
if (count < win_size - 1) {
count = 0; // 不足以形成连续的五个棋子,得分清零
}
return count;
}
// 获取某个方向的偏移量
function getDirection(direction) {
switch (direction) {
case "horizontal":
return [0, 1];
case "vertical":
return [1, 0];
case "diagonalDown":
return [1, 1];
case "diagonalUp":
return [1, -1];
default:
return [0, 0];
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册