add: 添加胜利棋数的配置

上级 dde5b676
<script setup> <script setup>
import { onMounted, reactive, ref } from "vue" import { onMounted, ref } from "vue"
import { checkWin, findBestMove } from "./utils" import { checkWin } from "./utils"
// 配置 // 配置
const con = reactive({ const size = ref(20)
width: 20, const winSize = ref(5)
height: 20
})
const lattices = ref([]) const lattices = ref([])
// let nextPlay = 'isBlack' // isWhite let nextPlay = 'isBlack' // isWhite
// 5 连珠的下标 // 5 连珠的下标
let isWin = [] let isWin = []
onMounted(confirm) onMounted(confirm)
function confirm() { function confirm() {
const { width, height } = con
isWin = [] isWin = []
lattices.value = Array(height).fill([]).map(item => Array(width).fill(null)) nextPlay = 'isBlack';
lattices.value = Array(size.value).fill([]).map(() => Array(size.value).fill(null))
} }
// 玩家下棋 // 玩家下棋
function playChess(item, r_i, c_i) { function playChess(item, r_i, c_i) {
if (isWin.length || item) return if (isWin.length || item) return
lattices.value[r_i][c_i] = 'isBlack' lattices.value[r_i][c_i] = nextPlay
const test = checkWin(r_i, c_i, lattices.value) const test = checkWin({ row: r_i, col: c_i, board: lattices.value, player: nextPlay, winSize: winSize.value })
if (test) { if (test) {
isWin = test isWin = test
} else { return
robotMove()
} }
} nextPlay = nextPlay == 'isWhite' ? 'isBlack' : 'isWhite'
function robotMove() {
const [bestRow, bestCol] = findBestMove(lattices.value, "isWhite");
console.log(bestRow, bestCol)
// lattices.value[bestRow][bestCol] = "isWhite";
/* const testRobot = checkWin(lattices.value)
if (testRobot) {
isWin = testRobot
} */
} }
...@@ -50,14 +38,14 @@ function getStyle(item, r_i, c_i) { ...@@ -50,14 +38,14 @@ function getStyle(item, r_i, c_i) {
</script> </script>
<template> <template>
<div class="content flex-between"> <div class="content flex-start">
<p class="flex-between"> <p class="flex-between mr-6px">
<label></label> <label>棋盘大小</label>
<input v-model="con.height" type="number"> <input v-model="size" type="number">
</p> </p>
<p class="flex-between"> <p class="flex-between mr-6px">
<label></label> <label>胜利棋数</label>
<input v-model="con.width" type="number"> <input v-model="winSize" type="number">
</p> </p>
<button @click="confirm">重新开始</button> <button @click="confirm">重新开始</button>
</div> </div>
......
...@@ -23,6 +23,16 @@ ...@@ -23,6 +23,16 @@
align-items: center; align-items: center;
} }
.flex-start {
display: flex;
justify-content: start;
align-items: center;
}
.mr-6px {
margin-right: 6px;
}
input { input {
width: 60px; width: 60px;
} }
...@@ -59,6 +69,7 @@ input { ...@@ -59,6 +69,7 @@ input {
position: absolute; position: absolute;
top: calc(50% - 1px); top: calc(50% - 1px);
left: 0; left: 0;
font-size: 20px;
} }
.col::before { .col::before {
...@@ -71,17 +82,34 @@ input { ...@@ -71,17 +82,34 @@ input {
top: 0; top: 0;
} }
.isWhite::after,
.isBlack::after,
.isWin::after {
border-radius: 50%;
width: 90%;
height: 90%;
top: calc((20px - 20px * 0.9) * 0.5);
left: calc((20px - 20px * 0.9) * 0.5);
border: 1px solid #999;
}
/* 竖线隐藏 */
.isWhite::before,
.isBlack::before,
.isWin::before {
display: none;
}
.isWhite::after { .isWhite::after {
content: 'O'; background-color: white;
color: brown;
} }
.isBlack::after { .isBlack::after {
content: 'O'; background-color: black;
color: black; border: 1px solid black;
} }
.isWin::after { .isWin::after {
content: 'O'; background-color: red;
color: red; border: 1px solid red;
} }
\ No newline at end of file
export function checkWin(row, col, board) { export function checkWin({ row, col, board, player, winSize }) {
const _row = board.length; const _row = board.length;
const _col = board[0].length const _col = board[0].length
const pieceType = board[row][col] const pieceType = player ?? board[row][col]
const directions = [ const directions = [
[1, 0], // 水平方向 [1, 0], // 水平方向
...@@ -12,14 +12,14 @@ export function checkWin(row, col, board) { ...@@ -12,14 +12,14 @@ export function checkWin(row, col, board) {
]; ];
for (let i = 0; i < directions.length; i++) { for (let i = 0; i < directions.length; i++) {
const res = [[row, col]];
const [dx, dy] = directions[i]; const [dx, dy] = directions[i];
let count = 1; // 当前位置算一个
let x = row + dx; let x = row + dx;
let y = col + dy; let y = col + dy;
// 向正反两个方向扩展,检查是否有连续的五个相同棋子 // 向正反两个方向扩展,检查是否有连续的五个相同棋子
while (x >= 0 && x < _row && y >= 0 && y < _col && board[x][y] === pieceType) { while (x >= 0 && x < _row && y >= 0 && y < _col && board[x][y] === pieceType) {
count++; res.push([x, y])
x += dx; x += dx;
y += dy; y += dy;
} }
...@@ -27,100 +27,15 @@ export function checkWin(row, col, board) { ...@@ -27,100 +27,15 @@ export function checkWin(row, col, board) {
x = row - dx; x = row - dx;
y = col - dy; y = col - dy;
while (x >= 0 && x < _row && y >= 0 && y < _col && board[x][y] === pieceType) { while (x >= 0 && x < _row && y >= 0 && y < _col && board[x][y] === pieceType) {
count++; res.push([x, y])
x -= dx; x -= dx;
y -= dy; y -= dy;
} }
if (count >= 5) { if (res.length >= winSize) {
return true; // 出现五连珠,返回胜利 return res; // 出现五连珠,返回胜利
} }
} }
return false; // 未出现五连珠 return false; // 未出现五连珠
} }
export const findBestMove = (boardSize, piece) => {
let bestScore = -Infinity;
let bestRow = -1;
let bestCol = -1;
const _row = boardSize.length
const _col = boardSize[0].length
for (let row = 0; row < _row; row++) {
for (let col = 0; col < _col; col++) {
if (boardSize[row][col] === 0) {
boardSize[row][col] = piece;
const score = minimax(boardSize, 0, false, -Infinity, Infinity);
boardSize[row][col] = 0;
if (score > bestScore) {
bestScore = score;
bestRow = row;
bestCol = col;
}
}
}
}
return [bestRow, bestCol];
}
// 最大值搜索算法
function minimax(boardSize, depth, isMaximizingPlayer, alpha, beta) {
const _row = boardSize.length
const _col = boardSize[0].length
if (checkWin(-1, -1, playerPiece)) {
return -1; // 玩家获胜
} else if (checkWin(-1, -1, robotPiece)) {
return 1; // 机器人获胜
} else if (isGameOver()) {
return 0; // 平局
}
if (isMaximizingPlayer) {
let maxScore = -Infinity;
for (let row = 0; row < _row; row++) {
for (let col = 0; col < _col; col++) {
if (boardSize[row][col] === 0) {
boardSize[row][col] = robotPiece;
const score = minimax(depth + 1, false, alpha, beta);
boardSize[row][col] = 0;
maxScore = Math.max(maxScore, score);
alpha = Math.max(alpha, score);
if (alpha >= beta) {
break;
}
}
}
}
return maxScore;
} else {
let minScore = Infinity;
for (let row = 0; row < _row; row++) {
for (let col = 0; col < _col; col++) {
if (boardSize[row][col] === 0) {
boardSize[row][col] = playerPiece;
const score = minimax(depth + 1, true, alpha, beta);
boardSize[row][col] = 0;
minScore = Math.min(minScore, score);
beta = Math.min(beta, score);
if (alpha >= beta) {
break;
}
}
}
}
return minScore;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册