Files
fzu-product/4.人工智能/4.3.1.2项目:Tic-Tac-Toe井字棋.md
E1PsyCongroo bbbe90dbe2 🐞 fix(4.3人工智能导论及机器学习): 按照CS50AI课程note格式化文档
删除了大量“无辜”的无序列表
2023-09-10 14:35:46 +08:00

66 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 项目Tic-Tac-Toe 井字棋
::: warning 😋 我们为你提供了一个简单有趣的项目,帮助你进行知识巩固,请认真阅读文档内容。
如果你卡住了,请记得回来阅读文档,或请求身边人的帮助。
:::
::: tip 📥
本节附件下载 <Download url="https://cdn.xyxsw.site/code/1-Projects.zip"/>
:::
`pip3 install -r requirements.txt`
## 理解
这个项目有两个主要文件:`runner.py``tictactoe.py``tictactoe.py` 包含了玩游戏和做出最佳动作的所有逻辑。`runner.py` 已经为你实现,它包含了运行游戏图形界面的所有代码。一旦你完成了 `tictactoe.py` 中所有必需的功能,你就可以运行 `python runner.py` 来对抗你的人工智能了!
让我们打开 `tictactoe.py` 来了解所提供的内容。首先我们定义了三个变量X、O 和 EMPTY以表示游戏的可能移动。
函数 `initial_state` 返回游戏的启动状态。对于这个问题,我们选择将游戏状态表示为三个列表的列表(表示棋盘的三行),其中每个内部列表包含三个值,即 X、O 或 EMPTY。以下是我们留给你实现的功能
## 说明
实现 `player`, `actions`, `result`, `winner`, `terminal`, `utility`, 以及 `minimax`.
- `player` 函数应该以棋盘状态作为输入并返回轮到哪个玩家X 或 O
- 在初始游戏状态下X 获得第一步。随后,玩家交替进行每一个动作。
- 如果提供结束棋盘状态作为输入(即游戏已经结束),则任何返回值都是可接受的。
- `actions` 函数应该返回一组在给定的棋盘状态上可以采取的所有可能的操作。
- 每个动作都应该表示为元组 `(ij)`,其中 `i` 对应于移动的行0、1 或 2`j` 对应于行中的哪个单元格对应于移动(也是 0、1、或 2
- 可能的移动是棋盘上任何没有 X 或 O 的单元格。
- 如果提供结束棋盘状态作为输入,则任何返回值都是可接受的。
- `result` 函数以一个棋盘状态和一个动作作为输入,并且应该返回一个新的棋盘状态,而不修改原始棋盘。
- 如果 `action` 函数接受了一个无效的动作,你的程序应该<u>raise an exception</u>.
- 返回的棋盘状态应该是从原始输入棋盘,并让轮到它的玩家在输入动作指示的单元格处移动所产生的棋盘。
- 重要的是,原始棋盘应该保持不变:因为 Minimax 最终需要在计算过程中考虑许多不同的棋盘状态。这意味着简单地更新棋盘上的单元格本身并不是 `result` 函数的正确实现。在做出任何更改之前,你可能需要先对棋盘状态进行<u>deep copy</u>。
- `winner` 函数应该接受一个棋盘作为输入,如果游戏结束,则返回游戏的获胜者。
- 如果 X 玩家赢得了游戏,函数应该返回 X。如果 O 玩家赢得了比赛,函数应该返回 O。
- 一个人可以通过水平、垂直或对角连续三次移动赢得比赛。
- 你可以认为最多会有一个赢家(也就是说,没有一个棋盘会同时有两个玩家连着三个,因为这将是一个无效的棋盘状态)。
- 如果游戏没有赢家(要么是因为游戏正在进行,要么是因为比赛以平局结束),函数应该返回 `None`
- `terminal` 函数应该接受一个棋盘作为输入,并返回一个布尔值,指示游戏是否结束。
- 如果游戏结束,要么是因为有人赢得了游戏,要么是由于所有单元格都已填充而没有人获胜,则函数应返回 `True`
- 否则,如果游戏仍在进行中,则函数应返回 `False`
- `utility` 函数应接受结束棋盘状态作为输入,并输出该棋盘的分数。
- 如果 X 赢得了比赛,则分数为 1。如果 O 赢得了比赛,则分数为 -1。如果比赛以平局结束则分数为 0。
- 你可以假设只有当 `terminal(board)` 为 True 时,才会在棋盘上调用 `utility`
- `minimax` 函数应该以一个棋盘作为输入,并返回玩家在该棋盘上移动的最佳移动。
- 返回的移动应该是最佳动作 `(ij)`,这是棋盘上允许的动作之一。如果多次移动都是同样最佳的,那么这些移动中的任何一次都是可以接受的。
- 如果该棋盘是结束棋盘状态,则 `minimax` 函数应返回 `None`
对于所有接受棋盘作为输入的函数,你可以假设它是一个有效的棋盘(即,它是包含三行的列表,每行都有三个值 X、O 或 EMPTY。你不应该修改所提供的函数声明每个函数的参数的顺序或数量。、
一旦所有功能都得到了正确的实现,你就应该能够运行 `python runner.py` 并与你的人工智能进行比赛。而且,由于井字棋是双方最佳比赛的平局,你永远不应该能够击败人工智能(尽管如果你打得不好,它可能会打败你!)
## 提示
- 如果你想在不同的 Python 文件中测试你的函数,你可以用类似于 `from tictactoe import initial_state` 的代码来导入它们。
- 欢迎在 `tictactoe.py` 中添加其他辅助函数,前提是它们的名称不会与模块中已有的函数或变量名称冲突。
- alpha-beta 剪枝是可选的,这可能会让你的人工智能运行更高效!