当前位置: 首页 > news >正文

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

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

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 Trueif all([self.board[i][2 - i] == player for i in range(3)]):self.winning_cells = [(i, 2 - i) for i in range(3)]return Truereturn 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 = scoreif 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_scorereturn max_scoreelse: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_scorereturn 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 = Noneself.last_move_label.config(text="上一步: 无")# 切换回上一个玩家self.current_player = playerself.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人机对战的井字棋游戏

http://www.dtcms.com/a/285658.html

相关文章:

  • 「Java EE开发指南」如何用MyEclipse创建企业应用项目?(一)
  • UniApp -- 小程序自定义导航栏组件
  • 小程序常用api
  • 2025年算法备案发号规律总结与下半年发号预测
  • js中 new Set()实例的各个api使用
  • Http请求中的特殊字符
  • iOS加固工具有哪些?项目场景下的组合策略与实战指南
  • Axios泛型参数解析与使用指南
  • 谷歌地球与ArcGIS Pro查看三维地形
  • Linux操作系统之线程:分页式存储管理
  • VR平台应该具备哪些功能?怎样选择VR平台?
  • RecyclerView与ListView深度对比分析
  • 相机光学(五十)——Depth AF
  • Visual Studio编译WPF项目生成的文件介绍
  • 相机的内外参分别指什么
  • AI生成邮件发送脚本(带附件/HTML排版)与定时爬取网站→邮件通知(价格监控原型)
  • Maven学习总结(62)—— Maven 打包瘦身和提速解决方案
  • [JS逆向] 微信小程序逆向工程实战
  • 7.18 Java基础 |
  • CentOS7/Redhat7破解Root密码(linux)
  • 进阶数据结构:红黑树
  • 解锁 Java 并发编程的奥秘:《Java 并发编程之美》中的技术亮点与难题攻克
  • Java Map 集合详解:从基础语法到实战应用,彻底掌握键值对数据结构
  • 【PTA数据结构 | C语言版】左堆的合并操作
  • 异世界历险之数据结构世界(排序(插入,希尔,堆排))
  • Webpack 项目优化详解
  • uniapp微信小程序 实现swiper与按钮实现上下联动
  • 技术演进中的开发沉思-38 MFC系列:关于打印
  • 微信小程序 wx.request() 的封装
  • 为Notepad++插上JSON格式化的翅膀