Robo Home | VirtualBullets | Changes | Preferences | AllPages

Here's one way to work with VirtualBullets / Waves. It uses the Robocode built in custom event system, which I am very fond of using. =) -- PEZ
import robocode.*;
import java.awt.geom.*;

public class VirtualBulletsBot extends AdvancedRobot {
    private int timeSinceLastScan = 10;
    Point2D robotLocation = new Point2D.Double();
    Point2D enemyLocation = new Point2D.Double();
    static double enemyAbsoluteBearing;
    public void run(){
        do {
        } while true;
    public void onScannedRobot(ScannedRobotEvent e) {
        enemyAbsoluteBearing = getHeadingRadians() + e.getBearingRadians();
        robotLocation.setLocation(getX(), getY());
        toLocation(enemyAbsoluteBearing, e.getDistance(), robotLocation, enemyLocation);

        // Aim your gun here

        Bullet bullet = setFireBullet(3);
        if (bullet != null) {
            addCustomEvent(new VirtualBulletTrigger(bullet.getVelocity()));

        timeSinceLastScan = 0;

    private void doScanner() {
        double radarOffset = Double.POSITIVE_INFINITY;
        if(getOthers() == 1 && timeSinceLastScan < 3) {
            radarOffset = robocode.util.Utils.normalRelativeAngle(getRadarHeadingRadians() - enemyAbsoluteBearing);
            radarOffset += sign(radarOffset) * 0.02;

    void toLocation(double angle, double length, Point2D sourceLocation, Point2D targetLocation) {
        targetLocation.setLocation(sourceLocation.getX() + Math.sin(angle) * length, sourceLocation.getY() + Math.cos(angle) * length);

    int sign(double v) {
        return v > 0 ? 1 : -1;

    class VirtualBulletTrigger extends Condition {
        private long time;
        private double bulletVelocity;
        private Point2D oldRobotLocation = new Point2D.Double();

        public VirtualBulletTrigger(double bulletVelocity) {
            this.time = getTime();
            this.bulletVelocity = bulletVelocity;

        public boolean test() {
            if (bulletVelocity * (getTime() - time) > oldRobotLocation.distance(enemyLocation)) {

                //update your stats here
                //(you probably need some more instance variables in this class for this.)

            return false;
You probably shouldn't do the work with the virtual bullet inside the test() function there. Better do it in the event handler. But this works for me. Also note that this only fires virtual bullets when a real bullet is fired. Which is good against bullet dodgers. But you could remove the test for a bullet fired (and work out a way to store the bullet velocity of the last bullet fired) to fire virtual bullets each scan. Which makes for much faster "learning". I haven't tested this code. if someone does and find something missing, please update the code snippet. -- PEZ

Oh~~Cool,PEZ,it must can save many codesize for some minibots. -- iiley

Alright, nifty, I get them now but your right, that is tough to make work in a micro. -- Dan724

Of course, if you make it fire the VB every scan, you need to figure out the speed yourself. -- Kawigi

Yes, I beleive I said that actually. It's as easy as using a member variable for bulletVelocity in the bot class and store it there. Or if you instead use a function for determining bullet power (which you often have for energy management purposes anyway). From that function it's easy to calculate the bullet speed. As for saving codesize this way. I have never thought of it that way, but it's true that it is rather small code. The VB trigger class is very small, even with some stat updating included. For Tityus this class is 256 bytes. Which anyone who has read my code knows can be shrinked a lot if you are fond of that. -- PEZ

FloodMini's MiniBullet? is something like 164 bytes I think, but part of that is that it doesn't have a constructor (as initializing everything from the outside seemed to be smaller at least in my case, that may not be the case for you). -- Kawigi

I'm pretty sure it could be fit in a micro. I made a GuessFactorTargeting bot of codesize 932 using this kind of VirtualBullets. And that was while sticking to my coding principles. A code shrinker would probably easily get it down to microbot size. -- PEZ

FloodMini's version is more accurate than this if I miss scans, too. But if I take that part out, and most segmentation information, I could get it down to something like 75 bytes (I've been attempting occasionally to put that into a NanoStatist?). -- Kawigi

I doubt that kind of accuracy pays of any way. A NanoStatist? would be great fun to welcome! -- PEZ

I'll have to get really creative, though, to get it under 300 bytes, especially if I want it to move. Although it may be worthwhile to use the custom event system, as it eliminates the loop for updating and checking. I'll give it some thought (when I get back to school, actually, I'm packing up and moving tomorrow...) Of course, if I use completely unsegmented statistics, I have a way of actually using a StringBuffer? to be my stat buffer. Unfortunately, it's not very robust (I can only have 65000 or so samples in each bucket). -- Kawigi

I have renamed the VirtualBulletTrigger? class in my bots to Wave since this is really more like waves than virtual bullets. -- PEZ

The dev version of FloodHT is one step ahead even, it has a multi-VirtualBullet? wave sort of class now. It acts like a wave, but then returns an array of booleans which represent all the angles that would have hit.

I'm almost done with FhqwhgadsMicro now, which uses this technique in a minimalist sort of way. -- Kawigi

Ok, so after much deliberation and cursing i've decided to ask for help rather than struggling. How do i calculate the factor that hit when my wave reaches the right distance??

At the moment im using:

        if(waveTravelDistance >= target.Distance)
             double diff = bearingNow - bearingAtFire;
             double factor = diff/(Math.asin(8/waveVelocity));

             int statArrayIndex = ((int)((factor * 18)+0.5)) + 18;
             return statArrayIndex;

         return -1; 

This is what seems logical to me, however i'm having a few problems with my gun so wanted to check it was a bug rather than an error. I looked at the way that kawigi did it in his bots but i have no idea how or why that works, as it works along a completely seperate idea. Or at least thats how it appears. I decided waves were probably a good idea as i was skipping 20-30 turns a round and suspect i may just have to many virtual thingies to track... -- Brainfade

It looks reasonable enough to me. For the record, Kawigi's aiming works around the same idea, only it's heavily obscured in, I think, an effort to squeeze codesize. You might want to normalize the "diff" angle there. Also make sure that both "bearings" are measured from your position at the time of fire. -- PEZ

That looks extremely similar to what I do in FloodMini, except I do it one line, multiply it by the lateral direction of the opponent at fire-time, and I already have teh asin(8/waveVelocity) calculated into that direction. But PEZ is right that you want to normalize diff, in case you go from 5 degrees to 355 degrees. The other thing to consider looking at my code is that I linearly interpolate my opponent's movement during missed scans. lastx and lasty are the enemies current position. -- Kawigi

can some one explain me what the below line means? SSO?

int statArrayIndex? = ((int)((factor * 18)+0.5)) + 18;

It's taking a factor (that is set up so it should always be between -1 and 1) and trying to make it a number from 0 to (I'm guessing) 36 or 37 to be put into a bucket of the stat buffer. The +0.5 is to make it round instead of truncate the number, but he should really use Math.round(), since this method won't work for his negative factors. -- Kawigi

Yeah, kawigi is completely right. The reason i didnt use Math.round() was because i thought it rounded the number down rather than off. I've actually changed over to Math.round() now... --Brainfade

Here's how I do it. Which expresses how I "think".

index = (int)Math.round(((Bot.sign(deltaBearing) * bearingDiff) / maxBearing) * (numFactors - 1) / 2D + (numFactors - 1) / 2D);
-- PEZ

Is the factor number starts from 0 to 36 or -18 to 18 --SSO

The factor is between -1.0 to 1.0 inclusive. And this is mapped into an array with 37 buckets, indexed 0 to 36. -- PEZ

Pez, in your code snippet above, what is the difference between "deltaBearing" and "bearingDiff"?? -- Brainfade

Sorry, it's my bad naming of variables... deltaBearing is the change in bearing between the two last scans at the time of firing the wave. bearingDiff is the change in bearing between the time of fire and "now" (when the wave reaches the enemy). That is the same as your "diff" in your code snippet. I take the sign of the deltaBearing to know if a negative bearingDiff means a negative factor or not and vice versa. That might actually be what's missing from your code there. If the enemy was traveling leftwards when you fired the wave and continued that movement and ended up at say, the minimum angle (maybe -46 degrees). Then your code would say that it was factor -1.0 whereas my calculation would say it was factor +1.0. And my calculation would be the correct one I believe. -- PEZ

Ok, i think i understand what you're saying. And i think this could well be why my implementation isn't working properly. Currently i am calculating which direction is positive and negative according the the change in absolute bearing, whereas i should be assigning this due to the direction that the robot was travelling. This would explain why i am so bad at hitting oscillating robots. My only question is why you use deltaBearing only between the last 2 scans. Surely this means that if the robot changes direction just before your bullet hits that you will calculate the index wrong?? maybe i've got it round my neck. i think its time to sit down with a pencil and paper... --Brainfade

No, if your opponent just changed direction, before you fire, you do want to use their new direction. You can't know what direction your opponent will go when you hit them, the great thing about statistical targeting is that you assume you can't know that and don't care. There is a significance to accounting for which direction your opponent is going around you, though. Most robots' movement is symmetrical (they could do the same thing going backwards as forwards). However, most robots are more likely to end up ahead of where they were before when they would get hit by a bullet. Here, you can look at just how much ahead of where they were. -- Kawigi

Robo Home | VirtualBullets | Changes | Preferences | AllPages
Edit text of this page | View other revisions
Last edited March 26, 2009 23:44 EST by Pakistan (diff)