From 3dc414d1f2ed3694c876eeaca50ee2d52ae54a2c Mon Sep 17 00:00:00 2001 From: 63db3122f0950a2aef64df95 <63db3122f0950a2aef64df95@devide> Date: Fri, 7 Jul 2023 20:44:00 +0000 Subject: [PATCH] Fri Jul 7 20:44:00 UTC 2023 inscode --- src/App.vue | 1 + src/utils/api.js | 2 +- src/utils/index.js | 91 +++++++++++++++++++++++++++------------------- 3 files changed, 55 insertions(+), 39 deletions(-) diff --git a/src/App.vue b/src/App.vue index f4832a4..8bff5b6 100644 --- a/src/App.vue +++ b/src/App.vue @@ -64,6 +64,7 @@ async function playChess(item, row, col) { setPiece([y, x], is_white) const testRobo = checkWin({ row: y, col: x, board: lattices.value, player: is_white, win_size: win_size.value }) + console.log(testRobo) if (testRobo) { isWin = testRobo } diff --git a/src/utils/api.js b/src/utils/api.js index f40451c..e54081e 100644 --- a/src/utils/api.js +++ b/src/utils/api.js @@ -11,7 +11,7 @@ import { is_empty, checkWin, is_black, is_white } from "./index" * @return {[number, number]} 返回机器人回合要落子的坐标 */ export async function robotPlay(board, player, win_size) { - const content = `这是一个五子棋游戏,${JSON.stringify(board)},只能在"${is_empty}"中选择下一步的位置,"${player}"要下到哪?请不要返回多余的文字,只返回数组,比如["x", "y"]。` + const content = `这是一个五子棋游戏,${JSON.stringify(board)},只能在"${is_empty}"中选择下一步的位置,"${player}"要下到哪?请不要返回多余的文字,只返回数组,比如[x, y]。` const body = { messages: [ { diff --git a/src/utils/index.js b/src/utils/index.js index 0a2ad7a..c935ad4 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -104,28 +104,39 @@ export function checkWin({ row, col, board, player, win_size }) { */ export function robotPlay(board, win_size) { let maxScorePos = []; - let maxScore = -1; // 空位 对每个空位进行评分 - board.map((item, row) => { - return item.map((_item, col) => { + const scores = board.map((item, row) => { + return item.flatMap((_item, col) => { if (_item === is_empty) { - let score = 0; // 评估每个空位置的价值,从八个方向去计算 - score = directions.reduce((r, [y, x]) => { - const square = getDirectionScore(board, row, col, [y, x], win_size) - return r + square - }, 0) - - // 选取分数最高的空位 - if (score >= maxScore) { - maxScorePos = [row, col]; - maxScore = score; - } + const score = directions.reduce((r, [y, x]) => { + r[is_black] += getDirectionScore(board, row, col, [y, x], win_size, is_black) + r[is_white] += getDirectionScore(board, row, col, [y, x], win_size, is_white) + return r + }, { + [is_black]: 0, + [is_white]: 0 + }) + if (score[is_black] == 0 && score[is_white] == 0) return [] + return [{ + [`${row}_${col}`]: score + }] + } else { + return [] } }) + }).flat(1) + const _scores = scores.sort((black_score, white_score) => { + const [b_s1, b_w1] = Object.values(Object.values(black_score)[0]) + const [w_s1, w_w1] = Object.values(Object.values(white_score)[0]) + const score1 = b_s1 > b_w1 ? b_s1 : b_w1 + const score2 = w_s1 > w_w1 ? w_s1 : w_w1 + return score2 - score1 }) - return maxScorePos; + console.log(_scores) + + return Object.keys(_scores[0])[0].split('_'); } /** @@ -138,13 +149,15 @@ export function robotPlay(board, win_size) { * 计算公式 10**(n) * * 是以一条线的记录积分,一个位置上正负方向为一条线 - * 同样是三颗棋子,没有挡住的比挡住一边的分数要大 * 当一个位置上 横 竖 斜 反斜 位置上都有棋子 * 积分最大为 4 * (10**8) = 400000000 * 积分最小为 4 * (10**0) = 4 * - * 连子边界判断 + * 连子边界判断,连子分 **** 和 ** ** * 判断单边,双边,连子末尾是否有障碍物 + * 相同的棋子数,没有挡住的比挡住的分数要大 10**(n) + * + * 单边,两边空位置多的那边加分 10**(n) ===== * * 黑白棋棋盘积分判断 * 比较黑白棋的棋盘最高积分,积分大的位置优先下,避免总是在防守 @@ -171,12 +184,12 @@ function getBoundary(size, num) { * @param {number} col 列 * @return {{num: number, empty_num: number}} 说明:num: 棋子个数;empty_num: 空格数量 */ -function getJoinInfo(board, row, col, [y, x]) { +function getJoinInfo(board, row, col, [y, x], player) { const ROW = board.length const COL = board[0].length // 连续棋子数 let num = 0 - // 一侧到边缘的距离 + // 一侧到边缘的空位 let empty_num = 0 // 不包括当前位置 let _row = row + y @@ -188,7 +201,7 @@ function getJoinInfo(board, row, col, [y, x]) { break; } // 连珠计数 - if (!empty_num && item === is_black) { + if (!empty_num && item === player) { num += 1 } // 计算空位数 @@ -201,7 +214,7 @@ function getJoinInfo(board, row, col, [y, x]) { return { num, - empty_num, + empty_num } } function pow(num = 0) { @@ -216,25 +229,27 @@ function pow(num = 0) { * @param {number} win_size 需要几个棋子才赢 * @returns */ -function getDirectionScore(board, row, col, [y, x], win_size) { - let res = 0 - const { num: r_num, empty_num: r_empty_num } = getJoinInfo(board, row, col, [y, x]) - const { num: l_num, empty_num: l_empty_num } = getJoinInfo(board, row, col, [y * -1, x * -1]) - - res = r_num + l_num - - // 如果是中间断掉的 1,1; 1,2; 1,3; 2,2 - if (r_num !== 0 && l_num !== 0) { - // 两边都有障碍物且小于 win_size - if (r_empty_num === 0 && l_empty_num === 0 && (r_num + l_num) < win_size) { - return 0 - } - // 一边有障碍物 - if (r_empty_num !== 0 || l_empty_num !== 0) { - // 只判断长的那边有障碍物的 +function getDirectionScore(board, row, col, [y, x], win_size, player) { + const { num: r_num, empty_num: r_empty_num } = getJoinInfo(board, row, col, [y, x], player) + const { num: l_num, empty_num: l_empty_num } = getJoinInfo(board, row, col, [y * -1, x * -1], player) + + const SIZE = r_num + l_num + // 没有棋子 + if (SIZE == 0) return 0 + // 两边有障碍物且小于 win_size + if (r_empty_num == 0 && l_empty_num == 0 && (SIZE + 1) < win_size) return 0 + + // 两边都没障碍物 + if (r_empty_num != 0 && l_empty_num != 0) { + // 单边,哪边空位置多,加分 + if ((r_num != 0 && l_num == 0 && (l_empty_num + 1) > r_empty_num) || (l_num != 0 && r_num == 0 && (r_empty_num + 1) > l_empty_num)) { + return (10 ** SIZE) * 2 } } + + // TODO:还有其他的判断,以后再做了 + // 如果位置不够 win_size,要加上当前位置 - return 10 ** res + return 10 ** SIZE } -- GitLab