您的位置:首页 > 编程语言 > C语言/C++

在Robocode中使用Vector实现敌人列表

2005-09-04 17:22 316 查看
C++程序员,Robocode玩家,Robocode 中华联盟的成员
2002 年 11 月 26 日RoboCode的混战模式中,如何更好的掌握多个对手的情况,从而采取更好的策略,成为每一个玩家迫切需要解决的问题。而世界级的机器人大都采用了向量(vector)数组的方式来保存多个对手的信息。前言

RoboCode的混战模式中,如何更好的掌握多个对手的情况,从而采取更好的策略,成为每一个玩家迫切需要解决的问题。而世界级的机器人大都采用了向量(vector)数组的方式来保存多个对手的信息。
而且vector的作用不止于此,上届世界冠军Yngwie还使用vector来保存子弹的命中率信息,为更好的决策提供依据。当然这超出了我们今天的话题,有兴趣的朋友可以看一下Yngwie中的Enemy类和Strategy类。
好了,让我们正式开始今天的vector之旅吧,如果您对JAVA中的vector还不是特别了解,没关系,我在最后介绍了一些关于vector的知识。
给我们的敌人排个队

熟悉JAVA的朋友都知道,vector是用来保存一系列对象的集合。今天我们用他来保存我们的敌人的一些信息,把这些四处乱跑的家伙都抓进我们的集合还真不是个轻松的活。孔子云:“万物皆类”。所以,我们首先要声明一个类:Track类。将我们能知道的敌人的属性全都作为这里类中的一个属性:名称、绝对角度、敌人坦克相对于你车头方向的相对角度、距离、能量、速率和敌人坦克所面对的方向等。这些都是通过ScannedRobotEvent对象得到的,具体的API函数请参考Robocode的API帮助。代码如下:
/**

* Track类,保存目标的信息

*/

package mytest;

import robocode.*;

public class Track

{

public String Name;                           //敌人坦克的名称

//敌人的绝对角度,通过计算得出

public double Heading;

//敌人坦克相对于你车头方向的相对角度

public double Bearing;

public double Distance;                      //敌人坦克的距离

public double Energy;                         //能量

public double Velocity;                       //速率

public double FaceHeading;                //敌人坦克面向的方向

public double trackX,trackY;              //敌人坦克的坐标

//下一个标准时间中敌人坦克所在的位置

public double nextTrackX,nextTrackY;

public void update(ScannedRobotEvent e)

{

Name=e.getName();        //敌人坦克的名称

Bearing=e.getBearing();    //敌人坦克相对于你车头方向的相对角度

Distance=e.getDistance(); //敌人坦克的距离

Energy=e.getEnergy();     //能量

Velocity=e.getVelocity();  //速率

FaceHeading=e.getHeading(); //敌人坦克面向的方向

}

}
在战场上,一个优秀的指挥官会很好的利用他手头有限的信息,而我们的信息都来自于雷达找到敌人后产生的ScannedRobotEvent事件,至于我们能得到哪些信息,看上边的注释好了,不多解释了。
下一步就是如何把已经现身在雷达中的敌人抓到一个vector里去了,让我们回到我们的机器人主体中去:派生自AdvancedRobot 类的MyVector类中。
首先,声明一个vector类型,并在run中进行初始化。
public class MyVector extends AdvancedRobot

