如何在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
相关产品推荐
相关产品推荐

