User:D414/Diary of a Robocoder

From Robowiki
Jump to navigation Jump to search
19th August 2025

For the past few days I've been trying to squeeze a neural network capable of "learning" into a nanobot, and I seem to have succeeded with Neutrino. I say "learning" because actually training mid-battle like Gaff is utterly infeasible in a nanobot. Instead I've been looking at echo state networks (See A Practical Guide to Applying Echo State Networks) as a way of maintaining state on multiple time scales.

In the process of shrinking down the inference code to a measly ~90 bytes I ended up accidentally designing something significantly more powerful that supports the following:

  • Multi layer perceptrons (MLP)
  • Echo state networks (ESN)
  • Special cases and/or approximations of a handful of other types of neural network
  • Any of the above connected in arbitrary ways (eg MLPs feeding multiple ESNs tuned to different timescales that then feed into another MLP)
  • Doesn't require the network to be organised in layers - it can handle an arbitrary DAG
  • Handles sparsely connected networks efficiently
  • Can save state from one round to the next, and supports training a completely separate network that is only run once per round

These capabilities only emerged after I finally managed to flatten the typical nested loops needed for matrix multiplication down to this:

static void doNN(double[] inout, int i) {
    try {
        while (true) {
            double leak;
            inout[OUT_ORDER.charAt(i)] = ((1 - (leak = decode(LEAK, i))) * inout[IN_ORDER_1.charAt(i)])
                + (leak * Math.tanh((inout[ACCUMULATOR_INDEX] += decode(WEIGHTS, i) * inout[IN_ORDER_2.charAt(i)]) + decode(BIASES, i++)));
        }
    } catch (ArrayIndexOutOfBoundsException e) {
    }
}

I've still got an enormous amount of work to go before I can turn Neutrino into a fully functioning bot, let alone a competitive one.

16th August 2025

I've been doing some exploratory work for an entirely different approach for Quantum worthy of being called version 2. Something I'm trying to add is storing data about my enemies.

The typical way of tracking data about enemies would be to use a Map, an example of which can be seen in HawkOnFire but this uses up far too much space to put into a nanobot. Kev uses an imaginative approach in Mirage that stores the data in arrays instead and uses a static function to give each enemy a unique integer id to index into those arrays. I shaved 11 bytes off of Mirage's approach in FireHammer (my attempt to fit Mirage's gun into a micro) and then Kev found a way to shave a whopping 26 bytes(!) off of that in Figment.

Unfortunately the Figment method has some drawbacks that could make it unsuitable for how I'm hoping to use enemy data in Quantum v2 but I have been able to shave another 5 bytes off of FireHammer's code.

// Mirage
// Size: 46 bytes
// Stable IDs: Yes
// Contiguous IDs: Yes, from 1-10 in a 10 bot melee match
// Clashing IDs: Theoretically possible, but unlikely (uses 18bits of the 32bit .hashcode())
// Memory usage: Low. Constant 1mb overhead for IDs. 1-based indexing wastes one enemy's worth of space in the data arrays.
static final int OPPONENT_HASHES = 262144; // 18 bits
static int[] opponentIDs = new int[OPPONENT_HASHES];
static int opponentsSeen;

static int getOpponentID(String name) {
    int code = name.hashCode() & (OPPONENT_HASHES - 1);
    int id = opponentIDs[code];
    return opponentIDs[code] = (id == 0 ? ++opponentsSeen : id);
}

// FireHammer
// Size: 35 bytes
// Stable IDs: Yes
// Contiguous IDs: Yes, from 0-9 in a 10 bot melee match
// Clashing IDs: No
// Memory usage: Extremely low. Almost zero overhead and no wasted space in the data arrays.
static ArrayList<String> opponentIDs = new ArrayList<>();

static int getOpponentID(String name) {
    ArrayList<String> list;
    if (!(list = opponentIDs).contains(name)) {
        list.add(name);
    }
    return list.indexOf(name);
}

// Figment
// Size: 9 bytes
// Stable IDs: Yes
// Contiguous IDs: No, could be anything from 0 - 255
// Clashing IDs: Theoretically possible, more likely than Mirage
// Memory usage: Potentially high, increases data size by 246x
static final int OPPONENT_HASHES = 256; // 8 bits

static int getOpponentID(String name) {
    return name.hashCode() & (OPPONENT_HASHES - 1);
}

