botZilla : A Programming Challenge.

by Steve Baker

INTRODUCTION | SCREENSHOTS | ABOUT | RULES | FAQ | INTERNALS | DOWNLOADS | INSTALLING | KNOWN BUGS | PROJECT PAGE | MAILING LIST

About this Document

As I write this document, I am still tuning the game parameters. So rather than telling you specific numbers for ranges, speeds, damage rates and such and risking making a mistake in transcribing them into this document, I'll simply refer you to the 'zilla_internals.h' header file which has the values for all of these things clearly defined.

Whilst I do not intend to change any of these numbers on a frequent basis, it would be wise to code your program to use those symbols where possible so that an unforseen need to change the rules won't totally destroy your careful work!

The Rules:

Each contestant submits a C or C++ program to control a virtual BotZilla. These programs will be linked into a simulation that lets these monsters battle it out in realtime in a virtual city while we feeble humans can only stand and watch.

It's a contest of programming skill and algorithmic subtlety.

The Software You Must Write:

The software you write must consist of a single source file that compiles into either a '.DLL' or a '.so' library. These libraries are dynamically linked into the 'City Simulator' that runs the game.

Your library should export just one symbol - a function called 'runZilla'. For C++ programmers: This function must be declared 'extern "C"' so that it can be called with C calling conventions.

The runZilla() function takes a pointer to a simple structure as it's input and another pointer indicates where it should write its results:

  In C:

    void runZilla ( struct ZillaInputs  *input,
                    struct ZillaOutputs *output ) ;

  In C++:

    extern "C" void runZilla ( ZillaInputs  *input,
                               ZillaOutputs *output ) ;

The contents of the two interface structures are defined in "zilla_interface.h" which should be the only '#include' at the top of the file.

Representation of Angles, Headings, Times and Distances

All distances in the game are in meters, all times are in seconds and all angles are in degrees with positive angles being anticlockwise and all numbers being in the range -180 to 180. Directions are represented as an angle with Zero being north, 90 is therefore West, -90 East and either +180 or -180 could be South.

ZillaInputs

The ZillaInputs structure contains all of the information about the current state of your robot - including inputs from it's external sensors and it's internal state. The entire structure is recomputed at the start of each turn - so you can write to it if you want - but whatever changes you make will be erased on the next iteration.

ZillaOutputs

The ZillaOutputs structure contains all of the controls that your software uses to operate the virtual robot. The City simulator checks that you don't demand more speed or turn rate than the robot is capable of - and that you don't exceed it's energy reserves. Speed and turn rate are clamped to the robot's maximum and if you try to consume energy you don't have - then your command simply won't happen.

The public Zilla structures look like this:


struct EnemyZilla
{
  int   visible ;    /* Remainder of structure is invalid if this is FALSE */
  float heading ;    /* Degrees, Zero is NORTH, positive anticlockwise */
  float energyRemaining  ; /* Expressed as a percentage of maximum en
ergy */
  float healthRemaining  ; /* Expressed as a percentage of full healt
h */
  enum ZillaAction action ;  /* What is he doing? */
} ;


struct ZillaInputs
{
  float energyRemaining  ; /* Expressed as a percentage of maximum energy */
  float healthRemaining  ; /* Expressed as a percentage of full health */
  int   collectable      ; /* Which collectable are you holding right now?
                              One of:
                                MAP_COLLECT_ENERGY
                                MAP_COLLECT_HEALTH
                                MAP_COLLECT_TIMESLOW
                                MAP_COLLECT_SPEED
                              or -1 if you have no collectable on board */
  int   usingSpeedup     ; /* 1 if you are using a Speed collectible, 0 otherwise */
  int   usingTimeSlow    ; /* 1 if you are using a Time-Slow collectible, 0 otherwise */
  float elapsedTime      ; /* Seconds elapsed since start of round */
  float currentHeading   ; /* Degrees: Zero is NORTH, positive anticlockwise */
                           /* Angle is always between -180 and 180. */
  int numRobotsRemaining ; /* The number of other bots still alive */

  unsigned char map [ MAP_SIZE ] [ MAP_SIZE ] ;  /* See documentation */
  struct EnemyZilla enemy [ NUM_ENEMY ]       ;  /* See documentation */
} ;


enum ZillaAction
{
  MOVE ,
  CHOMP,
  SHOOT,
  RAGE,
  USE_COLLECTABLE
} ;


struct ZillaOutputs
{
  float turnRate  ;  /* In degrees per second, positive is anticlockwise */
  float moveSpeed ;  /* In meters per second - always positive */

  enum ZillaAction action ;  /* Only one action per iteration! */
  char name [ MAX_NAME_LENGTH ] ;
  char speech [ MAX_LINES_OF_SPEECH ] [ MAX_SPEECH_LENGTH ] ;
} ;

The zilla_interface.h header also contains a large number of commented #define's for various constants.

