Robo Home | Ali | Changes | Preferences | AllPages

/BumbleBee a gun by PEZ

An experimental "fuzzy matching" GuessFactorTargeting gun based on CassiusClay/Bee. -- PEZ

TargetingChallenge/FastLearning (TC35) Performance

I'll try to track BumbleBee's TC35 performance here. Together with the current top competition for reference.

Name Author DT Asp TAOW SparCig Tron Fhqw HTTC Yngw Funk Total Comment
CassiusClay PEZ 81.49 93.41 99.76 97.96 83.97 85.20 95.21 85.83 97.57 89.71 91.01 15 seasons
Shadow 3.06 ABC 78.85 90.24 99.63 98.45 83.23 87.43 93.95 89.67 97.86 88.99 90.83 15 seasons
Pugilist PEZ 81.05 91.69 99.85 98.14 82.11 84.79 93.54 85.74 97.45 88.97 90.33 16 seasons
Ali PEZ 80.74 92.06 99.77 96.72 78.96 83.03 95.95 85.41 97.86 89.11 89.96 33 seasons
Raiko 0.43 Jamougha 80.02 89.93 99.63 97.65 81.63 84.23 95.92 85.19 97.20 88.06 89.95 16 seasons
Phoenix 0.2 dev David Alves 74.20 89.98 99.88 96.18 82.15 84.52 95.28 87.49 96.84 89.81 89.63 50 seasons
Ali 0.2.5 PEZ 78.17 92.09 99.75 96.42 79.35 82.26 95.79 86.48 96.67 88.66 89.56 15 seasons
DarkHallow Jim 76.71 90.34 99.30 97.42 80.72 85.74 95.14 85.35 96.90 87.59 89.52 15 Seasons

Implementation issues

Instead of indexed segmentation BB uses normalized scalar measures. This is the only difference in the actuall Gun class. Then there is some changes in the Wave subclass, BumbleWave, too. The new stuff looks like so (as always, my code is covered by the RWPCL):
class BumbleWave extends Wave {
    static final double MATCH_THRESHOLD = 11;
    static List log = new ArrayList();

