服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

在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  
  {
  
  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  
  {
  
  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