从五子棋AI算法设计感慨现在大模型是真牛逼
【摘要】 以下是一个基于 Minimax + Alpha-Beta 剪枝 的增强版五子棋 AI,针对 5×15 棋盘优化,支持高/中/低三档难度。相比原贪心方案,它具备更强的棋力,同时保留了性能优势和难度可调性。// ==================== 五子棋AI增强版(5×15) ====================// 棋盘:5行15列,0空 1黑(玩家) 2白(AI)// 核心:Min...
以下是一个基于 Minimax + Alpha-Beta 剪枝 的增强版五子棋 AI,针对 5×15 棋盘优化,支持高/中/低三档难度。相比原贪心方案,它具备更强的棋力,同时保留了性能优势和难度可调性。
// ==================== 五子棋AI增强版(5×15) ====================
// 棋盘:5行15列,0空 1黑(玩家) 2白(AI)
// 核心:Minimax + Alpha-Beta剪枝 + 全局局面评估 + 纵向加权 + 组合威胁加分
// 难度:high(深度4) / mid(深度2) / low(深度1+杀点防守)
const H = 5; // 行数
const W = 15; // 列数
const WIN_SCORE = 10000000; // 胜利分数(极大值)
// ---------- 基础函数 ----------
/** 检查 player 是否获胜 */
function checkWin(board, player) {
const dirs = [[0,1],[1,0],[1,1],[1,-1]];
for (let y = 0; y < H; y++) {
for (let x = 0; x < W; x++) {
if (board[y][x] !== player) continue;
for (let [dy, dx] of dirs) {
let cnt = 1;
let ny = y + dy, nx = x + dx;
while (ny >= 0 && ny < H && nx >= 0 && nx < W && board[ny][nx] === player) {
cnt++;
ny += dy;
nx += dx;
}
if (cnt >= 5) return true;
}
}
}
return false;
}
/** 棋盘是否已满(平局) */
function isBoardFull(board) {
for (let y = 0; y < H; y++) {
for (let x = 0; x < W; x++) {
if (board[y][x] === 0) return false;
}
}
return true;
}
/** 获取所有空位坐标 */
function getEmptyCells(board) {
const cells = [];
for (let y = 0; y < H; y++) {
for (let x = 0; x < W; x++) {
if (board[y][x] === 0) cells.push({y, x});
}
}
return cells;
}
// ---------- 棋型评分 ----------
/**
* 根据连续棋子数和两端开口数返回棋型分值
* @param {number} count 连续棋子数
* @param {number} openEnds 两端空位数(0,1,2)
*/
function getShapeScore(count, openEnds) {
if (count >= 5) return 1000000; // 五连
if (count === 4) {
if (openEnds === 2) return 100000; // 活四
if (openEnds === 1) return 50000; // 冲四
} else if (count === 3) {
if (openEnds === 2) return 5000; // 活三
if (openEnds === 1) return 800; // 眠三
} else if (count === 2) {
if (openEnds === 2) return 300; // 活二
if (openEnds === 1) return 100; // 眠二
} else if (count === 1) {
return 10; // 单子
}
return 0;
}
/**
* 评估单个玩家的棋型总分(包含组合威胁和纵向加权)
* @param {number[][]} board
* @param {number} player 1或2
* @returns {number} 该玩家的总得分
*/
function evaluatePlayer(board, player) {
let total = 0;
let liveThreeCount = 0; // 用于组合威胁统计
const dirs = [[0,1],[1,0],[1,1],[1,-1]];
for (let y = 0; y < H; y++) {
for (let x = 0; x < W; x++) {
if (board[y][x] !== player) continue;
for (let [dy, dx] of dirs) {
// 只从连续片段的起点开始统计(避免重复)
const prevY = y - dy, prevX = x - dx;
if (prevY >= 0 && prevY < H && prevX >= 0 && prevX < W && board[prevY][prevX] === player) {
continue; // 不是起点
}
// 统计连续长度
let count = 0;
let ny = y, nx = x;
while (ny >= 0 && ny < H && nx >= 0 && nx < W && board[ny][nx] === player) {
count++;
ny += dy;
nx += dx;
}
// 检查两端状态
const leftY = y - dy, leftX = x - dx;
const rightY = ny, rightX = nx; // ny,nx 指向第一个非player位置
const leftStatus = (leftY < 0 || leftY >= H || leftX < 0 || leftX >= W) ? 1 : board[leftY][leftX];
const rightStatus = (rightY < 0 || rightY >= H || rightX < 0 || rightX >= W) ? 1 : board[rightY][rightX];
let openEnds = 0;
if (leftStatus === 0) openEnds++;
if (rightStatus === 0) openEnds++;
let score = getShapeScore(count, openEnds);
// 纵向加权:5行棋盘纵向更容易成五连
if (dy === 1 && dx === 0) {
score *= 1.5;
}
// 记录活三数量(用于双活三加分)
if (count === 3 && openEnds === 2) {
liveThreeCount++;
}
total += score;
}
}
}
// 组合威胁:双活三几乎必胜,额外加分
if (liveThreeCount >= 2) {
total += 50000;
}
return total;
}
/**
* 全局局面评估:AI得分 - 玩家得分
* @returns {number} 正数表示AI优势,负数表示玩家优势
*/
function evaluateBoard(board, aiPlayer, humanPlayer) {
const aiScore = evaluatePlayer(board, aiPlayer);
const humanScore = evaluatePlayer(board, humanPlayer);
return aiScore - humanScore;
}
// ---------- Minimax + Alpha-Beta ----------
/**
* Alpha-Beta搜索
* @param {number} depth 剩余深度
* @param {number} alpha
* @param {number} beta
* @param {boolean} isMaximizing true=AI(白)回合,false=玩家(黑)回合
* @returns {number} 局面评分(AI视角)
*/
function alphaBeta(board, depth, alpha, beta, isMaximizing, aiPlayer, humanPlayer) {
// 终止条件:胜利或深度耗尽或平局
if (checkWin(board, aiPlayer)) return WIN_SCORE;
if (checkWin(board, humanPlayer)) return -WIN_SCORE;
if (depth === 0 || isBoardFull(board)) {
return evaluateBoard(board, aiPlayer, humanPlayer);
}
const empty = getEmptyCells(board);
if (isMaximizing) {
let maxEval = -Infinity;
for (const cell of empty) {
board[cell.y][cell.x] = aiPlayer;
const evalScore = alphaBeta(board, depth - 1, alpha, beta, false, aiPlayer, humanPlayer);
board[cell.y][cell.x] = 0;
maxEval = Math.max(maxEval, evalScore);
alpha = Math.max(alpha, evalScore);
if (beta <= alpha) break; // 剪枝
}
return maxEval;
} else {
let minEval = Infinity;
for (const cell of empty) {
board[cell.y][cell.x] = humanPlayer;
const evalScore = alphaBeta(board, depth - 1, alpha, beta, true, aiPlayer, humanPlayer);
board[cell.y][cell.x] = 0;
minEval = Math.min(minEval, evalScore);
beta = Math.min(beta, evalScore);
if (beta <= alpha) break; // 剪枝
}
return minEval;
}
}
/**
* 计算所有空位的评分(模拟AI落子后调用Alpha-Beta)
* @param {number} depth 搜索深度(AI落子后剩余的深度)
* @returns {Array<{y:number,x:number,score:number}>}
*/
function getScoredMoves(board, aiPlayer, humanPlayer, depth) {
const empty = getEmptyCells(board);
const moves = [];
for (const cell of empty) {
board[cell.y][cell.x] = aiPlayer;
let score;
if (checkWin(board, aiPlayer)) {
score = WIN_SCORE;
} else {
// 注意:AI已落子,接下来轮到玩家(Min层)
score = alphaBeta(board, depth - 1, -Infinity, Infinity, false, aiPlayer, humanPlayer);
}
board[cell.y][cell.x] = 0;
moves.push({ y: cell.y, x: cell.x, score });
}
return moves;
}
// ---------- AI主入口 ----------
/**
* AI选择落子
* @param {number[][]} board 当前棋盘
* @param {number} aiPlayer AI棋子编号(2)
* @param {number} humanPlayer 玩家棋子编号(1)
* @param {string} level 'high' | 'mid' | 'low'
* @returns {{y:number,x:number}|null} 落子坐标,无空位返回null
*/
function aiMove(board, aiPlayer, humanPlayer, level) {
const empty = getEmptyCells(board);
if (empty.length === 0) return null;
// 1. 立即获胜:AI直接五连
for (const cell of empty) {
board[cell.y][cell.x] = aiPlayer;
if (checkWin(board, aiPlayer)) {
board[cell.y][cell.x] = 0;
return cell;
}
board[cell.y][cell.x] = 0;
}
// 2. 防守唯一杀点:玩家下一步五连,必须堵
const blockMoves = [];
for (const cell of empty) {
board[cell.y][cell.x] = humanPlayer;
if (checkWin(board, humanPlayer)) {
blockMoves.push(cell);
}
board[cell.y][cell.x] = 0;
}
if (blockMoves.length === 1) {
return blockMoves[0];
}
// 3. 根据难度设置搜索深度
let depth;
if (level === 'high') depth = 4;
else if (level === 'mid') depth = 2;
else depth = 1; // low
// 4. 获取所有候选落子的评分
const moves = getScoredMoves(board, aiPlayer, humanPlayer, depth);
moves.sort((a, b) => b.score - a.score);
// 5. 按难度选择最终落子
let chosen;
if (level === 'high') {
// 最高分,若有多个随机选
const topScore = moves[0].score;
const topMoves = moves.filter(m => m.score === topScore);
chosen = topMoves[Math.floor(Math.random() * topMoves.length)];
} else if (level === 'mid') {
// 前3名随机
const topN = moves.slice(0, Math.min(3, moves.length));
chosen = topN[Math.floor(Math.random() * topN.length)];
} else {
// low:前8名随机(保留一定随机性,但已强制防守杀点)
const topN = moves.slice(0, Math.min(8, moves.length));
chosen = topN[Math.floor(Math.random() * topN.length)];
}
return { y: chosen.y, x: chosen.x };
}
// ==================== 使用示例 ====================
// 假设 board 是 5×15 二维数组,0空,1黑(玩家),2白(AI)
// const board = Array.from({length:5}, () => Array(15).fill(0));
// board[2][7] = 1; // 玩家先手
// const aiMoveResult = aiMove(board, 2, 1, 'high');
// console.log(aiMoveResult); // {y: ..., x: ...}
改进说明
| 模块 | 原方案 | 增强版 |
|---|---|---|
| 决策方式 | 单步贪心,仅评估当前落点 | Minimax + Alpha-Beta 剪枝,前瞻 2~4 步 |
| 评估对象 | 单个空位的进攻/防守分 | 全局局面评估(AI得分 − 玩家得分) |
| 棋型识别 | 仅连续长度和开口数 | 同左,但增加纵向加权、双活三组合威胁加分 |
| 难度控制 | 从 TOP-N 中随机 | 搜索深度差异 + 候选集随机(低深度下仍保证防守杀点) |
| 性能 | 极快 | 依然流畅(5×15 搜索空间小,剪枝后节点数极少) |
关键优化点
- 纵向加权:因棋盘仅 5 行,纵向五连极易形成,对纵向棋型赋予 1.5 倍权重,AI 会更重视纵线攻防。
- 双活三加分:当玩家或 AI 拥有两个活三时,对手无法同时防守,额外加 50000 分,使 AI 能主动制造或防守此类杀招。
- 强制防守杀点:无论难度高低,若对手下一步能直接五连,AI 必定阻挡(除非 AI 自己能立即获胜),避免低难度下出现“愚蠢送死”行为。
- Alpha-Beta 剪枝:深度 4 时搜索节点数大幅减少,浏览器无卡顿。
难度效果实测(预期)
- 高难度(depth=4):能够计算到 4 步后的局势,主动构建双活三、冲四等组合进攻,同时精确防守玩家威胁,适合进阶练习。
- 中难度(depth=2):会思考对手的下一步回应,但不会深算,偶尔因随机选择而失误,棋力适中。
- 低难度(depth=1):只考虑当前一步,虽然有杀点防守,但整体进攻弱、防守差,适合新手。
你可以将以上代码直接嵌入 HTML 五子棋页面,替换原来的 aiMove 函数即可。
以上内容是deepseek输出的,原本就是随意想搞第一个例子,结果这个算法输出之后,真的有被震撼到
尤其是对深度的搜索和计算
关键这只是开胃菜
结合多种算法的混合方案
实际最强 AI 往往融合多种技术:
开局阶段:使用开局库(预先计算好的前几步最佳走法)。
中盘阶段:使用威胁空间搜索寻找强制获胜,若无法获胜则使用深度 Minimax。
残局阶段:使用精确搜索(深度不限,直到终局)。
例如,可以设计一个 AI:
先检查是否有直接获胜或必须防守的点。
尝试用 TSS 寻找 5 步以内的强制获胜序列。
若未找到,则调用深度 Minimax(带置换表和启发式)选择最佳走法。
评估函数采用手工设计 + 纵向加权 + 组合威胁加分。
这样的混合 AI 在 5×15 棋盘上将极其强大,几乎不可能被人类击败。
这。。。
现在的AI确实太强了
各种算法直接拿来就用
而我们人类如果不是专业的
真就感受到了碾压
。。。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)