CS课程项目设计3:支持AI人机对战的井字棋游戏

发布于:2025-07-19 ⋅ 阅读:(15) ⋅ 点赞:(0)

本课程项目专栏的第一篇文章就介绍了交互友好的井字棋游戏,具体内容可以参考以下这篇帖子:

CS课程项目设计1:交互友好的井字棋游戏_井字棋人机交互-CSDN博客https://blog.csdn.net/weixin_36431280/article/details/149309500?spm=1001.2014.3001.5501随着人工智能的火热,后面突然想到可以尝试加入AI人机对战的功能,本质上就是引入强化学习的概念了,这也是现在大模型领域比较关心的方向了。


今天要分享的是第三个CS课程项目:支持AI人机对战的井字棋游戏,向现有的井字棋游戏代码中添加 AI 对战功能,并且让 AI 的思考下棋时间不超过 10 秒钟,我们可以采用 Minimax 算法来实现 AI 的决策逻辑,同时使用threading模块来限制 AI 的思考时间。

1. 研究背景

井字棋(Tic-Tac-Toe)是一种简单的两人对弈棋类游戏,历史悠久且规则易懂。尽管游戏本身复杂度较低(状态空间有限),但它是研究人工智能决策算法的理想实验平台。传统的井字棋游戏仅支持双人对战,而随着人工智能技术的发展,开发具有智能决策能力的 AI 对手成为可能。通过实现不同难度级别的 AI,不仅能提升游戏的趣味性,还能帮助理解基础的博弈论算法和决策模型。

在人机交互领域,开发一个具有不同难度级别的 AI 对手,可以满足不同技能水平玩家的需求,从初学者到高级玩家都能获得适当的挑战。

2. 研究目的

本项目的主要研究目的是开发一个支持人机对战的井字棋游戏,其中 AI 对手具备以下特性:

  1. 不同难度级别:实现三种难度级别(简单、中等、困难),满足不同技能水平玩家的需求。
  2. 决策时间限制:确保 AI 的决策时间不超过 10 秒,避免玩家长时间等待。
  3. 游戏体验优化:通过动画效果、音效和悔棋功能提升用户体验。
  4. 代码可扩展性:设计模块化的代码结构,便于后续添加新功能或改进 AI 算法。

通过这些目标,项目不仅提供了一个可玩的游戏,还为研究 AI 决策算法在实时交互环境中的应用提供了实践案例。

3. 技术方案

3.1 游戏框架

  • 编程语言:Python 3.8
  • GUI 库:tkinter(Python 内置库,无需额外安装)
  • 多线程处理:使用threading模块实现 AI 决策的异步执行,避免 UI 卡顿
  • 数据存储:使用 JSON 格式保存和加载游戏状态

3.2 AI 决策算法

  • Minimax 算法:用于实现困难难度的 AI,通过递归搜索游戏树找到最优解。
  • 启发式搜索:中等和简单难度的 AI 基于启发式规则,如优先占据中心位置、阻止对手连成一线等。
  • 随机策略:简单难度的 AI 引入随机性,增加失误概率,使游戏更具挑战性。

3.3 时间控制机制

  • 计时器:在 AI 决策过程中实时监控耗时,超过 10 秒时强制终止搜索并选择当前最优解。
  • 多线程执行:将 AI 决策放在独立线程中执行,确保 UI 响应性。

4. 实现流程

4.1 基础游戏框架实现

  1. 界面设计:创建 3×3 网格棋盘、玩家信息显示区和控制按钮。
  2. 游戏逻辑:实现落子、胜负判断、平局检测等核心功能。
  3. 状态管理:保存棋盘状态、当前玩家、历史记录等信息。

 其中,判断胜负和平局条件的代码如下所示:

def check_winner(self, player):
    """检查玩家是否获胜,并记录获胜的格子"""
    # 检查行
    for row in range(3):
        if all([self.board[row][col] == player for col in range(3)]):
            self.winning_cells = [(row, col) for col in range(3)]
            return True

    # 检查列
    for col in range(3):
        if all([self.board[row][col] == player for row in range(3)]):
            self.winning_cells = [(row, col) for row in range(3)]
            return True

    # 检查对角线
    if all([self.board[i][i] == player for i in range(3)]):
        self.winning_cells = [(i, i) for i in range(3)]
        return True

    if all([self.board[i][2 - i] == player for i in range(3)]):
        self.winning_cells = [(i, 2 - i) for i in range(3)]
        return True

    return False

平局和赢局的可视化界面如下图所示:

保存棋盘状态也是比较关键的一个功能,相当于可以持续保留前面几次游戏的进度,运行代码如下所示:

def save_game(self):
    """保存游戏进度"""
    if not self.move_history:
        messagebox.showinfo("提示", "游戏尚未开始,无需保存")
        return

    # 创建游戏状态字典
    game_state = {
        'board': self.board,
        'current_player': self.current_player,
        'last_move': self.last_move,
        'move_history': self.move_history,
        'winning_cells': self.winning_cells,
        'player_names': self.player_names,
        'game_active': self.game_active
    }

    # 打开文件对话框
    file_path = filedialog.asksaveasfilename(
        defaultextension=".json",
        filetypes=[("JSON files", "*.json"), ("All files", "*.*")],
        title="保存游戏进度"
    )

    if not file_path:
        return  # 用户取消了保存

    try:
        # 将游戏状态保存为JSON文件
        with open(file_path, 'w') as f:
            json.dump(game_state, f)
        messagebox.showinfo("成功", f"游戏进度已保存到 {os.path.basename(file_path)}")
    except Exception as e:
        messagebox.showerror("错误", f"保存游戏时出错: {str(e)}")

