C Robots for the web

Background

I have always been fascinated by the idea behind crobots also inspired by RobotWar on the Apple II. A simple robot simulation environment where you can program your own autonomous robot in a simple language and then battle against other AI robots.

I started a project in Java (jrobot) where the idea was that each robot would be a JAR file which which could be loaded by the simulator (on any platform) and keep its own updated state after competitions.

Another improvement would be to support many programming languages. One common programming API nowadays are the HTTP. So the next idea is to build a simulation environment over a HTTP api. As any programming language can support the web this would make it very easy to build robots in different languages.

Web Robots

So the simulation environment is accessed over an HTTP api.

Simulation is divided in three phases.

  1. Simulation setup - create simulation environment, add robots and start simulation
  2. Battle - each robot move, scan, fire and robot state can be accessed
  3. Finalize - winner is determined and detailed simulation data can be retrieved

Simulation is time based where missed deadlines will result in missed opportunity to control the robot.

A separate program can be used to visualize the battle from the detailed simulation data.

HTTP API

Setup

Battle

Finalize

How to synchronize clients over HTTP?

Each client must be allowed to send its command and get a result in each time synk.

Because the result of each simulation step is based on the actions of the other opponents we need to wait until we get all commands before we can return a result. If one client doesn't send a command within a timeout period that client will miss the opportunity to command the robot during that time slot.

This requirement doesn't work well with the typical HTTP request/response scheme where a request is assumed to get a response directly.

One solution would be to poll for the result after a command was sent.

send command
poll for result -> no result (all clients has not sent a command)
poll for result -> no result
poll for result -> return result

This would work in most web servers even non-concurrent ones like sinatra.

Another strategy would be to block each request until the last client sent its requests and then return the result from the simulation step. This would require a concurrent web server and some synchronization between request handlers on the server side.

send command -> return result

The advantage with this solution is that polling is avoided and the result can be returned directly in the command request. This also makes it possible to run the simulation faster. A new command can be sent directly after the first request returned. Polling also means wasted resources on both the client and server which can be avoided.

But on the other hand this puts additional requirements on the web server capabilities.

Yaws is a Erlang web server which seems to be capable enough.

"Yaws is entirely written in Erlang, and furthermore it is a multithreaded webserver where one Erlang lightweight process is used to handle each client."

Process commands

We assume a persistent database accessible for all request handlers.

The following tables would be needed:

A command request could be handled the following way:

  1. Store command including pid of receiving http handler process and association with current simulation step
  2. Try a simulation step (thread). IF simulation step can be calculated (all clients has sent a command), notify all handlers on the result.
  3. Wait for (receive) for simulation result (from simulation step handler)
  4. Return simulation result.

Alternatively the responses could be delegated to a simulation handler. Then http request handlers may exit and the simulation handler take over to send all responses. But I don't know if responses can be delegated to another process.

The http request handler

  1. Get which Battleground the received command is associated with
  2. Get current SimulationHandler (if none create a new one)
  3. Send response handler and command to simulation handler

And in the SimulationHandler ...

  1. Wait for (receive) simulation commands with a timeout
  2. Update simulation state in mnesia
  3. Return simulation results for all commands

Code sketch

Sketch of code. Does it work now?

Battle
  id = 123
  size = (100, 100)
  commandTimeout = 1000 [ms]

Robot
  id = 456
  position = (x, y) -- position on battleground
  angle = Angle     -- angle of tank
  aim = Angle       -- angle of tower relative tank

Error
  code = 234
  message = "battle has not started"

Battle

create :: Battle
enter  :: BattleId -> Robot        -- get initial robot
start  :: BattleId -> [Robot]

Wait

ping :: RobotId -> Timeout         -- ping to start

Play

walk :: RobotId -> Steps -> Robot  -- available commands
turn :: RobotId -> Angle -> Robot
aim  :: RobotId -> Angle -> Robot
scan :: RobotId -> Robot -> Int
fire :: RobotId -> Robot

Simulation Tracer

Visualize a battle from simulation data.

This will probably be implemented in Elm language as fat web client.

Building elm-lang on OpenBSD

Current implementation

This is under active developement..

See latest implementation here: RobotWars

References