The 'map' and 'enemy' arrays in the ZillaInputs structure are described below.

HEALTH AND ENERGY:

Each bot has both 'health' and 'energy' - both start out at 100% and may be depleted or restored by various means. There are on-screen indicators for health and energy so you can see how your bot is doing relative to the competition. By looking at the 'enemy' array (see below) allows you to see how much health and energy each visible enemy has.

THE MAP:

The ZillaInputs structure contains a two-dimensional array of unsigned char's that represents a top-down view of the current state of your world. The map is a MAP_SIZE x MAP_SIZE grid with your botZilla in the center. Each square in the grid represents an area GRID_SIZE x GRID_SIZE meters. The first array index is the North/South direction (positive North), the second is East/West (positive East). Hence, your BotZilla can 'sense' things out to about MAP_SIZE*GRID_SIZE/2 in every direction. Hence the data in input->map[Y][X] represents a point (Y-MAP_SIZE/2)*GRID_SIZE to the North of you, and (X-MAP_SIZE/2) to the East.

The map contains data to show where buildings, force-fields, rubble and enemy BotZilla's are. The value in each grid cell is either a number in the range 0..(NUM_ENEMY-1) or a #define'd token above that range.

Zillas may move freely through empty areas (roads, etc) and across rubble. They are stopped when they touch a building, a force field or another Zilla.

When a zilla just drives mindlessly into another bot or into a building, it'll gradually do damage to it - but not as fast as a series of 'CHOMP' attacks.

THE FORCEFIELD

The city is surrounded by a forcefield that does great damage for Zillas that come in contact with it.

