Robocode是一个易于使用的机器人战斗模拟器,可在支持Java 2的所有平台上运行。您可以创建一个机器人,将其放置在战场上,并使其与其他开发人员创建的对手机器人进行激烈的战斗。 Robocode带有一组预制的对手,可以帮助您入门,但是一旦超出对手,您就可以与世界上最好的联盟中的世界上最好的联盟对抗,进入自己的创作。
每个Robocode参与者都使用Java语言的元素来创建自己的机器人,从而使各种开发人员(从高级初学者到高级黑客)都可以参与其中。 入门的Java开发人员可以学习以下基础知识:调用API代码,阅读Javadocs,继承,内部类,事件处理等。 高级开发人员可以在全球性挑战中调整其编程技能,以构建同类最佳的软件机器人。 在本文中,我们将介绍Robocode,并通过构建您的第一个Robocode机器人开始征服世界。 我们还将窥视使Robocode流行的迷人的“幕后”机制。
Robocode是Mathew Nelson(IBM高级技术,Internet部门的软件工程师)的创意。 首先,进入Robocode页面。 在这里,您将找到Robocode系统的最新可执行文件。 下载完发行版(位于独立的安装文件中)之后,可以使用以下命令来将软件包安装在系统上(假设您的计算机上已预先安装了Java VM(JDK 1.3.x)) , 当然):
java -jar robocode-setup.jar在安装过程中,Robocode会询问您是否要使用此外部Java VM进行机器人编译。 另一种选择是作为Robocode发行版的一部分提供的Jikes编译器。
安装后,您可以从外壳程序脚本(robocode.sh),批处理文件(robocode.bat)或桌面上的图标启动Robocode系统。 此时,战场将出现。 在这里,您可以使用菜单调用机器人编辑器和编译器。
激活Robocode时,您将看到两个相互关联的GUI窗口,它们构成Robocode的IDE:
战场 机器人编辑器图1显示了战场和实际的机器人编辑器。
战场是机器人之间进行战斗的地方。 它包含主要的模拟引擎,并允许您创建,保存和打开新的或现有的战斗。 您可以使用舞台上可用的控件来暂停和继续战斗,终止战斗,销毁任何单个机器人或获取任何机器人的统计信息。 此外,您可以从该屏幕激活机器人编辑器。
机械手编辑器是一个自定义的文本编辑器,用于编辑构成机械手的Java源文件。 它在菜单中集成了Java编译器(用于编译机器人代码)和自定义的Robot包装程序。 使用“机器人编辑器”创建并成功编译的所有机器人都位于战场上随时可以部署的位置。
Robocode中的机器人由一个或多个Java类组成。 这些类可以存档到JAR包中。 Robocode的最新版本提供了一个“ Robot Packager”,可以从战场GUI窗口中激活它。
在撰写本文时,Robocode机器人是一个图形坦克。 图2说明了典型的Robocode机器人。
请注意,机器人具有旋转枪,并且在枪的顶部是旋转雷达。 机器人车辆,枪支和雷达都可以独立旋转:在任何时候,机器人车辆,枪支和雷达都可以朝不同的方向旋转。 默认情况下,这些项目是面向车辆运动方向对齐的。
Robocode机械手的命令集全部记录在Robocode API的Javadoc中。 您会发现它们是robocode.Robot类的公共方法。 在本节中,我们将按类别介绍每个可用的命令。
让我们从移动机器人及其配件的基本命令开始:
turnRight(double degree)和turnLeft(double degree)将机器人旋转指定的度数。 ahead(double distance)和back(double distance)将机器人移动指定的像素距离; 如果机器人撞到墙壁或其他机器人,则完成这两种方法。 turnGunRight(double degree)和turnGunLeft(double degree)使喷枪转动,与车辆的方向无关。 turnRadarRight(double degree)和turnRadarLeft(double degree)将雷达置于枪支顶部,与枪支的方向(以及车辆的方向)无关。这些命令在完成之前不会将控制权返回给程序。 此外,当车辆转弯时,枪支(和雷达)的方向也会移动,除非通过调用以下方法进行另外说明:
setAdjustGunForRobotTurn(boolean flag) :如果该标志设置为true,则在车辆转弯时,喷枪将保持相同方向。 setAdjustRadarForRobotTurn(boolean flag) :如果该标志设置为true,则在车辆(和机枪)转弯时,雷达将保持相同方向。 setAdjustRadarForGunTurn(boolean flag) :如果该标志设置为true,则在枪支转动时雷达将保持相同方向。 它也将像已调用setAdjustRadarForRobotTurn(true)一样起作用。存在许多获取有关机器人的信息的方法。 以下是常用方法调用的简短列表:
getX()和getY()获取机器人的当前坐标。 getHeading() , getGunHeading()和getRadarHeading()以度为单位获取车辆,枪支或雷达的当前航向。 getBattleFieldWidth()和getBattleFieldHeight()获取当前回合的战场尺寸。掌握了如何移动机器人及其相关武器后,现在就可以考虑发射和控制伤害的任务了。 每个机器人都以默认的“能量级别”开始,并且当其能量级别降至零时被视为已销毁。 发射时,机器人最多可以使用三个单位的能量。 提供给子弹的能量越多,它将对目标机器人造成的伤害越大。 fire(double power)和fireBullet(double power)用于以指定的能量(火力)发射子弹。 调用的fireBullet()版本返回对robocode.Bullet对象的引用,该对象可在高级机器人中使用。
每当机器人移动或转动时,雷达始终处于活动状态,并且如果检测到其范围内的任何机器人,都会触发事件。 作为机器人的创建者,您可以选择处理战斗中可能发生的各种事件。 基本的Robot类具有所有这些事件的默认处理程序。 但是,您可以覆盖所有这些“不执行任何操作”默认处理程序,并实现自己的自定义操作。 以下是一些更常用的事件:
ScannedRobotEvent 。 通过重写onScannedRobot()方法来处理ScannedRobotEvent ; 当雷达检测到机器人时,将调用此方法。 HitByBulletEvent 。 通过重写onHitByBullet()方法来处理HitByBulletEvent ; 当机器人被子弹击中时,将调用此方法。 HitRobotEvent 。 通过重写onHitRobot()方法来处理HitRobotEvent ; 当您的机器人撞击另一个机器人时,将调用此方法。 HitWallEvent 。 通过重写onHitWall()方法来处理HitWallEvent ; 当您的机器人撞到墙壁时,将调用此方法。这就是我们创建一些非常复杂的机器人所需的全部知识。 您可以在Javadoc中找到其余的Robocode API,可以从战场的帮助菜单或机器人编辑器的帮助菜单中进行访问。
现在是时候运用我们的知识了。
要创建新的机器人,请启动机器人编辑器,然后选择文件 -> 新建 -> 机器人 。 系统将提示您输入机械手的名称,该名称将成为Java类名称。 在此提示符下输入DWStraight 。 接下来,系统将提示您输入一个唯一的缩写,该名称将用作机器人(及其相关Java文件)所在的软件包的名称。在此提示符下输入dw 。
机器人编辑器将显示您需要编写以控制机器人的Java代码。 清单1是您将看到的代码示例:
突出显示的区域是我们可以添加代码来控制机器人的地方:
1区 在此空间中,我们可以声明类作用域变量并设置其值。 它们将在机器人的run()方法以及您可能创建的任何其他帮助程序方法中可用。
2区 战斗管理员调用run()方法来启动机器人的生命。 它通常由两个区域(清单1中指定为Area 2和Area 3)组成,您可以在其中添加代码。 在区域2中,您将放置每个机器人实例仅运行一次的代码。 它通常用于在开始重复动作之前使机器人进入预定状态。
3区 这是典型的run()方法实现的第二部分。 在这里,在一个无尽的while循环中,我们将对机器人可能涉及的重复动作进行编程。
4区 在该区域中,您可以添加帮助程序方法,以供机器人在其run()逻辑中使用。 您也可以在其中添加任何要覆盖的事件处理程序。 例如,清单1中的代码处理ScannedRobot事件,并在雷达检测到机器人时直接向机器人触发。
对于我们的第一个机器人DWStraight,我们将更新清单2中以粗体显示的代码。
这是第一个机器人按区域进行的操作:
1区 我们没有在此机器人中指定任何类范围变量。
2区 为了使机器人进入已知状态,我们使用turnLeft(getHeading())将其旋转为面向0度。
3区 在此重复部分中,我们使用ahead(1000)将机器人向前移动到尽可能远的距离。 碰到墙壁或机器人时,它将停止。 然后我们使用turnRight(90)右转。 重复此过程后,机器人将基本上沿顺时针方向画出墙壁。
4区 在这里,除了处理自动生成的ScannedRobot事件并向直接找到的机器人射击外,我们还检测到HitByBullet事件,并在HitByBullet旋转180度(顺时针和逆时针交替旋转)。
从“机器人编辑器”菜单中,选择“ 编译器” ->“ 编译”以编译机器人代码。 我们现在准备尝试我们的第一场战斗。 切换回战场并选择菜单Battle- > New,以显示类似于图3的对话框。
将我们的机器人dw.DWStraight添加到战斗中,然后添加一个对手机器人,例如sample.SittingDuck。 点击完成 ,战斗将开始。 诚然,与SeatingDuck进行战斗并不太令人兴奋,但是您可以了解DWStraight机器人默认情况下的功能。 与样本集中的其他机器人进行实验,并了解DWStraight如何与他们竞争。
当你准备好检查另一个机器人的编码,请即与在代码分发提供的dw.DWRotater机器人代码相关的话题 。 默认情况下,此机器人将:
移到战场中心 持续旋转枪支直到检测到机器人 在检测到的机器人前方稍稍开火,每次尝试不同的角度 每当它被另一个机器人撞击时,来回快速移动。该代码很简单,我们将不在这里进行分析,但是我鼓励您尝试一下。 Robocode随附的示例软件包也为许多其他机器人提供了代码。
随着您在机器人设计方面的能力越来越强,可以包含在机器人中的代码量也会大大增加。 处理代码的模块化方法是将其分解为单独的Java类,然后使用打包程序将它们捆绑到一个单独的程序包(JAR文件)中,以将其包括在您的机器人分发中。 Robocode将自动在放置在其robots目录中的程序包中找到机械手类。
我遇到了Robocode的创建者Mathew Nelson,并询问了他创建Robocode的最初动机。 这是Mat必须分享的内容:“编写Robocode的部分动机是向世界证明,'Java速度慢'和'您不能用Java编写游戏'这样的说法已不再正确。我想我做到了它。”
任何人都可以创建Robot子类,并添加可用于构建机器人的新功能。 Robocode提供了Robot的子类AdvancedRobot ,该子类支持异步API调用。 AdvancedRobot类的描述不在本文讨论范围之内,但是我建议您在熟悉基本Robot类的操作之后尝试使用该高级类。
通过Robocode的幕后观察,您可以看到一个复杂的仿真引擎,该引擎既具有高性能(以便以逼真的速度渲染战斗)又具有灵活性(无需阻碍即可创建复杂的机器人逻辑)。 特别感谢Robocode的创建者Mathew Nelson慷慨地提供了有关仿真引擎体系结构的内部信息。
如图4所示,该仿真引擎利用了大多数现代Java VM提供的非抢占线程,并将其与JDK GUI和2D图形库提供的渲染功能相结合。
请注意,每个模拟的机器人都在其自己的Java线程上,并在适当的情况下利用VM的本机线程映射。 战斗管理器线程是系统的控制器:它协调模拟并驱动图形渲染子系统。 图形渲染子系统本身基于Java 2D和AWT。
为了缓解共享资源的潜在问题(从而可能导致模拟引擎死锁或阻塞),战斗管理器线程和机器人线程之间需要非常松散的耦合。 为了实现这种松散耦合,每个机械手线程都有自己的事件队列。 然后,在机器人自己的线程中提取并处理每个机器人的事件。 这种按线程排队有效地消除了战斗管理器线程与机器人线程之间或机器人线程本身之间的任何潜在争用。
您可以将Robocode仿真器引擎视为一个仿真器程序,该程序在运行时需要一组插件(自定义机械手)。 这套插件可以利用提供的API( robocode.Robot类的方法)。 从物理上讲,每个机械手是一个独立的Java线程,并且run()方法包含将在该线程上执行的逻辑。
机械手线程可以随时调用其父级robocoode.Robot类提供的API。 通常,这将通过Object.wait()调用来阻塞机器人线程。
战斗管理器线程管理战场上的机器人,子弹和渲染。 模拟“时钟”由战场上渲染的帧数标记。 实际帧频可由用户调整。
在典型的回合中,战斗管理器线程会唤醒每个机器人线程,然后等待机器人完成其回合(即再次调用阻塞API)。 该等待间隔通常为数十毫秒,即使是最复杂的机器人也往往仅以1或2毫秒的速度来使用当今典型的系统速度进行策略和计算。
这是战斗管理器线程执行的逻辑的伪代码:
请注意,在内部for循环中,战斗管理器线程将不会等待超过最大时间间隔。 如果机器人线程未及时调用阻塞API(通常由于某些应用程序逻辑错误或无穷循环),它将继续战斗。 SkippedTurnEvent会生成到机器人的事件队列中,以通知高级机器人。
当前实现中的渲染子系统只是一个AWT和Java 2D线程,它从战役管理器获取命令并渲染战场。 它已与系统的其余部分充分分离。 可以预见,可以在以后的版本中替换它(例如使用3-D渲染器)。 在当前的实现中,只要将Robocode应用程序最小化,就将禁用渲染,从而使仿真以更快的速度进行。
马修·纳尔逊是通过在alphaWorks上的Robocode站点承载的讨论组的Robocode用户社区紧密的反馈回路(参见相关主题 )。 许多反馈已合并到实际代码中。 Mathew已计划一些即将到来的增强功能:
具有不同对象和障碍物的自定义战场地图 基于团队的战斗 对比赛或联赛的综合支持 用户可选的坦克主体/枪支/雷达/武器样式对于最近于2001年7月12日首次亮相的项目,Robocode的成名之举简直是惊人的。 尽管可用的最新版本尚未达到1.0(在撰写本文时为0.98.2版),但它已成为全世界大学校园和公司计算机上非常流行的消遣方式。 Robocode联盟(或roboleagues联盟) Swift崛起 ,人们在此通过互联网相互交流自己的定制创作。 大学教授正在利用Robocode的教育特性,并将其纳入计算机科学课程中。 Robocode用户组,讨论列表,常见问题解答,教程和Webrings遍布整个Internet。
显然,Robocode填补了流行的游戏和教育领域的空白-为学生和午夜工程师提供了一种简单,有趣,无威胁,但具有竞争性的方式,以释放他们的创造力,并有可能实现他们的幻想来征服世界。
翻译自: https://www.ibm.com/developerworks/java/library/j-robocode/index.html
相关资源:Robocode