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

如何在UIViewController的computerPlay()中为UIKit井字棋添加多AI难度?

为UIKit井字棋游戏实现多难度AI逻辑

核心AI逻辑实现

当前你的computerPlay()仅实现随机落子,无法按「赢→堵→占中→随机」的优先级执行决策,也不支持多难度。以下是适配UIKit项目的完整解决方案:

1. 添加辅助判断函数

在xoGame类中新增用于检测获胜落子的辅助函数:

// 检测指定玩家是否能通过落子某空格获胜,返回该空格(存在则返回)
func winningMove(for playerChoices: [Box2], availableBoxes: [Box2]) -> Box2? {
    // 复用你已定义的获胜组合
    let winningCombos: [[Box2]] = [
        [.one, .two, .three], [.four, .five, .six], [.seven, .eight, .nine],
        [.one, .four, .seven], [.two, .five, .eight], [.three, .six, .nine],
        [.one, .five, .nine], [.three, .five, .seven]
    ]
    
    for combo in winningCombos {
        let missingBoxes = combo.filter { !playerChoices.contains($0) }
        // 若组合中仅缺一个空格,且该空格可用,则返回它
        if missingBoxes.count == 1, availableBoxes.contains(missingBoxes[0]) {
            return missingBoxes[0]
        }
    }
    return nil
}

2. 定义AI难度枚举

在xoGame类内部或外部添加难度枚举:

enum AIDifficulty {
    case easy, medium, hard
}

3. 重写computerPlay()函数

替换原有函数,实现分难度的决策逻辑:

func computerPlay(difficulty: AIDifficulty = .hard) {
    var availableSpaces = [UIImageView]()
    var availableBoxes = [Box2]()
    for name in Box2.allCases {
        let box = getBox(from: name.rawValue)
        if box.image == nil {
            availableSpaces.append(box)
            availableBoxes.append(name)
        }
    }
    
    guard availableBoxes.count > 0 else { return }
    
    var chosenBox: Box2?
    
    // 根据难度执行不同决策逻辑
    switch difficulty {
    case .hard:
        // 优先级1:AI直接获胜
        chosenBox = winningMove(for: computerChoices, availableBoxes: availableBoxes)
        // 优先级2:阻止玩家获胜
        if chosenBox == nil {
            chosenBox = winningMove(for: playerChoices, availableBoxes: availableBoxes)
        }
        // 优先级3:占据中间格
        if chosenBox == nil, availableBoxes.contains(.five) {
            chosenBox = .five
        }
    case .medium:
        // 中等难度:70%概率执行hard逻辑,30%随机
        if Double.random(in: 0...1) > 0.3 {
            chosenBox = winningMove(for: computerChoices, availableBoxes: availableBoxes)
            if chosenBox == nil {
                chosenBox = winningMove(for: playerChoices, availableBoxes: availableBoxes)
            }
            if chosenBox == nil, availableBoxes.contains(.five) {
                chosenBox = .five
            }
        }
    case .easy:
        // 简单难度:完全随机落子
        break
    }
    
    // 若未找到优先级落子,则随机选一个
    if chosenBox == nil {
        let randIndex = Int.random(in: 0 ..< availableBoxes.count)
        chosenBox = availableBoxes[randIndex]
    }
    
    // 执行落子操作
    if let targetBox = chosenBox {
        let targetView = getBox(from: targetBox.rawValue)
        makeChoice(targetView)
        computerChoices.append(targetBox)
        checkIfWon()
    }
}

4. 调整调用方式

在boxClicked函数中调用computerPlay时,可指定难度(示例默认用hard):

DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
    self.computerPlay(difficulty: .hard)
}

你也可以添加UI控件(如分段选择器)让用户切换难度,只需在控件回调中修改传入的difficulty参数即可。

问题解决说明

原代码缺少针对性的获胜组合检测逻辑,仅靠随机落子无法实现智能决策。新逻辑完全复用了你已有的Box2枚举和获胜组合定义,完美适配当前UIKit项目结构:

  • 困难难度会严格执行最优策略,大概率平局或获胜
  • 中等难度有概率忽略玩家的获胜机会,让你能故意输掉游戏
  • 简单难度完全随机,很容易被玩家击败

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 21:55:14