Mon Jun 26 02:15:00 UTC 2023 inscode

上级 2cfbc79d
<script setup> <script setup>
import { onMounted, ref } from "vue" 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 size = ref(20)
const winSize = ref(5) const win_size = ref(5)
const lattices = ref([]) const lattices = ref([])
let nextPlay = 'isBlack' // isWhite let nextPlay = is_black // is_white
// 5 连珠的下标 // 5 连珠的下标
let isWin = [] let isWin = []
...@@ -13,25 +13,26 @@ onMounted(confirm) ...@@ -13,25 +13,26 @@ onMounted(confirm)
function confirm() { function confirm() {
isWin = [] isWin = []
nextPlay = 'isBlack'; nextPlay = is_black;
lattices.value = Array(size.value).fill([]).map(() => Array(size.value).fill(null)) 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 if (isWin.length || item) return
lattices.value[r_i][c_i] = nextPlay lattices.value[row][col] = nextPlay
const test = checkWin({ row: r_i, col: c_i, board: lattices.value, player: nextPlay, winSize: winSize.value }) const test = checkWin({ row, col, board: lattices.value, player: nextPlay, win_size: win_size.value })
if (test) { if (test) {
isWin = test isWin = test
return 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) { 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 return item
} }
...@@ -40,14 +41,14 @@ function getStyle(item, r_i, c_i) { ...@@ -40,14 +41,14 @@ function getStyle(item, r_i, c_i) {
<template> <template>
<div class="content flex-start"> <div class="content flex-start">
<p class="flex-between mr-6px"> <p class="flex-between mr-6px">
<label>棋盘大小:</label> <label for="size" class="space-nowrap">棋盘大小:</label>
<input v-model="size" type="number"> <input v-model="size" id="size" type="number">
</p> </p>
<p class="flex-between mr-6px"> <p class="flex-between mr-6px">
<label>胜利棋数:</label> <label for="win_size" class="space-nowrap">胜利棋数:</label>
<input v-model="winSize" type="number"> <input v-model="win_size" id="win_size" type="number">
</p> </p>
<button @click="confirm">重新开始</button> <button @click="confirm" class="space-nowrap">重新开始</button>
</div> </div>
<div class="content border-top content-lattice"> <div class="content border-top content-lattice">
<p class="row" v-for="(lattice, r_i) in lattices" :key="r_i"> <p class="row" v-for="(lattice, r_i) in lattices" :key="r_i">
......
...@@ -114,6 +114,6 @@ input { ...@@ -114,6 +114,6 @@ input {
border: 1px solid red; border: 1px solid red;
} }
label { .space-nowrap {
white-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 }) { /**
const _row = board.length; * 检查四个方向连续的棋子数
const _col = board[0].length * @param {object} param
const pieceType = player ?? board[row][col] * @param {number} param.row 行
* @param {number} param.col 列
const directions = [ * @param {(null|is_white|is_black)[]} param.board 棋盘
[1, 0], // 水平方向 * @param {is_white|is_black} [param.player] 当前棋子类型
[0, 1], // 垂直方向 * @param {number} param.win_size 需要几个棋子才赢
[1, 1], // 右下方向 * @returns
[1, -1] // 左下方向 */
]; export function checkWin({ row, col, board, player, win_size }) {
const _row = board.length;
for (let i = 0; i < directions.length; i++) { const _col = board[0].length
const res = [[row, col]]; const pieceType = player ?? board[row][col]
const [dx, dy] = directions[i];
let x = row + dx; const directions = [
let y = col + dy; [1, 0], // 水平方向
[0, 1], // 垂直方向
// 向正反两个方向扩展,检查是否有连续的五个相同棋子 [1, 1], // 右下方向
while (x >= 0 && x < _row && y >= 0 && y < _col && board[x][y] === pieceType) { [1, -1] // 左下方向
res.push([x, y]) ];
x += dx;
y += dy; for (let i = 0; i < directions.length; i++) {
} const res = [[row, col]];
const [dx, dy] = directions[i];
x = row - dx; let x = row + dx;
y = col - dy; let y = col + dy;
while (x >= 0 && x < _row && y >= 0 && y < _col && board[x][y] === pieceType) {
res.push([x, y]) // 向正反两个方向扩展,检查是否有连续的五个相同棋子
x -= dx; while (x >= 0 && x < _row && y >= 0 && y < _col && board[x][y] === pieceType) {
y -= dy; res.push([x, y])
} x += dx;
y += dy;
if (res.length >= winSize) { }
return res; // 出现五连珠,返回胜利
} x = row - dx;
y = col - dy;
while (x >= 0 && x < _row && y >= 0 && y < _col && board[x][y] === pieceType) {
res.push([x, y])
x -= dx;
y -= dy;
}
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;
}
return false; // 未出现五连珠 // 获取某个方向的偏移量
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.
先完成此消息的编辑!
想要评论请 注册