本文演示了一种根据过去的表现选择运动状态的技术。 为了使事情尽可能简单,该示例不包括数据的长期持久性(尽管您可以不费吹灰之力地添加此功能)。 我将把本技巧的范围限于代码的高级概述。 如果您想对类和方法进行更详细的说明,请参考源代码注释文档。 完整的源代码可在参考资料中找到 。
数学实用程序类
通常,机器人会严重依赖一些数学算法。 一个好的做法是为最常用的算法创建一个带有静态方法的实用程序类。
此示例的实用程序类是BotMath
类。 此类包含单个方法calculateDamage()
,用于根据子弹的力量来计算由子弹造成的伤害。
扩展AdvancedRobot类以提供发布者/订阅者支持
当我们向机器人添加状态,状态管理器和其他支持类时,他们将需要访问不同的事件。 我们可以将这些事件传递给状态管理器,然后让它们将事件传递给各个状态,但是将仅将相关事件直接传递给需要它们的对象会更有效。
ExtendedRobot
类允许对象注册以仅接收其感兴趣的事件。 EventRegistry
类包含用于注册不同事件的常量。 抽象的EventListener
类定义接收这些事件所需的方法。
除了标准的Robocode事件外, ExtendedRobot
类还生成状态管理器和状态所需的三个事件。 enable
, disable
和execute
事件直接传递给任何注册的状态管理器,它们负责将事件传递给活动状态。 在每个回合开始时调用enable()
方法; 此方法的实现应初始化变量并注册任何相关的Robocode事件。 在每个回合结束时调用disable()
方法。 此方法的实现应释放资源,并取消订阅该类当前已预订的任何Robocode事件。 每次回合都会调用execute()
方法,从而允许状态管理器和状态执行基于回合的算法。 任何需要接收这些事件的类都必须实现CommandListener
接口。
管理状态
StateManager
类负责选择最佳状态。 每转一圈,其execute()
方法都会调用当前活动状态的isValid()
方法。 如果状态的isValid()
方法返回false,则选择新状态(此过程可用于根据对手的数量等切换状态)。
选择新状态涉及的大部分工作由StateManager
的selectNewState()
方法处理。 此方法从每个候选状态请求统计数据,并对数据进行评估以选择最佳状态。 StateManager
使用两阶段方法来选择最佳状态。 首先,它尝试使用赢/输比最高的状态; 如果找不到合适的状态,则StateManager
选择损坏/时间比率最低的状态。
状态
抽象的State
类定义每个状态实现所需的方法。 它包括标准的enable()
, disable()
和execute()
方法,以及一些与状态管理器进行通信的专用方法。 getStatistics()
方法返回一个Statistics
对象,其中包含有关该州过去的表现的数据(在此示例中,该状态管理一个Statistics
对象,但是可以很容易地对其进行修改以使用HashMap
来查看对手的统计信息)。 getName()
方法返回在调试消息中使用的状态的友好名称。 isValid()
方法负责确定何时应使用状态-在状态选择期间和选择状态后的每一回合都将调用它。
每个State
类负责跟踪其执行情况并将该数据记录到其Statistics
对象。
我在源代码中包括了两个简单的示例状态: TrackState
和CannonFodderState
类提供了抽象State
类的示例实现。
统计
Statistics
类是用于跟踪状态执行情况的简单容器类。 它包含损坏率(损坏/时间),使用状态的遭遇次数,损失次数和获胜次数的变量。 它还包含用于设置和检索此数据的三种帮助方法。 update()
方法提供了一种简单的方法来设置Statistics
对象中的变量。 getDamageRatio()
和getWinLossRatio()
方法返回状态的统计数据。
为防止单个不良回合取消潜在有效状态的资格,除非统计状态数据至少在三次遭遇中使用过( Statistics
对象在此评估期间返回默认数据值),否则统计数据将不被视为有效。
放在一起
机器人的主要类别承担建立状态管理器和状态的大部分责任。 每轮必须创建状态管理器,将状态添加到状态管理器,将状态管理器注册为命令侦听器,并调用ExtendedRobot
enable()
方法来激活命令侦听器。 主机器人类还负责每转executeTurn()
调用ExtendedRobot
executeTurn()
方法(此方法调用所有已注册命令侦听器的execute()
方法)。 在每个回合结束时,主机械手类必须调用disable()
方法以允许命令侦听器正常关闭。
清单1显示了一个多状态机器人的典型run()
方法:
清单1.多状态机器人的典型run()
方法
public void run() {
try {
// Set up and enable the state manager
StateManager navigation = new StateManager(this);
navigation.addState(new CannonFodderState(this));
navigation.addState(new TrackState(this));
addCommandListener(navigation);
enable();
// Set turret to move independent of body
setAdjustGunForRobotTurn(true);
// Main bot execution loop
while(true) {
// Spin gun
setTurnGunRightRadians(Math.PI);
// Allow StateManager to do it's thing
executeTurn();
// Finish the turn
execute();
}
} finally {
// Disable the State Manager
disable();
}
}
在那里。 我意识到这实现起来相当复杂,但是它提供了两个巨大的持续优势。 该体系结构非常可扩展-您可以通过添加状态来增强功能。 此外,始终选择最佳状态的优势使机器人更具活力-更不用说击败了。
翻译自: https://www.ibm.com/developerworks/java/library/j-movement/index.html