{

final double version=0.1;   //版本号

private Vector trackVector;    //声明我们的向量数组

/**

* run: MyVector's default behavior

*/

public void run() {

out.println("myVector Version is "+version);

trackVector=new Vector();       //初始化我们的向量数组

while(true) {

// Replace the next 4 lines with any behavior you would like

showTrack();

setTurnRadarRight(360);  //让雷达不停转

execute();

}

}
好了,vector建好了,那下一步就……
请君入队

在Robocode中90%以上的外界信息来自于雷达的扫描,在这个例子里,我没有对雷达的动作进行更细致地处理,一直让他在不停旋转,从而能更多的收集不同敌人的信息。如果是在单挑模式中,可能采取雷达锁定目标会更加有效。
只要雷达工作正常,我们就能获取每一个敌人的信息了。当敌人的信息源源不断地涌入我们的onScannedRobot中,我们的机器人要像一个优秀的指挥官一样去鉴别情报,那些是已经有的,那些是没有的。如果已经存在我们则更新该对象的属性;如果没有的话,就在向量数组中添加一个新的成员。让我们去onScannedRobot事件里看一下吧。
/**

* onScannedRobot: What to do when you see another robot

*/

public void onScannedRobot(ScannedRobotEvent e) {

if(!isInVector(e))

{

Track myTrack=new Track();

myTrack.update(e);

trackVector.add(myTrack);

}

}
我的myVector机器人是靠自定义方法isInVector来判断该机器人是否存在于向量数组中的,我们等下去看isInVector的里边。如果isInVector返回值为false,则初始化一个Track对象,调用它的update方法来初始化敌人的信息,然后调用Vector类型的add方法,将该对象加入到向量数组中。
在这里请大家注意的一点是:同一个Vector对象中可以存储不同类型的对象,这是JAVA优于C++的一点,但是切忌滥用,我们在trackVector对象中存贮的对象都是Track类型。 好了,让我们去isInVector里边看看吧。
/**

* isInVector:自定义方法,判断该机器人是否已存在于队列中

*/

public boolean isInVector(ScannedRobotEvent e)

{

int i=0;

while(i<trackVector.size())

{

Track myTrack=(Track)trackVector.get(i);

if(myTrack.Name==e.getName())

{

myTrack.update(e);

return true;

}

i++;

}

return false;

}
isInVector方法的基本思路是,通过传进来的ScannedRobotEvent中的getNa
bb46
me来和vector中已经存在的对象的Name来进行比较,如果有相同的Name存在,则说明该敌人的对象已经储存在vector中了,我们只需要简单的调用Track类的update方法,更新信息,并返回true 就可以了。如果没有在vector中找到同名的机器人,则返回false,交给onScannedRobot事件来将这个机器人添加到vector中来。
这里我使用了Vector类型的size方法来得到向量数组中存在的对象的数量,在后边我们还会用到这个方法。同时使用一个int变量来控制操作哪个对象,更好的办法是使用迭代器,有兴趣的朋友可以参考一下《JAVA编程指南》。要得到vector中的Track对象,则需要使用Vector 类型的get方法,它指定返回第几个对象。注意,这里需要进行强制类型的转换。得到对象后我们就可以比较Track的 Name和ScannedRobotEvent的getName()是否相同了。
敌人不见了

在Robocode的战场上,杀戮与被杀的几率是相同的。不知道大家想过没有,如果一个敌人被干掉了,他的对象还保存在我们的vector中!如果我们的火控系统偏巧选中了他来作为下一个攻击目标的话……不用担心,如果我的机器人真那么傻,他恐怕等不到别人被杀的情况。很简单,我们只需要在onRobotDeath事件中调用Vector类型的remove方法。Remove方法是用来删除指定位置上的对象的。下面代码的基本思路和isInVector是一样的。显示如下:
/**

* onScannedRobot:有机器人被消灭时产生该事件

*/

public void onRobotDeath(RobotDeathEvent event)

{

int i=0;

while(i<trackVector.size())

{

Track myTrack=(Track)trackVector.get(i);

if(myTrack.Name==event.getName())

{

trackVector.remove(i);

}

i++;

}

}
显示敌人的距离

我们这么辛苦地保存了战场上所有敌人的信息后,由myVector在每个基本时间里报告每个机器人距我们的距离。但这里应该注意的是,myVector报告的距离是我们的雷达最后一次看到敌人时的距离,敌人很可能已经移动了。正如一位物理学家所说:“我们无法预测未来是因为我们无法看到真实的现在。”
我在run的while中调用了下面的函数,用来显示当前的时间、敌人的数量及每个敌人与我们的距离。对数量的计算用到了Vector 的size方法。
/**

* 自定义函数:显示当前敌人的距离

*/

public void showTrack()

{

int i=0;

out.println("This Time is "+getTime());

out.println("Track's count is "+trackVector.size());

while(i<trackVector.size())

{

Track myTrack=(Track)trackVector.get(i);

out.println(myTrack.Name+"'s Distance is "+myTrack.Distance);

i++;

}

}
好了,一个简单的使用vector来保存敌人信息的机器人完成了,你可以在这里下载他的代码。在这里我们的机器人仅仅是将敌人的距离显示了出来,但是,实战中我们可以通过对这些信息的分析,来确定下一个攻击目标,比如最近的一个。这就要看你的发挥了。我在这里提供的机器人可以说是很幼稚的,甚至公然违反了一些面向对象编程的原则,比如把类中的元素直接声明成public。这些问题请大家在编码的过程中避免。我在这里想说明的是,在Robocode中你可以使用任何的JAVA技术,让你的机器人更强大。
下面是我写的机器人myVector输出测量结果时的情况,大家可以看到Time2和Time3时的情况是不同的,在Time2时,雷达只扫描到了Crazy和Fire两个敌人;Time3的时候雷达又发现了Corner。当有机器人被消灭的时候,Vector中的对象会马上被删除。大家如果有兴趣可以从下面找到myVector的源代码(resource),大家可以亲自实验一下。



Vector基本概念

最后,我来为不十分熟悉JAVA的朋友来简单讲解一些Vector的基础知识,熟悉这些内容的朋友可以跳过。
Vector类型定义了Object 类型的一个元素集合,它最大的特点是能够根据你的需要动态增长。它实现了List接口,因此你可以把它看作一个列表。Vector中只储存对象的引用,而不是实际的对象。这里引用的概念和C++中的很类似,熟悉C++的朋友可以对照理解一下。
Vector的长度可以通过size()来获得,而它的容量则用capacity()来得到。容量(capacity)指的是为这个Vector分配的空间,而长度(size)则是Vector中已经使用了的空间,size和储存的对象个数相同。而长度永远小于容量,这点请大家注意。
Vector的容量可以通过setSize(i)来更改,如果Vector对象占用的元素个数小于i,则其余元素将被null填充;如果包含的数量超过i,则所有i后的对象引用将被丢弃。
Vector中使用add为向量数组添加新的元素。Add(yourObject)是在vector的最后添加一个元素。而Add(i,yourObject)则是在i指定的位置添加一个元素,使i以后的元素向后移动,总长度加1。与此类似,set(i,yourObject)则是由yourObject替换i位置上的元素。这里大家需要注意的是,Vector的记数是从0开始的,而不是从1开始的。
Vector中使用get(i)来得到对象的引用,使用remove(i)来删除i位置上的元素。另外你还可以使用firstElement()来得到Vector中的第一个元素。形式如下:
YourObject you=(YourObject)vector.firstElement();
我们可以通过把一个对象作为参数传递给indexOf()方法来获得存储在一个Vector中的对象的索引位置。
至于,迭代器等一些高级属性,如果有兴趣,大家可以参考一下《Java编程指南》。里面进行了很详细的解说.
最后,我还要感谢天翼.李(Skyala.Li)耐心地看完了这篇文章的初稿,并提出了宝贵的意见。感谢 Robocode 中华联盟网站上的朋友们为我提供了各种帮助。
参考资料
文章中源代码可于此处下载( download).

请访问 Robocode 中华联盟网站,它是国内一个新生的Robocode组织。其内有大量关于Robocode机器人的原创及翻译文档,负责有关中华区机器人赛事的组织事宜。是现今为此中华区最大 ,增长最快的Robocode站点。

请阅读《Java2编程指南(JDK 1.3)》[美]Ivor Horton著

请阅读 Robocode技巧精粹的所有文章。在新技巧出现时这个页面会得到更新。

从 alphaWorks 下载 Robocode的最新版本。

Mathew Nelson 是 Robocode 的创建者,他维护着 官方 Robocode 站点。这应当是所有关心 Robocode 的人的第一站。在此,您还可以参加由 Mathew Nelson 主持的 讨论组。您还可以看看 to-do list,这个列表是对请求功能的“持续更新”的列表。

RoboLeague是针对 Robocode 的联盟以及赛季管理者,由 Robocodeby Christian Schnell 负责。它确保所有可能的分组实际打好比赛、管理结果并生成 HTML 状态报告。

想要更多的了解 Robocode 吗?是学习高手的秘诀还是从在 IBM alphaWorks 上红极一时的下载作品的创造者那里发掘真相呢? 现在注册可以免费订阅一份印刷版的 IBM developerWorks journal(2002 第 5 期)

在 developerWorks 上的 Java 技术专区查找 Java 参考资料。

关于作者
羌狼(aawolf)正在从事Pocket PC下的软件开发,C++程序员,Robocode玩家。Robocode 中华联盟的成员。有兴趣于Robocode的朋友请与他联系: aawolf@inhe.net
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息