After some unspecified time (typically a couple of minutes), the force field will start to shrink. This forces the game to end within a finite amount of time no matter how stupidly (or effectively) the bots are being driven. The forcefield will start to shrink when the 'elapsedTime' field reaches FORCEFIELD_SHRINK_START_TIME and will have shrunk to zero size (killing all 'bots in the process) by FORCEFIELD_SHRINK_FINISH_TIME.

If you touch the forcefield while it's shinking, it'll be very hard to avoid being completely embedded in it which is certain death for a bot. It's essential to give the forcefield a wide berth once it's shrinking!

THE ENEMY ARRAY:

This array contains one element for every possible enemy (there could be as many as MAX_ENEMY). If this enemy is visible then the number you'll find in the 'map' can be used as an index into this array to find more information about the robot you can see.

Each structure contain a boolean called 'visible' which tells you whether you can see this enemy on the map, also the current 'heading' that the robot is pointing at (0==NORTH, positive anticlockwise, all numbers in the range -180 to 180). There are also 'energyRemaining' and 'healthRemaining' fields so you can see how the other robot is doing.

ATTACKING:

Doing an attack takes a short amount of time during which the Zilla can do nothing else and it's software does not get executed. The time these take - and the energy they consume is defined in the zilla_interface.h file.

If a Zilla does a 'CHOMP' action while standing next to a building - or attempts to walk through the building, it'll damage it. Shooting or doing a rage attack will also damage buildings that happen to get in the way. The amount of this damage is listed in the header file. Whilst a chomp attack consumes no energy, your bot doesn't recover energy during the time the chomp takes - so it's not without cost.

Shooting drains the Zilla's energy reserves. Each shoot action reduces your reserves by an amount defined in zilla_internals.h - and does damage to any Zilla standing directly in front of you, providing it is within range and with no buildings or other Zilla's are in the way.

A 'Rage Attack' is a blast of energy that radiates out in all directions, and consumes 100% of your energy reserves. The blast damages any Zilla within range - regardless of whether they are hiding behind something - and it instantly flattens any buildings that are within the blast range.

If you do an attack inappropriately (eg if you don't have enough energy - or if you weren't close enough), you don't pay the energy penalty - but you do get held up for the time an attack would actually take.

MOVING:

At any time when you aren't attacking, you can turn and move by setting the turn_rate and move_speed variables in your ZillaOutputs structure. The maximum forward speed and turn rate is defined in the 'zilla_internals.h' file. You can also input a negative speed and move slowly backwards.

COLLECTABLES:

Scattered randomly around the arena are 'collectables'. These can be picked up merely by walking into them - at which point you 'own' that collectable and another one will pop up randomly somewhere else to replace it.

Each robot can only hold one collectable at a time. There is a special action called 'USE_COLLECTABLE' which activates (and removes) whatever collectable you are currently holding. You can then pick up another one - even while the effects of the first are still working.

On-screen, the four collectable types are marked with a spinning icon with a letter on it:

NOTE 1: If two or more robots activate TimeSlow collectibles - all operate at normal speed while everyone else is slowed down. Even if your TimeSlow time expires, you continue to operate normally until ALL TimeSlow effects run out.

NOTE 2: BEWARE: If you slow time, the damage you take from a forcefield accumulates at a normal rate for you - whilst everyone else is taking forcefield damage more slowly.

You can tell what collectable you are carrying from the ZillaInputs structure - also whether you are currently slowing everyone elses time down and/or are under the influence of a Speed collectable. Robots who are being slowed down can't tell (except by the fact that one of the other robots is moving so much faster!)

SPEECH BALLOONS:

There is a 2 dimensional array of characters in your ZillaOutput structure. If you write text into that array, it will appear in a speech balloon over your robot's head. This has no effect whatever on the game play. Please be VERY careful to NULL-terminate your strings and not to overflow those arrays!

eg:

   strcpy ( input.speech[0], "Hello" ) ;
   strcpy ( input.speech[1], "World" ) ;
Each row of the 'speech' array represents a separate line of text. There are MAX_LINES_OF_SPEECH rows of text, of MAX_SPEECH_LENGTH characters each (including the null byte). MAX_LINES_OF_SPEECH will always be at least 2 and MAX_SPEECH_LENGTH will always be at least 10 - so you can definitely have two lines of text of 9 characters each (plus the null byte).

INITIALISATION:

On the first occasion that your robot is called, you must strcpy the name of your robot as a null-terminated string into 'output->name'. The maximum length of this string (including the NULL byte at the end is MAX_NAME_LENGTH. Doing this again after the first call has no effect.

For One-On-One competitions:

At the start of the competition, your robot will be placed at the center of a random road intersection inside the City boundaries - but not within MIN_INITIAL_RANGE of another robot. You'll be facing in a random direction.

For All-Against-All competitions:

Due to limited space in the City model, it may not be possible to start off with the robots separated by MIN_INITIAL_RANGE - so all the system will guarantee is that the robots won't be touching at the start.

The Fine Print:

The following rules must STRICTLY be followed - breaking one will disqualify your program.

  1. The program must be delivered in a SINGLE source file called 'robot.c' (or 'robot.cxx' if it's in C++). No header files, data files or other libraries are allowed.

  2. All global symbols used within the program must be declared 'static' except for ONE external function that must be named: runZilla.

  3. The only header file you are allowed to include is 'zilla_interface.h'

  4. The only library functions you are allowed to call are defined for you in zilla_interface.h - they are: Notice that no standard I/O or stream I/O functions are included.

  5. The runZilla() function takes a pointer to a simple structure as it's input and another pointer indicates where it should write its results:
      In C:
    
        void runZilla ( struct ZillaInputs  *input,
                        struct ZillaOutputs *output ) ;
    
      In C++:
    
        extern "C" void runZilla ( ZillaInputs  *input,
                                   ZillaOutputs *output ) ;
    
    
    The contents of the two interface structures are defined in "zilla_interface.h"

  6. The runZilla function will be called between 10 and 100 times per simulated second. (If the underlying hardware can't run things that fast, simulation time will run slower than realtime). The current simulation time is provided in the ZillaInputs structure on each call. Don't rely on a particular iteration rate to make your algorithm work!! When timeslow is activated, all robots will be told time from their perspective.

  7. To keep the game running smoothly for the sake of the audience, your function must return within 1 millisecond on our target hardware (which will have at least a 2GHz CPU).

  8. Programs may not return Not-A-Number (NaN) or Infinite (Inf) numbers in their ZillaOutput structures. The consequences of doing so are to cause the 'bot to freeze for that iteration - taking damage as usual but unable to move, shoot, rage or chomp.

  9. You may not consume more than 1Mbyte of RAM within your library.

  10. The C or C++ library must conform to current C/C++ standards without using compiler-specific extensions. The final contest will be run on a Linux PC with a recent GCC/G++ compiler used to compile the bot programs.

  11. All robot programs must be provided as source code via email to the contest organiser in time for them to be judged for illegal content and tested to give a reasonable indication that they are robust and do not routinely crash.

  12. Code must be provided free of copyright and must not contain licensed or patented material and will be published as example programs for the following year's contest.

  13. Programs that attempt to gain advantage by deliberately corrupting memory or otherwise disrupting the operation of the simulation will be eliminated from the competition.

  14. Any program that crashes the simulation or breaks any of the rules is eliminated from the competition. Since it is sometimes hard to determine which part of the system caused a crash, the Judge's opinion is final. If any of those situations arise during the 'last man standing' round then the round will be restarted without the offending robot. Please work hard to make sure this doesn't happen because of you!

  15. The City Simulator software is subject to change in the unlikely case that serious bugs are found in it leading up to the competition. All effort will be made to keep the interface to the your function the same.

A WARNING ABOUT THE GRAPHICS:

The graphic display of the game is intended to look cool for the audience and to help with debugging - but it is NOT intended to represent the 'ground truth' of the game. As far as your bot is concerned, the world is a boring, flat, two-dimensional place - buildings are solid and completely fill the grassy area within their block - rubble is the same as empty space. No matter how their graphic representation looks, all bots are circular and identical in size.

For example: