Saturday, March 29, 2008

Robocode 1.6 explained

Why ?

During last Christmas I was seeking for some new toy and remembered Robocode, game or competition for Java programmers. I got an idea that I would rework Robocode for .NET. I sat down and wrote an email to Flemming N. Larsen, owner of Robocode. Soon we realized that we had common opinion about the need for support of other languages in Robocode. We were discussing various technical solutions how we could do it, including IPC messages and complete rewrite. Then I came with idea of IKVM as possible solution. During few days we hacked the prototype. Yep, Robocode for .NET exists, it is able to run both Java and .NET robots, paint the battlefield and it is pretty incomplete and unstable.

Update: 17.02.2010 Finally, Robocode .NET version works. It looks different than described here :-D

During prototyping I realized that I couldn't run AWT on top of IKVM, so we splitted Robocode UI from core and drafted new UI in WinForms.
This was first obstacle, need of split of UI from core "rules". I also hacked robot loader to be able to load .NET robots together with Java robots in same battle.

I started with reimplementation of robot base classes for .NET, because it support properties and naming convetions are different. I would like to make the robot classes look natively to .NET beginner programmers.
There I hit second obstacle, because pre 1.6 versions of Robocode could recognize only robot inherited from Robot class. So when you just inherit .NET robot from Java robot, there will be lot of methods from Java object or just named by Java convention. And this looks ugly in .NET.

Later when Flemming implemented drawing of the battle field (he learned some of GDI+ on it ;-), we hit third obstacle. WinForms are running in single thread only, but Robocode is running lot of threads and doesn't care about synchronization of UI much.

So the prototype showed us, that it is possible to share core of Robocode, but the code should be decomposed and refactored.

Version 1.6 is first step, introduction of robot interfaces, to get rid of necessity to inherit from standard Robocode base robots. I believe that the changes we do are not only for possibility of .NET version, but also for beauty of pure Java Robocode.

How Robocode works

Because lot of people don't have so much knowledge how Robocode internals works, let me first introduce you to the problem area. This is described from viewpoint of robot and oversimplified. Robocode
During start of battle round, for each "robot specification" RobotPeer instance is created. This class instance is containing "all the truth" about robot. It is then creating robot instance of "user" robot and start the "robot thread". This thread is that thing which is powering user code of robot, usually calling bunch of get() calls on base class and then it calls execution of some blocking command (for example move or fire). Blocking means that robot thread is blocked in the engine until engine cames to next tick. During tick all robots are examined (by battle thread) for commands issued, position, speed and energy and rules are applied. Then robot threads are resumed again, and redirected into EventManager to evaluate conditions of events. Events are called (still by same robot thread) back to user-land code of robot event handler. Usually there is another blocking command issued from that event handler, which is just nested (recursive call) on the stack.

Event interfaces

On the picture above you already can see one of new interfaces. The interface of event handler. Before 1.6 there were always the methods with same signature as on new event interfaces, they were empty handlers on robot base class and you could override them. This is still true. But now you can also decompose such event listener to some other class. You can see the example of it on AlienComposition robot from new sampleex package. I'm using such decomposition to hide the methods/handlers with Java-like naming convention for .NET base robots. Each robot kind (junior, standard, advanced, team) has some specific events, so there are multiple event interfaces. You can examine it on the picture below.

Robot interfaces

Till version 1.6, every robot should be inherited from Robot or JuniorRobot class to be recognized by Robocode engine. This is another degree of freedom which needs to be unlocked to implement nice base robots in .NET. So now you are not forced to inherit from Robot, instead you just need to implement IBasicRobot, IJuniorRobot, IInteractiveRobot, IAdvancedRobot or ITeamRobot. Each of them will allow you to provide different event handlers and you will be also given by IRobot*Peer which will support appropriate commands. There is also another improvement, so that IAdvancedRobot is not forced to be IInteractiveRobot. In other words, such advanced robots will run faster as they will not need to handle UI events.

I hope that one nice day someone will also use this interfaces to implement nice base robot for Jython or other languages on top of Java.

Peer interfaces

Till version 1.6, security of commands and queries executed by "user" robot code were guarded by robot base class. More advanced base class you inherited more possibilities you got. But more duties as well. Base classes were calling RobotPeer, which has full set of methods,which are not guarded any way. Now when we would like to allow you to just implement the interface, instead of inheriting from base class, we need to give you opportunity to issue commands and queries other way. But we still need to assure that you will not use more power than belongs to your robot kind. So we put protecting shield between base robot and RobotPeer. It is implemented by *RobotProxy classes, which implement I*RobotPeer interfaces. Now when you would like to implement issuing of command in your robot of base robot, you should call thru I*RobotPeer interfaces. This way we created secure layer and allowed robots to inherit from custom classes.

For most of users, inheritance from base classes is still right way how to do it. We are not trying to replace it, as it serve well. This is rather opportunity for very advanced coders to create new base classes with different architecture for others, or for other languages.

All together

All the new functionality described above should work transparently for all existing robots. The new features could be now used only when Robocode is started with -DEXPERIMENTAL=true command-line option, but this limitation will probably disappear in future versions.
I must admire Flemming for hard work on Javadoc for new interfaces. Also documentation of other classes was improved by him.
Robocode interfaces
I believe that decomposition we did is good thing, even for pure Java version, because separation of concerns.

In the pipeline

As you might guess, not all problems found during the work on the prototype were solved in Robocode 1.6. We are working on next steps.

First of them will be rework of RobotPeer, which will address synchronization issues caused by display thread. Most of this work in progress has been already done in this branch. RobotPeer was split into several parts by usage. By robot thread, by battle thread and by display thread. Data about robot state are also decomposed into separate classes, so they could be now fully synchronized. We also moved handling of interactive events from UI thread to robot thread by posting it thru EventManager queue, so you could change priority of such events. If you look at RobotPeer class now in 1.6 you will see big spaghetti implementation, this work should help it a lot. I didn't yet back-merged the changes to .NET branch, so I don't know yet whether it solved UI deadlocks. I will write another article when we get there.

After then we will need to split carefully UI from core, so that core could be reused in .NET. This was already drafted in .NET branch. I'm also thinking about more advanced modularization, plug-in infrastructure. Ideas are welcome.

When we will have that, we can build .NET version on top of it. We could implement UI visually compatible with Java version, or different, if someone will invent something better. The battlefield will be the same of course. We should also think about version control options. For now we are just merging the branches.
After then I dream about IronPyton and IronRuby robots built on top of it ;-)

Feedback

We need lot of feedback and we need it now when 1.6 is Beta. I guess that we will have few weeks of time, before we reach release and will merge interfaces branch to the trunk.

We need lot of testers. Please try to run your historic robots, they should run just OK. Please try to play with new interfaces, so that we could get your feedback. The interfaces will become new API between robot and engine. That means that they will live with us long time, so please review them and shout now, if you don't like them (and have better ideas). Please try also to broke security of the solution, in both legacy and experimental mode.
Questions are also welcome.

Thanks a lot!

Update: 02.04.2008
Just to make it clear: 1) Robocode will stay 100% Java, my IKVM extension will be just build on top of it, so you will be able to run on any Java enabled HW or OS as usually.
2) We still don't have plan how Java only users could run .NET robots, for example in Roborummble. Rednaxela is proposing JaCIL. Ideas and prototypes are welcome.
3) We are looking for someone who will help us design and prototype plugin, which will allow to load robots in other languages running on JVM.

9 comments:

3rojka said...

Celé sem to nečetl, ale graficky se mi moc líbí ty tvoje UML diagramy v čem to děláš?

Anonymous said...

As I understand, you're thinking (and not just thinking) about development and evolution of Robocode in other, then Java, programming languages, particularly on .NET platform.

On Java, platform Robocode receives such a great tool for measuring logical complexity of robots as measuring robots' bytecode size. Thus, one can say that a Mini robot is more complex than a Micro. This is possible due to Java platform properties.

My question is how do you plan to compare complexity of robots on .NET platform, and particularly compare complexity of robots implemented in different platforms?

Z said...

vitaliy,

we have still lot questions to answer. Your q is one of them. Just from top of my head, I guess that we could measure number of CIL instructions (maybe using .NET reflection, maybe with CECIL from Mono). And then find some constant rate, which will help us to set fair rule. You are welcome to contribute ideas as well as implementation.

Z said...

3rojko,

je to Enterprise Architect.

Unknown said...

Supporting robots coded in compiled JVM languages[1] is easy--just open up the CLASSPATH.

The compilers for these languages produce .class files that depend on the runtime JARs of the language's standard library. In most cases, the only thing stopping them from working today is Robocode's refusal to load their standard library classes from the CLASSPATH.[2] After lifting this restriction, the robot coder just has to add the language's standard library to their CLASSPATH to make their robots work.

For example, I got robots compiled in Scala to work by patching robocode/peer/robot/RobotClassManager.java to allow loading of scala.* packages from the CLASSPATH.

Allowing loading arbitrary classes from the CLASSPATH may seem like a security hole waiting to happen. But, assuming Robocode's sandboxing is solid, classes loaded from the CLASSPATH don't have any more privileges than classes the robot coder wrote. You just need to harden the class loader to resist other JARS clobbering the robocode.* namespace.

Interpreted languages will require much more invasive changes, but that's for someone else to ponder.

Footnotes:

[1] JVM languages which produce .class files that look like normal java .class files.

[2] Currently Robocode will only load classes from the CLASSPATH if they are in the java.* or robocode.* packages.

Z said...

Duy,

please search this group and join us
http://groups.google.com/group/robocode-developers?hl=en

to discuss it.

Flemming N. Larsen said...

Duy:

I really like your comments! And I agree with you. As soon as I get more time for it I will do exactly as you propose as it makes perfect sense. :-)

If you fell like it, please join us at the Robocode Discussion Group here (as Pavel proposed):

http://groups.google.com/group/robocode-developers?hl=en

Unknown said...

you can try to write a robot using Mainsoft Grasshoper - it is a free version. it's not really .net but you can write your robot in C# and compile directly to j-b (and f.e. link with other jars)

FReNeTiC said...

It's a very nice idea. But why running to .NET?

I'm not complaining. But, what about try languages like Python or Lua?
I thjink those two languages are very easy for people that are starting to program, and having a platform like robocode where they can play and have fun would encourage them to pratice.

Well, it's just my opinion.

Last month my college promoted a robocode championship and my friend and I got second place. We are not java programmers. My friend is a really good C# programmer and if you are done with .NET robocode next year we will be champions!
=D