副标题#e#
媒介
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(); //仇人坦克面向的偏向
}
}
#p#副标题#e#
在疆场上,一个优秀的批示官会很好的操作他手头有限的信息,而我们的信 息都来自于雷达找到仇人后发生的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事件里看一下吧。
#p#分页标题#e#
/**
* 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中的 getName来和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要领。
#p#分页标题#e#
/**
* 自界说函数:显示当前仇人的间隔
*/
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)耐性地看完了这篇文章的初稿,并提 出了名贵的意见。