在这个项目中,我们将要开发一个 Agent 来玩一个叫做“孤立(Isolation)”的游戏。孤立是一个二人零和对抗性游戏,两名玩家交替走子,将棋子从棋盘上的一个格子移到另一个格子。当某个格子被玩家占据后,该格子即被锁定。最先无法移动的玩家算输,由另一位玩家取胜。这些规则被写在 isolation.Board
类中。
在本项目中,每个 Agent 只能采取日字形的移动方式(如象棋中的马),即每次需移动 2 行 1 列或 1 行 2 列。移动可以跳过其他棋子,但不能超出棋盘边界。
另外,每一步都存在时间限制,若超出了时间限制则对手获胜。
需要编写的代码在 game_agent.py
中。其他文件中则包含玩家示例与评价函数、棋盘函数、和本地单元测试模板。
在 game_agent.py
中编写代码使其通过所有测试样例,并提交相应报告。代码可以通过 Udacity Project Assistant 提交。在提交后,可以收到测试样例的 success/failure 的反馈。
要编写的代码如下:
MinimaxPlayer.minimax()
: minimax 搜索AlphaBetaPlayer.alphabeta()
: 带有 alpha-beta 剪枝的 minimax 搜索AlphaBetaPlayer.get_move()
: 搜索迭代深化过程custom_score()
: 最佳位置评价算法custom_score_2()
: 位置评价算法custom_score_3()
: 位置评价算法
允许的模块有: random
, numpy
, scipy
, sklearn
, itertools
, math
, heapq
, collections
, array
, copy
, 和 operator
. (模块中的内容也可以随意使用, 如 numpy.random
.)
以下是一个游戏示例,可以通过 python sample_players.py
运行。
from isolation import Board
from sample_players import RandomPlayer
from sample_players import GreedyPlayer
# 创建游戏面板 (默认 7x7)
player1 = RandomPlayer()
player2 = GreedyPlayer()
game = Board(player1, player2)
# 玩家 1 落子 2 行 3 列,玩家 2 落子 0 行 5 列
# 显示棋盘
# .apply_move() 方法决定位置
game.apply_move((2, 3))
game.apply_move((0, 5))
print(game.to_string())
# 玩家轮流走子,所以下一个应该是玩家 1
assert(player1 == game.active_player)
# 获得玩家可选的行动列表
print(game.get_legal_moves())
# 获得一个走了一步棋之后的棋盘副本
# 并不会改变当前对象
# (而不是像 .apply_move() 那样).
new_game = game.forecast_move((1, 1))
assert(new_game.to_string() != game.to_string())
print("\nOld state:\n{}".format(game.to_string()))
print("\nNew state:\n{}".format(new_game.to_string()))
# 自动完成游戏
# 输出 "illegalmove", "timeout", 或 "forfeit"
winner, history, outcome = game.play()
print("\nWinner: {}\nOutcome: {}".format(winner, outcome))
print(game.to_string())
print("Move history:\n{!s}".format(history))
建议按以下步骤完成本项目。
单元测试在 test_game_agent.py
文件中。执行 python -m unittest
命令来进行测试 (具体参考 unittest )
运行 pip install udacity-pa
,并使用 udacity submit isolation
进行提交。在提交报告前要确保通过了所有的单元测试。
-
运行
udacity submit isolation
。(会看到测试失败的用例 -- 因为还没有开始编写) -
编写
MinimaxPlayer.minimax()
方法使其返回当前玩家可用的移动,并再次提交代码来通过 minimax 测试。 -
继续编写
MinimaxPlayer.minimax()
实现递归搜索 (参考 AIMA Minimax Decision). 再次提交代码,通过 minimax 和方法测试用例。 -
然后是 alpha beta 测试用例。编写
AlphaBetaPlayer.alphabeta()
方法使其返回当前玩家可用的移动,并再次提交代码来通过 alphabeta 测试。 -
继续编写
AlphaBetaPlayer.alphabeta()
实现递归搜索 (参考 AIMA Alpha-Beta Search). 再次提交代码,通过 alphabeta 和方法测试用例。 -
从
MinimaxPlayer.get_move()
中复制代码通过AlphaBetaPlayer.get_move()
测试。再次提交代码,通过get_move()
测试用例。 -
编写
AlphaBetaPlayer.get_move()
Iterative Deepening 通过 test_get_move 测试。参考 AIMA Iterative Deepening Search -
最后,在
custom_score()
,custom_score_2()
, 和custom_score_3()
任意一个中添加启发,通过 heuristic 测试 (测试用例只关注类型,而不会关注是否正确) 可以在sample_players.py
文件中看到示例。
tournament.py
脚本用来评价启发的有效程度。
有时限的搜索的表现和硬件相关。尝试开发一种优于 ID_Improved 的启发。
标准如下: (参考 sample_players.py
)
- Random: 随机
- MM_Open: MinimaxPlayer agent using the open_move_score heuristic with search depth 3
- MM_Center: MinimaxPlayer agent using the center_score heuristic with search depth 3
- MM_Improved: MinimaxPlayer agent using the improved_score heuristic with search depth 3
- AB_Open: AlphaBetaPlayer using iterative deepening alpha-beta search and the open_move_score heuristic
- AB_Center: AlphaBetaPlayer using iterative deepening alpha-beta search and the center_score heuristic
- AB_Improved: AlphaBetaPlayer using iterative deepening alpha-beta search and the improved_score heuristic
参考 AIND-Sudoku
在项目路径运行 udacity submit isolation
。输入用户名与密码。如果使用谷歌或脸书登录,参考 instructions for using a jwt.
这个过程会创建一个压缩文件 isolation-<id>.zip
。提交该文件即可。
isoviz
文件夹包含一个 7x7 游戏棋盘。从项目目录运行 python -m http.server 8000
来使用该棋盘 (可将 8000 替换为其他数字), 然后从浏览器进入 http://localhost:8000
并进入 /isoviz/display.html
页面。输入移动历史 (即 Board.play() 方法返回的数组) 并执行比赛。刷新页面来执行不同的游戏。
编写 competition_agent.py
并运行 :
udacity submit isolation-pvp