targeting weakest bots

Help
Harbinger
2007-06-30
2012-09-15
  • Harbinger

    Harbinger - 2007-06-30

    I've been doing Robocode for only a week. I want to make a bot that finds the bot with the least amount of energy and goes after it.

    I tried scanning then entering the enemies into an ArrayList, then identifying the one with the least energy. It gave me too much trouble since my robot would usually sit there and do nothing. It never works as intended.

    Any ideas?

     
    • Harbinger

      Harbinger - 2007-07-07

      I get four semantic errors when compiling; it says that I need Java 1.5 for the HashMap and enhanced for-loops. However, I have Java 6 and verified it with the Java portion of the site. I reinstalled Robocode and still get the same errors. Any ideas? Thanks again for the help.

       
    • Flemming N. Larsen

      If your robot is an AdvancedRobot you must make sure to call execute() as one of the last statements after the setAhead(), setTurnLeft(), and similar calls.

      It is hard to say what exactly causes the problem. You could send the source to me and let me have a look. If the robot is not too big (containing many lines), you could post it here.

       
    • Harbinger

      Harbinger - 2007-07-01

      Here it is. I appreciate any help. Like I said, I'm new at this.
      Also, I'm unsure of the difference between scan() and turnRadarRight(360). How do they differ?

      package mh;
      import robocode.*;
      import java.awt.Color;
      import java.util.ArrayList;

      public class Predator extends Robot
      {
      double lowEnergy = 100.0;
      Robot nextVictim = null;
      ArrayList enemies;

      /**
       * run: Predator's default behavior
       */
      public void run() {
      
          setColors(Color.black,Color.red,Color.black);
          while(true) {
      
              turnRadarRight(360);
              ahead(75);
              turnRight(90);
              }
      }
      
      public void onScannedRobot(ScannedRobotEvent e) {
      
          enemies.add(e); //add the scanned enemy to the ArrayList
          for(int i = 0; i < enemies.size(); i++)
              {
                  if(((Robot)enemies.get(i)).getEnergy() < lowEnergy)  //compare the scanned enemy to the previous
                                                                                       //weakest
                  {
                      lowEnergy = ((Robot)enemies.get(i)).getEnergy();  //if it's weaker, it's the new victim
                      nextVictim = (Robot)enemies.get(i);
                  }
              }
      
          if(nextVictim.equals(e)) //if the scanned enemy is the weakest, target it and fire
          {
              double absoluteBearing = getHeading() + e.getBearing();
              turnGunRight(robocode.util.Utils.normalRelativeAngle(absoluteBearing - getGunHeading()));   
              fire(1);
          }
      

      }

      public void onHitByBullet(HitByBulletEvent e) {
          turnGunRight(e.getBearing());
      
          fire(2);
      }
      

      }

       
    • Flemming N. Larsen

      First of all, the difference between scan() and turnRadarRight(360) is that scan() instructs your robot to scan for other robots (see http://robocode.sourceforge.net/docs/robocode/robocode/Robot.html#scan()). The turnRadarRight(angle) instructs your robot to turn it's radar the specified amount of degrees to the right (see http://robocode.sourceforge.net/docs/robocode/robocode/Robot.html#turnRadarRight(double)).

      Well, I have run your robot, and the first thing I noticed was that the robot causes a NullPointerException, i.e. in the onScannedRobot() event handler. You make this method call:

      enemies.add(e);

      But you haven't new'ed the enemies variable. You could do this as one of the first things to do in the run() method, or doing it in the constructor (you'd have to declare one first), or just do it as the location where you declare the variable.

      Hence, instead of writing:

      ArrayList enemies;

      You should write:

      ArrayList enemies = new ArrayList();

      When you just write "ArrayList enemies" alone, the variable will automatically be set to null causing the NullPointerException.

      You can see the NullPointerException is thrown by opening the robot cosole window for your robot. This is done by clicking on the button on the right side of the battle window that is labelled with the name of your robot.

      You can print out messages for debugging to this window by writting something like this:

      out.println("Hello Robot World");

      This is a nice feature for debugging.

      When this issue is fixed a ClassCastException occurs, which is thrown because you try to cast a ScannedRobotEvent into a Robot class. This is not possible as the ScannedRobotEvent is not an 'instance of' the Robot class. Thus, all the placed where you cast or assign the input parameter 'e', you should use the ScannedRobotEvent instead of Robot.

      After this you get another NullPointerException with this statement:

      if(nextVictim.equals(e))

      The reason is that the nextVictim is null when no next victim has been found yet. You could prevent this exception by writing:

      if (nextVictim != null && nextVictim.equals(e))

      However, it this situation you could also write:

      if (e.equals(victim))

      This is shorter. The event 'e' will never be null for onScannedRobot(), and equals() allows a null value as input.

      Now your robot does not cause any exceptions, and is infact starting to move! :-)

      However, there are still issues remaining. With the onScannedRobot() you call:

      enemies.add(e)

      You do this everytime onScannedRobot() is called, which will eventually be 1000 of times or more. At that time your list would contain 1000 elements, i.e. 1000 ScannedRobotEvents. There are several problems with that:

      • The list of enemies are growing for each time onScannedRobot() is called, which decreased the performance of your robot.
      • You got a lot of redundant ScannedRobotEvents for the same robots
      • The list will contain very old data for where the robots were for about 1000 turn ago. Remember, the robot moves all the time!!

      A better approach is to store records for each robot in e.g. a hash map/table, and remove old entries after e.g. 10 turns. By using a hash map/table you will always have the newest data for a specific robot, or at least the data for the robot the last time your robot saw it.

      You also have a problem when turning the gun. You write:

      double absoluteBearing = getHeading() + e.getBearing();
      turnGunRight(robocode.util.Utils.normalRelativeAngle(absoluteBearing - getGunHeading()));

      The problem here is that robocode.util.Utils.normalRelativeAngle works in radians, not degrees!
      Thus, you should write this instead:

      turnGunRight(Math.toDegrees(robocode.util.Utils.normalRelativeAngle(Math.toRadians(absoluteBearing - getGunHeading()))));

      So the input for normalRelativeAngle() is converted into radians by using Math.toRadians().
      Next, the radians returned from normalRelativeAngle() itself is converted into degrees using Math.toDegrees().

      Now you shot at the right victim. However, in the run() method you turn the radar 360 degrees, which will take 8 turns, and where you do not scan() in between. I would recommend that you turn 45 degrees at maximum, as this is the max. turning rate for the radar per turn.

      Well, I made all the changes (with comments) to your robot, which I list here:


      package mh;

      import robocode.util.Utils;

      import robocode.;
      import java.awt.Color;
      import java.util.
      ;

      public class Predator extends Robot {

      double lowEnergy = 100.0;
      ScannedRobotEvent nextVictim;

      // Map of enemies. The robot name (a String) is the key
      // and each value is a ScannedRobotEvent
      Map<String, ScannedRobotEvent> enemyData = new HashMap<String, ScannedRobotEvent>();

      /
      run: Predator's default behavior
      /
      public void run() {

      setColors(Color.black,Color.red,Color.black);
      
      while(true) {
      
      turnRadarRight(45);
      ahead(75); 
      turnRight(90); 
      }
      

      }

      public void onScannedRobot(ScannedRobotEvent e) {

      // Store the enemy name in the hash map, where the key = robot name
      enemyData.put(e.getName(), e);
      
      // Remove old enemy data that is more that 10 turns old
      for (ScannedRobotEvent sre : enemyData.values()) {
          if (sre.getTime() &lt; (getTime() - 10)) {
              enemyData.remove(sre);
          }
      }
      
      // Now, find the weakest robot (least energy)
      double minEnergy = Double.MAX_VALUE; // Initialize to max value
      
      for (ScannedRobotEvent sre : enemyData.values()) {
          if (sre.getEnergy() &lt; minEnergy) {
              minEnergy = sre.getEnergy();
              nextVictim = sre;
          }
      }
      
      if (e.equals(nextVictim)) { //if the scanned enemy is the weakest, target it and fire 
          double absoluteBearing = getHeading() + e.getBearing(); 
          turnGunRight(Math.toDegrees(Utils.normalRelativeAngle(Math.toRadians(absoluteBearing - getGunHeading()))));
          fire(1); 
      }
      

      }

      public void onHitByBullet(HitByBulletEvent e) {
          turnGunRight(e.getBearing());
      
          fire(2); 
      }
      

      }

      Now it is up to you to improve the robot further. If you still got problems, you could write again.

      Also notice that the http://robowiki.net is an excellent site for learning all the basics of a robot. You can find information in almost any aspect of Robocode programming. :-)

       

Log in to post a comment.