    LogEntry logEntry = new LogEntry();
    void registerVisits() {
	logEntry.visitIndex = Math.max(1, visitingIndex());

    int mostVisited() {
	int mostVisitedIndex = MIDDLE_FACTOR;
	int[] matched = new int[FACTORS];
	for (int i = 0, n = log.size(); i < n; i++) {
	    LogEntry e = (LogEntry)log.get(i);
	    double distance = logEntry.distance(e);
	    if (distance < MATCH_THRESHOLD) {
		e.usage = PUtils.rollingAvg(e.usage, 100, 200);
	    else {
		e.usage = PUtils.rollingAvg(e.usage, 0, 200);
	int most = 0;
	for (int i = 0; i < FACTORS; i++) {
	    if (matched[i] > most) {
		mostVisitedIndex = i;
		most = matched[i];
	return mostVisitedIndex;

    static void cleanLog() {
	if (log.size() > 10000) {
	    System.out.println(((LogEntry)log.get(0)).usage + " - " + ((LogEntry)log.get(4999)).usage);
	    Collections.sort(log, new Comparator() {
		public int compare(Object a, Object b) {
		    return (int)(((LogEntry)b).usage - ((LogEntry)a).usage);
	    log.subList(4999, log.size() - 1).clear();
	    System.out.println(((LogEntry)log.get(0)).usage + " - " + ((LogEntry)log.get(4999)).usage);

class LogEntry {
    double bulletPower;
    double fireDistance;
    double velocity;
    double lastVelocity;
    double velocityChangedTimer;
    double wallDistance;
    int visitIndex;
    double usage;

    double distance(LogEntry e) {
	double distance = Point2D.distanceSq(this.fireDistance, this.velocity, e.fireDistance, e.velocity);
	distance += Point2D.distanceSq(this.lastVelocity, this.velocityChangedTimer, e.lastVelocity, e.velocityChangedTimer);
	distance += Math.pow(this.wallDistance - e.wallDistance, 2);
	return Math.sqrt(distance);

Where Bee uses several stat buffers for efficience in both short and long term, this gun uses only the log. I guess I could increase and decrease the fuzziness in the match there to get some of that Bee quality back. I just don't know how to do that in a controlled manner.

-- PEZ


This is looking more and more like my gun, mixed with the new one I'm planning. Maybe I can take a break and just suggest things for you to experiment with... :) -- ABC

Interesting. That means our guns never where all that different. I seem not to be able to make this gun work near the performance of Bee though. Which feels a bit funny, because this gun "feels" better. But I won't give up yet. Keeping the raw data opens up a world of opportunities that I must explore some. Please suggest one or two things I can try. -- PEZ

There are still some fundamental differences, though. One of then is that, instead of a fixed MATCH_THRESHOLD, I use a fixed cluster size, so that when you don't have enough close matches you look for tendencies in not so close ones. Very much like using an unsegmented array when you don't have enough data for the segmented ones. -- ABC

Yeah, I haven't a clear idea on how to do that yet. All my attempts have resulted in really slow performance. And since Ali is already a SlowBot I keep thinking about the problem until I figure out how to do it without eating to much CPU. The cleaning of seldomly used data in the log there. Does that seem reasonable to you? How do you keep your log from not growing infinitly? -- PEZ

You should really look into the fire time only prediction, it will increase your bot's speed like nothing else. I have a gun.class where I deal with that kind of stuff, and all my guns extend that class by overriding the getFireAngle?(enemy) and other methods. You should maybe try making a HOT gun that does that, and tweak it until it fires at every chance it gets and always HOT, sitting duck is a good tester. I find your log cleaning very interesting, I just cap mine at 30000 scans, it only analyses data from the last 70 rounds or so, like a time-based data decay. Again, execution speed is crucial, you are struggling with 8000 samples, I use 30000 and still have time to do a lot of PM stuff on it... -- ABC

And you shouldn't compare a prototype gun first attempts with Bee's, no way a new gun can compete with another one that has been tweaked/optimised for years... -- ABC

I only run the matching when getGunHeat() < getGunCoolingRate() * 2. When the gun is hot I keep the gun HOT aimed. I guess this still runs the matching too often, but at least not all the time. -- PEZ

Ali is still a bit faster than Shadow, some 135% faster I think. But you are doing much more stuff and maintain a much larger log so I must definately look into where I can gain speed. Time to use that profiler David was talking about. -- PEZ

135% like 2.3x or 135% of Shadow's speed (1.3x)? It is obvious that the prediction is the slowest part of your code, and you are executing it 2-3 times per bullet. If you reduce it to 1 prediction/bullet you'll probably make it twice as fast. Try getGunHeat() <= getGunCoolingRate() && getGunHeat() > 0, I think like this it will predict only one tick before firing. -- ABC

Thanks. What if I miss a scan then? I mean if getGunHeat() reaches zero and I haven't predicted. -- PEZ

That's why I keep a flag to know if I already predicted, I set it to true after predicting (getGunHeat() <= getGunCoolingRate()) and false after firing. -- ABC

Thanks again. Expect a faster Ali tonight. =) -- PEZ

OK so I've now got the matching to run only once per bullet fired. And I also changed to a Manhattan distance calculation which, strangely enough, seems to work better but is also faster. Now the log is allowed to grow above 30000 waves and Ali is still more than twice as fast as Shadow I think. As it should be since my gun use simple GF techniques instead of projecting movement to find out where to fire. I've tweaked the weighting of some of the dimensions now and the gun performs better in my tests. Let's see what the rumble says. -- PEZ

Wow. And so I lost 40+ points! I have no clue why really. I've now reset back to squared distances and weighting of the dimensions like the earlier version. If that doesn't help I guess it must be my "run matching only once per bullet" thingy that goes terribly wrong. Squared distances means I had to keep the log shorter because it's much slower.

Never tweak your gun against Aristocles. It made my gun win points against Aristocles and Raiko and all bots using Raiko movement but lose against virtually every other bot in the rumble.

-- PEZ

Imo you should use a TC-enabled opponent and disable your movement. Maybe it's your movement that is making the results more volatile, a wavesurfer's dodging performance is very dependant on the enemy shots that hit it. -- ABC

Good point. -- PEZ

The current version of the gun didn't fix the problems introduced lately. I think that it must be something wrong in the code where I try to run te matching only once per bullet. -- PEZ

OK. I reverted back to 0.2.3 now and do gun heat and alignement like ABC suggests on the WhenToFire page. In my testing it seems to fix the problems. It's again up to the rumble god to decide though. =) -- PEZ

In Ali version I try squared Euclidian distancing. Like so:

    double distance(LogEntry e) {
	double d1 = this.fireDistance - e.fireDistance;
	double d2 = this.velocity - e.velocity;
	double d3 = this.lastVelocity - e.lastVelocity;
	double d4 = this.velocityChangedTimer - e.velocityChangedTimer;
	double d5 = this.wallDistance - e.wallDistance;
	return d1 * d1 + d2 * d2 + d3 * d3 + d4 * d4 + d5 * d5;
This should penalize larger differences in idividual dimensions more than the Manhattan distancing (that is summing plain absolute differences) does. An example could be these two cases:
  1. All dimensions are quite similar without anyone being an "exact" match
  2. Four dimensions are exact matches, but the velocity segment is quite different.
With Manhattan differencing both cases would count as a match. But with squared Euclidian distancing only the first case matches.

Tweaking remains. Right now I get the same total TC35 score using either distancing method, but I think I have a lot more tweaking to do everywhere in this gun. I tried ABC's approach of using fixed cluster sizes, but it lowered my guns performance quite much. I saved that branch of code though, so I can revisit it later.

-- PEZ

Robo Home | Ali | Changes | Preferences | AllPages
Edit text of this page | View other revisions
Last edited November 12, 2004 14:26 EST by PEZ (diff)