// Quantum v2
// Size: 30 bytes
// Stable IDs: Can be unstable at the start of the first round until each enemy has been scanned for the first time.
// Contiguous IDs: Yes, from 0-9 in a 10 bot melee match
// Clashing IDs: No
// Memory usage: Extremely low. Almost zero overhead and no wasted space in the data arrays.
static TreeSet<String> index = new TreeSet<String>();

static int getOpponentID(String name) {
    index.add(name);
    return Arrays.binarySearch(index.toArray(), name);
}
8th August 2025

It's been over a year since my last update! I got disheartened by the inadequacies of my testing framework and the fact that the melee RoboRumbles for Code Size restricted bots include results for battles involving bots from outside of the weight class - I think we'd see some interesting changes to the leaderboards and which strategies are and aren't successful.

Since the itch to robocode returned I think I've found ways to squeeze a few more bytes out of Quantum, perhaps as many as 4-8. Sadly without a robust testing strategy it seems infeasible to find anything to actually do with those bytes besides adding colours back.

I've also spent some time watching IWillFireNoBullet move and have to say it's a thing of beauty. I highly recommend it to anybody with even a passing interest in Melee battles.

7th June 2024

My last couple of updates to Quantum have hammered home the point that my test benches don't reflect rumble performance nearly as well as I'd like - v1.2.1 and v1.2.2 performed similarly in my testing but quite differently to each other in the rumble. They both outperformed v1.0.0 by around 1% APS in testing but failed to live up to that when released. I don't think I can get away with putting off building a good testing framework any longer!

It's not a complete loss though. I've learned a lot, found a few more bytes to play with and I'm still confident that the approach to bullet power selection will yield better performance (eventually).

14th May 2024

Well, that was unexpected! The minor update to Quantum that I released reduced the codesize enough to allow me to fix the radar bug I added in v0.2.2 to make room for colours (Each time an opponent died there was a 50% chance the radar would switch directions). That bugfix was worth around 0.7 APS in the micro melee rumble, which was enough to push Quantum above HawkOnFire! I'm very excited to tune the gun...

13th May 2024

ProGuard didn’t manage to shrink Quantum at all and installing Jikes is a bit of a faff these days (on an Arm MacBook anyway) so I decided to try out Krakatau to work with the assembly code directly. It looks like I can make room for the gun to use quite a few attributes - distance, bullet power, number of opponents, lateral velocity and lateral acceleration should all fit. I definitely need to improve on the spaghetti shaped shell scripts I’m using to build and test my bots if I’m going to successfully tune the gun, but I reckon it’ll be worth it. Whether or not it’s enough to outperform HawkOnFire with a nano remains to be seen, but I’m hopeful.

10th May 2024

Sheldor's adaptation of Quantum (NaturalScience) motivated me to put development of a micro bot on hold. I had space for table based bullet power selection, albeit much simpler than Sheldor's, but only found marginal gains and tuning it by hand was both tedious and slow. I did manage to squeeze another 3 bytes out of my code though, bringing Quantum down to 239 bytes (without colours). There is room now for several different table based approaches but I'm going to need an automated way of tuning them. This leaves me with a nice todo list that will also benefit the development of other bots:

  • Try some other compilers, Jikes in particular
  • Add ProGuard to my build scripts
  • Build a test system that allows me to tune tables genetically
4th May 2024

I managed to find another half-dozen or so bytes in FireHammer which was enough to improve the movement a bit. I've entered it into the rumble and will run some battles overnight so we'll see where it ranks when I wake up in the morning.

Update: Can't complain about top 5 in the micros, although I was hoping to edge out Sprout to make top 3. This has confirmed my belief that a good circular gun is the way to go in a micro; 116 bytes for movement really isn't much to work with!

2nd May 2024

I've finally given FireHammer a better (but not good) movement without going over 749 bytes. Once I've tidied the code up it will be ready to enter the rumble! I'm torn on whether to release it now versus waiting until I have a minibot ready to challenge Mirage, I don't like to think about how much stronger Kev could make Mirage with all the extra space to play with!

26th April 2024

My experimentation with micro sized melee guns is paying off; I've finally managed to squeeze Mirage's amazing gun into a micro! The only (intended) functional changes are switching to Quantum's bullet power selection and going back to a fixed size for bot width as per Mirage v0.1.

So far I'm down to 733 bytes from a starting point of 919 (both without colours).

Results are promising despite only spending 21 bytes on movement to move in an Infinity style box pattern.

18th April 2024

