Modularity is Popular
I think all the big bots use something like this? I mean Shadow does, my (bigger) bots do, who else? Mine in particular handles paint and robot color functions, and in Genesis tracks time, data and properties loading. It overlays it own methods for onScannedRobot, handles the radar and does many many other things I mostly forgot about, and it all does this with the data from a interface called 'Constants' (meaning colors, propertie file name, property names and numbers, etc. --Chase-san
It's not too surprising that the same people that enjoy programming for fun would also tend to build their bots with more modular designs, though some are certainly more "pluggable" than others. (Dookious is pretty clean code, IMO, but it would be easier to implement a new Wave-based gun than a new PatternMatching gun.) In addition to all the usual reasons for doing so (ie, in a profession), with Robocode it has the additional benefit of keeping me more motivated to work on my bots. PrairieWolf is a classic (one of the Ancients) that uses some kind of pluggable design for its MultiMode strategies. -- Voidious
Yeah, it does not surprise me that modularity would be a popular topic. Here's a bit more about how PluggableRobot works. Basically, PluggableRobot allows you to register Listeners, Components and Painters.
- I define a listener interface for each of the Robocode events, and any objects which implement the interfaces and register themselves with the bot will be notified of those events. The really nice thing is that PluggableRobot gives much better control over the order in which notifications are given; listeners are notified of events in the order that they are registered, and each listener gets the events in the order that the corresponding listener interfaces are declared. So a class with a declaration like
public class MyClass implements EventListener.ScannedRobot, EventListener.Deathwill get notified of the ScannedRobotEvent *before* the DeathEvent. Pretty handy. All of this happens inside a custom event test as discussed on the EventManagement page. I don't actually make the robot do anything at this stage; this is just for data collection and processing.
- Components are where I actually make the robot do stuff. Each component has a go() method that gets executed in the main loop of the robot. Like the event listeners, they get called in the order that they were registered.
- Similarly, painters have a paint() method that gets called when it's time to paint debug graphics. In the onPaint() method on the robot I inject the Graphics2D object into a custom object I've created called the Hud, which takes care of icky stuff that Graphics2D expects, like downcasting (Is that a word?) from double to int, translating angles to degrees, etc.
- Pluggable robot also defines initializeBattle() and initializeRound() methods.
Working on version 2.0
So I've been absent a long time, but I've been changing PluggableRobot some. Mainly because some changes to Robocode made it so PluggableRobot doesn't paint debug graphics anymore, and partly because I thought of some additional things I could do with it. When I'm finished, I'll update the source code on the wiki. RobertWalker 15:36, 4 May 2009 (UTC)
- I'm very pleased to know how many Robocoders that isn't forgot robocode already. Hoping the robocode community will be as active as the past. May I asked you to merge the DrawingBot and User:Nfwu/Painter to the PluggableRobot? It seem far more effective that your Hud. And can make the ListenerDelegate class warning-free with generic under java5? » Nat | Talk » 15:43, 4 May 2009 (UTC)
- Yeah, I was actually thinking about changing both of those things. I'm a little confused as to why exactly the ListenerDelegate is giving me the warnings; maybe you could enlighten me? Generics are awesome, but sometimes they give me migraines. I've tried various things to try to resolve it, but the warning either remains unchanged or I get a different one. As for the Hud class, I was planning on completely reworking that, but I didn't have any thoughts yet as to exactly how. I'll be sure to take a look at User:Nfwu/Painter and DrawingBot for ideas. Any other ideas for improvements while I'm at it? RobertWalker 15:23, 5 May 2009 (UTC)
- I try to generic-ize you ListenerDelegate before, but I can't make it warningless. I have problem with some thing so if I generic-ize the Class<EventListener> and vice versa, I'll have an error in the processEvent() method so I revert to the non-generic version =( » Nat | Talk » 15:43, 5 May 2009 (UTC)
- Well, the more I monkeyed around with it, the more I felt that generics were just making things unnecessarily complicated in this case. So I removed generics from the Invoker class, and changed it to have a consumesEvent(Event) method instead of an eventClass() method. This has cleared up all the warnings. The only bummer is that I lose some compile-time type checking, but the ListenerDelegate is built to ensure that the events get handed to the correct listeners in the first place, so I'm not terribly worried about it. Now to give it better painting support! RobertWalker 17:38, 8 May 2009 (UTC)
- Yeah, I was considering that, but when I can, I prefer to solve warnings rather than ignore them. In any case, the code is easier to follow without the loads of generics stuff cluttering it up. Usually, generics make things simpler, but in this case.... Anyway, I'll post new source when I finish writing the other changes I'm working on. RobertWalker 02:33, 9 May 2009 (UTC)
I'm putting together the new debug graphics code. Like before, you register objects that are interested in drawing graphics with PluggableRobot, and they'll get invoked when it's time to paint. However, I'm also incorporating layering behavior similar to User:Nfwu/Painter. All debug code will be modularized for efficiency. For example, PluggableRobot will avoid wasting time on logic dealing with debug graphics if painting is disabled. It will also be easy to completely disable debugging code if you like before releasing your robot. (Although, if you release the source with it, it's also easy to turn it back on.)
Some other things I'm planning on for the new PluggableRobot revision:
- Some basic, optional components that could be used directly, extended, or used as example code for your own components. They would be things that a lot of robots would need anyway, like a data collection object or a 1-on-1 radar module.
- A tweaking framework that would allow you to declare properties for your robot, then run a separate application that would test a range of different values for those properties and report on the results in combat. For example, let's say your robot has a property that controls the preferred distance your robot wishes to maintain from the enemy, and you'd like to figure out what the best value for this property would be. You'd configure the tweaking framework to test a range of values for this property, and then it would run a bunch of battles, storing the results in an database. When it was done, you could then run a viewer that would display the results with fancy graphs and such.
I welcome your feedback. RobertWalker 15:30, 11 May 2009 (UTC)
Awesome! Actually I don't think it is easy to re-enabled it if you release the source code. =D
- I'd suggest you do release a plain version without it and release its extension which doing those thing. Anyway, I think that thing will be used by only your own =P
- I don't really get the point what you are going to do with that thing, really. Please explain more.
Okay, so when you're coding your bot, you will likely encounter places where you will create a constant. Let's say you need to set how many bins to use in your guess factor calculations. So you might write something like this:
private static final int BINS = 25;
But how do you know that 25 is a good number of bins? How do you figure out what the optimal number of bins is for your robot? This is where the tweaking framework comes in. I haven't fully coded it yet, but it would look something like this. First, you'd replace the hard-coded 25 with something like this:
private static final int BINS = Props.getInt("guessfactor.bins");
The Props class would statically load a properties file out of your data folder, which would contain a line like this:
So now it's time to run the tweaker program. It would give you a list of the robots in your library, and you'd select the one you want to tweak from the list. It would then read the properties file and auto-detect the possible types of each (boolean, int, double or String). So you'd select "guessfactor.bins" out of the list and select int as its type. You'd then provide a range of values to test. You want to have an odd number of bins (so that a bin always falls directly at 0.0), so you configure it to test values between, say, 7 and 49, incrementing by 2. You'd then select what robots you want it to fight against and how many rounds to fight each bot.
Once you hit "Run", the program would back up your properties file, and write a new one with guessfactor.bins=7. It would then run battles between your bot and the others you selected, similar to RoboRumble, and store the results in memory. It would then increment guessfactor.bins to 9 and run the battles again, and continue in this way until it gets to 49.
Once it has finished, it will write a report of the results to a file, and restore the backed up properties file. You can open this file in a viewer that will show you a fancy chart of your bot's performance over the different values and show you which one did best.
What do you think? RobertWalker 18:43, 11 May 2009 (UTC)