作业1: Bait游戏 实验报告
151220129 计科 吴政亿
任务一 深度优先搜索
变量简介
变量类型 变量名 变量含义 ArrayList closeList 存储已经走过的历史路径 boolean isCalculated 是否得到了能走到终点的答案 ArrayList depthFirstAction 存储dfs中的每一步动作 int nowStep 当前步骤在depthFirstAction的下标
函数简介
返回类型 函数名 传入参数 函数功能 boolean isInCloseList StateObservation obs 检测是否在历史状态中 boolean getDepthFirst StateObservation stateObs, ElapsedCpuTimer elapsedTimer 计算从stateObs出发的深度优先路径,如果找到则返回true Types.ACTIONS act StateObservation stateObs, ElapsedCpuTimer elapsedTimer 根据局面stateObs调用getDepthFirst并返回当轮动作 void debugPrint Types.ACTIONS act 输出act动作信息 void debugPrintAllAction ArrayList actions 输入actions中所有动作信息
核心代码
boolean getDepthFirst(StateObservation stateObs, ElapsedCpuTimer elapsedTimer){
if (stateObs in closeList)
return false ;
else
closeList.add(stateObs);
stCopy = stateObs.copy();
for (all actions in stateObs){
try this action in stCopy;
depthFirstAction.add(action);
if (win)
return true ;
else if (stateObs in closeList || Game over){
stCopy = stateObs.copy();
depthFirstAction.delete(action);
continue ;
}
else {
if (getDepthFirst(stCopy,elapsedTimer))
return true ;
else {
stCopy = stateObs.copy();
depthFirstAction.delete(action);
continue ;
}
}
}
return false ;
}
任务二 深度受限的深度优先搜索
变量简介
变量类型 变量名 变量含义 ArrayList closeList 存储已经走过的历史路径 ArrayList stateDepth 历史路径里对应的每一个的深度 ArrayList limitDepthFirstAction 存储limitdfs中的每一步动作 double bestCost 精灵与目标在state中最优状态的距离 Vector2d goalpos 门的位置 Vector2d keypos 钥匙的位置
函数简介
返回类型 函数名 传入参数 函数功能 void initAgent null 初始化Agent boolean isInCloseList StateObservation obs 检测是否在历史状态中 void limitDepthFirst StateObservation stateObs, ElapsedCpuTimer elapsedTimer, int depth 计算从stateObs出发的受限层数为depth的深度优先路径 Types.ACTIONS act StateObservation stateObs, ElapsedCpuTimer elapsedTimer 根据局面stateObs调用limitDepthFirst并返回当轮动作 void debugPrint Types.ACTIONS act 输出act动作信息 void debugPrintAllAction ArrayList actions 输入actions中所有动作信息 double getDistance Vector2d vec1, Vector2d vec2 返回vec1与vec2的曼哈顿距离 boolean avatarGetKey StateObservation stateObs 判断精灵是否得到钥匙 double heuristic StateObservation stateObs 启发式函数,返回局面评分 void debugPos Vector2d vec, String head 输出vec的位置信息
核心代码
protected void limitDepthFirst (StateObservation stateObs, ElapsedCpuTimer elapsedTimer, int depth){
if (Reach the end of limitDepthFirst){
nowStateScore = heuristic(stateObs);
if (nowStateScore better than bestCost)
bestAction = now actions;
return ;
}
else if (stateObs is not game start){
if (stateObs in closeList && depth same)
return ;
else {
closeList.add(stateObs);
stateDepth.add(depth);
}
}
else {
closeList.clear();
stateDepth.clear();
}
for (all actions in stateObs){
try this action in stCopy;
limitDepthFirstAction.add(action);
if (Game win) {
nowStateScore = heuristic(stateObs);
if (nowStateScore better than bestCost)
bestAction = now actions;
stCopy = stateObs.copy();
limitDepthFirstAction.delete(action);
continue ;
}
else {
limitDepthFirst(stCopy,elapsedTimer,depth);
stCopy = stateObs.copy();
limitDepthFirstAction.delete(action);
continue ;
}
}
}
任务三 A*搜索
根据自己自行测试,可以在有限时间内完成第二关与第三关的搜索并成功通关。
变量简介
变量类型 变量名 变量含义 ArrayList closeList 存储已经走过的历史路径 PriorityQueue openList 存储尚未走的已探索到的步骤 boolean getAnswer 是否得到了能走到终点的答案 ArrayList aStarAction 存储aStar中的每一步动作 Vector2d goalpos 门的位置 Vector2d keypos 钥匙的位置
函数简介
返回类型 函数名 传入参数 函数功能 void initAgent null 初始化Agent boolean isInCloseList StateObservation obs 检测是否在历史状态中 boolean isInOpenList StateObservation obs 检测是否在尚未走的已搜索到的区域中 void aStar StateObservation stateObs, ElapsedCpuTimer elapsedTimer, int depth 计算从stateObs出发的受时间限制的aStar路径 Types.ACTIONS act StateObservation stateObs, ElapsedCpuTimer elapsedTimer 根据局面stateObs调用aStar并返回当轮动作 double getDistance Vector2d vec1, Vector2d vec2 返回vec1与vec2的曼哈顿距离 boolean avatarGetKey StateObservation stateObs 判断精灵是否得到钥匙 double heuristic StateObservation stateObs 启发式函数,返回局面评分
核心代码
protected void aStar (StateObservation stateObs, ElapsedCpuTimer elapsedTimer) {
initAgent();
openList.add(startNode);
while (!openList.isEmpty())
{
Node tmp = openList.poll();
aStarAction = tmp.actions;
closeList.add(tmp.stateObs.copy());
for (all actions in stateObs){
stCopy = tmp.stateObs.copy();
try this action in stCopy;
aStarAction.add(act);
if (Game win) {
getAnswer = true ;
return ;
}
else if (Game over || stateObs in closeList) {
aStarAction.delete(action);
continue ;
}
else if (stateObs in openList){
if (new actions better than old){
refresh openList;
}
aStarAction.delete(action);
}
else {
openList.add(new Node(stCopy,heuristic(stCopy),aStarAction));
aStarAction.delete(action);
}
}
}
}
任务四 蒙特卡洛树搜索
算法框架
while (时间限制内){
treePolicy选择一个当前可达状态selected;
对子状态执行rollOut,得到得分;
从selected开始执行backUp;
}
通过mostVisitedAction返回次数最大的动作并作为结果;
函数简介
函数名 传入参数 函数功能 rollOut null 不断随机向下搜索,当游戏结束或达到递归层数后对状态评分。更新Agent得分bound后返回得分。 backUp SingleTreeNode node, double result 传入一个节点与他的得分,对这个节点与他的所有祖先节点,访问次数+1,总分+=得分。 treePolicy null 如果当前节点有子节点未访问,则返回其中一个,否则调用uct从所有子节点中选择一个。 uct null 根据子节点总分,访问次数,Agent的得分bound计算节点分数,然后选择得分最高的返回。
核心代码
uct算法作为关键,他的子节点计算方式如下:
childValue(平均估值) =
n o r m a l i z e ( c h i l d T o t a l V a l u e c h i l d V i s i t T i m e s + ϵ ) , ( ϵ = 1 ∗ 10 − 6 )
n
o
r
m
a
l
i
z
e
(
c
h
i
l
d
T
o
t
a
l
V
a
l
u
e
c
h
i
l
d
V
i
s
i
t
T
i
m
e
s
+
ϵ
)
,
(
ϵ
=
1
∗
10
−
6
)
uctValue(节点分数) =
c h i l d V a l u e + 2 ln p a r e n t V i s i t T i m e s + 1 c h i l d V i s i t T i m e s + ϵ − − − − − − − − − − − − − − − √ + ξ , ξ
c
h
i
l
d
V
a
l
u
e
+
2
ln
p
a
r
e
n
t
V
i
s
i
t
T
i
m
e
s
+
1
c
h
i
l
d
V
i
s
i
t
T
i
m
e
s
+
ϵ
+
ξ
,
ξ
是噪声
简而言之,访问次数少的,平均分高的子节点节点分数更高,更容易被roolOut选中。由于在act中我们返回的是访问次数最多的子节点作为状态,所以可以看出uct对于可能成功的子节点更友好。
运行结果