I've started playing around with ideas for an entrant to the micro melee rumble. For now I'm looking at guns and mostly finding that DustBunny's gun seems to give excellent performance per byte and is difficult to improve upon. The next best thing seems to be a good implementation of Circular Targeting but ultimately I think that movement is where the money is.

I should probably turn my attention to finding the most efficient way I can to track enemy state, rather than relying on rolling averages, since the obvious HashMap approach introduces a lot of overhead. I'd also like to see if there's much to gain by switching from a basic nano style radar to something a little bit more sophisticated.

In short, challenging Wallaby for the micro crown isn't going to be easy!

14th April 2024

It turns out that Quantum is rather competetive! It knocked DustBunny off of the nano melee throne for a few days before settling in to second place. It still achieves a 100% PWIN and has by far the best survival score of any nano melee bot (and it has colours!). If I remove the colours I have 7 bytes to play with but I've not been able to find any changes that make a significant improvement. It would be interesting to see how the table looks once Quantum has run a similar number of battle to the other nanos (currently it's at less than 10%) however my rumble client has stopped working, which is a pain. Once we have internet again I'll see if I can get one of my low power machines setup as a dedicated client.

6th April 2024

I haven't had much time for robocode over the last month but I have been able to experiment a little with a nano melee bot, heavily inspired by DustBunny and Infinity. I'm quite pleased with the idea to calculate anti-gravity forces based on the angle my bot would fire at instead of the angle to the enemy's current position. This bot (Quantum) is my first entry into the Roborumble!

5th March 2024

My experiments with a nano Shadow/Melee Gun haven't gotten me the results I'd expected and I got a bit burned out from debugging it so I tried throwing a PM gun on which was okay but nothing to write home about. I think I'm going to experiment with different movements for a while for a change of pace. I've found I enjoy codesize restricted bots much more than megabots - I was getting a bit bogged down in top down development when I was allowed as much code as I liked.

28th February 2024
Targeting everybody at once, Nanobot version!

I've managed to get a (very) basic version of Shadow/Melee Gun squeezed into my Nanobot. At the moment it only aims (at everybody) with Head-On Targeting weighted by distance. Once I'm done with bug fixing I think I'll be able to find room to add another gun or two and/or better energy management into the mix.

27th February 2024

For the past couple of evenings I've been playing with nanobots for the first time. I'm interested in developing guns so decided to start by borrowing a movement from somewhere. Infinity was most appealing because its movement doesn't depend on the radar and only requires 68 bytes. I've managed to shrink the movement code by a further 15 bytes, giving me almost 200 bytes to use for a gun. ::Edit:: I've gotten it down to 35 bytes!

23rd February 2024

I'm wondering if there should be an equivalent page to Wave Suffering for Displacement Vectors. My early efforts at collecting displacement vectors with a codesize restricted gun have resulted in some interesting and wild arrows being drawn all over the place. I'm making progress but I'm sure that subtle bugs will continue to be found for quite some time. Still not sure I'll make it work with enough space left to pair it with decent movement but the experience will be helpful either way.

19th February 2024
A picture is worth a thousand words

Over the last couple of days I've fallen face first into the pit of premature optimisation. I noticed some interesting behaviour emerging as a result of my risk function and got carried away tweaking parameters and adding cobbled together versions of bits of code I'd not implemented in the hope of perfecting it. This predictably led to another pile of spaghetti code that needs (another) rewrite. /sigh.

15th February 2024

My experimental bot had become a pile of spaghetti so it got a rewrite today. I'm still pleased with core design principle, especially given how quickly I was able to experiment with an idea I've not seen mentioned on the wiki before (no spoilers :p). My initial assessment is that it shows promise but definitely needs refinement as my bot now has the tendency under certain conditions to turn into a melee rambot...

14th February 2024

My Robocoding time has been quite sporadic lately so it's been difficult to make progress on the ideas I have for a build system, testing framework and modular robot class. On the one hand that's disappointing because it's greatly slowing my efforts to develop an advanced melee contender however a few throwaway experiments have led to some interesting ideas for movement in mini (or possibly even micro) bots.

The movement appears to be doing a good job at evaluating risk despite using a spinning radar and tracking very little information on enemies. The code is a bit buggy and needs some improvement but I think a half-decent gun could be implemented that mostly reuses the movement code, which is very interesting.

At the very least the graphics displaying the risk evaluation are very satisfying to watch, even if these experiments don't find their way into a released bot.