保持游戏进度的可视化界面如下图所示:

4.2 AI 决策模块实现

  1. Minimax 算法:实现完整的 Minimax 算法,用于困难难度的 AI 决策。
  2. 中等难度策略:基于启发式规则,优先选择获胜机会和阻止对手的位置,同时引入 20% 的失误概率。
  3. 简单难度策略:30% 概率随机选择位置,70% 概率使用中等难度策略。

其中,用于AI决策的Minimax 算法还附带超时检查,避免当AI难度设置为困难时,AI无法在短时间内做出决策,从而影响游戏体验,该算法实现过程如下所示:

def minimax(self, depth, is_maximizing):
    """极小极大算法,带超时检查"""
    # 检查超时
    current_time = time.time()
    if current_time - self.ai_start_time > self.ai_timeout:
        return -1 if is_maximizing else 1

    # 检查游戏状态
    if self.check_winner('O'):
        return 100 + depth  # AI获胜,深度越大分数越低,鼓励尽快获胜
    if self.check_winner('X'):
        return -100 - depth  # 玩家获胜,深度越大分数越低,阻止玩家尽快获胜
    if self.is_board_full():
        return 0  # 平局

    if depth == 0:
        return self.evaluate_board()  # 评估当前局面

    if is_maximizing:
        max_score = -float('inf')
        # 遍历所有空位
        for r in range(3):
            for c in range(3):
                if self.board[r][c] == ' ':
                    self.board[r][c] = 'O'  # AI落子
                    score = self.minimax(depth - 1, False)
                    self.board[r][c] = ' '  # 撤销落子

                    if score > max_score:
                        max_score = score
                        if depth == self.initial_depth:  # 记录最佳落子位置
                            self.best_move = (r, c)

                    # 检查超时
                    current_time = time.time()
                    if current_time - self.ai_start_time > self.ai_timeout:
                        return max_score

        return max_score
    else:
        min_score = float('inf')
        # 遍历所有空位
        for r in range(3):
            for c in range(3):
                if self.board[r][c] == ' ':
                    self.board[r][c] = 'X'  # 玩家落子
                    score = self.minimax(depth - 1, True)
                    self.board[r][c] = ' '  # 撤销落子

                    if score < min_score:
                        min_score = score

                    # 检查超时
                    current_time = time.time()
                    if current_time - self.ai_start_time > self.ai_timeout:
                        return min_score

        return min_score

AI人机对手的设置界面如下所示:

4.3 时间限制实现

  1. 计时器集成:在 AI 决策过程中记录时间,超过 10 秒时终止搜索。
  2. 多线程处理:使用threading.Thread将 AI 决策放在后台线程执行,确保 UI 响应性。

4.4 游戏体验优化

  1. 动画效果:为落子和获胜显示添加闪烁动画。
  2. 音效系统:添加落子、获胜、平局等事件的音效。
  3. 游戏功能扩展:实现悔棋、保存 / 加载游戏等功能。

其中,悔棋也是一个关键功能,实现代码如下所示:

def undo_move(self):
    """悔棋功能"""
    if not self.move_history:
        return  # 没有历史记录

    # 播放悔棋音效
    self.play_sound('undo')

    # 恢复上一步
    row, col, player = self.move_history.pop()
    self.board[row][col] = ' '
    self.buttons[row][col].config(text='', bg='SystemButtonFace')  # 恢复默认背景

    # 清除获胜高亮
    if self.winning_cells:
        for r, c in self.winning_cells:
            self.buttons[r][c].config(bg='SystemButtonFace')
        self.winning_cells = []

    # 更新上一步信息
    if self.move_history:
        last_row, last_col, last_player = self.move_history[-1]
        self.last_move = (last_row, last_col)
        self.last_move_label.config(
            text=f"上一步: {self.player_names[last_player]} 在位置 {last_row + 1},{last_col + 1}"
        )
    else:
        self.last_move = None
        self.last_move_label.config(text="上一步: 无")

    # 切换回上一个玩家
    self.current_player = player
    self.status_label.config(text=f"当前玩家: {self.player_names[self.current_player]}")

    # 重新激活游戏(如果之前结束了)
    self.game_active = True

    # 如果没有历史记录了,禁用悔棋按钮
    if not self.move_history:
        self.undo_button.config(state=tk.DISABLED)

悔棋的可视化界面如下所示:

5. 总结

本项目成功实现了一个支持 AI 人机对战的井字棋游戏,具有以下特点:

  1. 三种难度级别:通过不同的 AI 策略实现了从简单到困难的三个难度级别,满足不同玩家需求。
  2. 时间控制机制:确保 AI 决策时间不超过 10 秒,通过多线程和计时器实现。
  3. 良好的用户体验:通过动画、音效和交互功能提升了游戏的趣味性和易用性。

通过这个项目,我们验证了 Minimax 算法在简单博弈游戏中的有效性,同时展示了如何通过启发式策略和随机性创建不同难度的 AI 对手。未来可以进一步扩展该项目,例如添加更复杂的 AI 算法(如 Alpha-Beta 剪枝)、实现联网对战功能或开发移动应用版本。

6. 项目展示

前面说太多了,最后还是上传个该项目的简要演示视频,供大家了解。

支持AI人机对战的井字棋游戏


网站公告

今日签到

点亮在社区的每一天
去签到