You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将完美井字棋Minimax算法修改为非完美AI算法?

如何将完美井字棋Minimax AI修改为非完美AI

要让AI不再总是选择最优落子,核心思路是限制Minimax的搜索深度,或在选步时加入随机概率选择次优解。结合你已添加的depth参数,具体实现步骤如下:

1. 添加启发式评估函数

当搜索达到设定的最大深度时,停止递归,用启发式函数评估当前局面的近似得分,模拟AI“无法预判全局”的情况:

#include <stdlib.h>
#include <time.h>

#define MAX_DEPTH 3 // 可调参数:数值越小,AI水平越弱

// 启发式评估:计算当前局面得分,AI为1,玩家为-1
int evaluate(int board[9]) {
    int score = 0;
    unsigned wins[8][3] = {{0,1,2},{3,4,5},{6,7,8},{0,3,6},{1,4,7},{2,5,8},{0,4,8},{2,4,6}};
    for(int i = 0; i < 8; ++i) {
        int ai_count = 0, player_count = 0;
        for(int j = 0; j < 3; ++j) {
            if(board[wins[i][j]] == 1) ai_count++;
            else if(board[wins[i][j]] == -1) player_count++;
        }
        // 根据潜在赢线数量赋值权重
        if(ai_count == 3) score += 100;
        else if(ai_count == 2 && player_count == 0) score += 10;
        else if(ai_count == 1 && player_count == 0) score += 1;
        
        if(player_count == 3) score -= 100;
        else if(player_count == 2 && ai_count == 0) score -= 10;
        else if(player_count == 1 && ai_count == 0) score -= 1;
    }
    return score;
}

2. 修改Minimax函数,加入深度限制

利用depth参数判断是否达到最大搜索深度,停止递归并返回启发式得分:

int minimax(int board[9], int player, int depth) {
    int winner = win(board);
    if(winner != 0) return winner * player;

    // 达到最大深度,返回启发式评估结果
    if(depth >= MAX_DEPTH) {
        return evaluate(board) * player; // 乘以player适配当前玩家视角
    }

    int score = -2;
    for(int i = 0; i < 9; ++i) {
        if(board[i] == 0) {
            board[i] = player;
            // 传递depth+1而非++depth,避免修改当前函数的depth变量
            int thisScore = -minimax(board, player*-1, depth + 1);
            if(thisScore > score) {
                score = thisScore;
            }
            board[i] = 0;
        }
    }
    return score == -2 ? 0 : score;
}

3. 改造ComputerMove函数,加入随机犯错逻辑

让AI有概率选择非最优解,模拟人类的失误:

void computerMove(int board[9]) {
    // 初始化随机数种子(仅首次调用执行)
    static int first_run = 1;
    if(first_run) {
        srand(time(NULL));
        first_run = 0;
    }

    int best_score = -2;
    int best_moves[9];
    int best_count = 0;

    // 先收集所有最优得分的合法移动
    for(int i = 0; i < 9; ++i) {
        if(board[i] == 0) {
            board[i] = 1;
            int tempScore = -minimax(board, -1, 0); // 初始depth从0开始
            board[i] = 0;
            if(tempScore > best_score) {
                best_score = tempScore;
                best_count = 0;
                best_moves[best_count++] = i;
            } else if(tempScore == best_score) {
                best_moves[best_count++] = i;
            }
        }
    }

    // 20%概率随机选择合法移动(非最优),80%概率选择最优移动
    if(rand() % 100 < 20) {
        int legal_moves[9];
        int legal_count = 0;
        for(int i = 0; i < 9; ++i) {
            if(board[i] == 0) legal_moves[legal_count++] = i;
        }
        int random_idx = rand() % legal_count;
        board[legal_moves[random_idx]] = 1;
    } else {
        int chosen_idx = rand() % best_count;
        board[best_moves[chosen_idx]] = 1;
    }
}

4. 修正原代码的换行符问题

将原代码中printf里的 替换为\n,否则编译会报错,例如:

void draw(int b[9]) {
    printf(" %c | %c | %c\n",gridChar(b[0]),gridChar(b[1]),gridChar(b[2]));
    printf("---+---+---\n");
    printf(" %c | %c | %c\n",gridChar(b[3]),gridChar(b[4]),gridChar(b[5]));
    printf("---+---+---\n");
    printf(" %c | %c | %c\n",gridChar(b[6]),gridChar(b[7]),gridChar(b[8]));
}

关键逻辑说明

  • 深度限制:通过MAX_DEPTH控制AI的搜索范围,数值越小,AI对后续局面的预判越短,容易做出次优选择。
  • 启发式评估:当无法继续递归时,用潜在赢线数量作为得分依据,模拟AI的“短视”判断。
  • 随机犯错:加入概率随机选择非最优解,让AI的行为更接近人类,而非始终完美。

内容的提问来源于stack exchange,提问作者poetisme

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 22:40:38