I spent an afternoon playing around with Sodarace, collecting information on how I could interface an AI application to it. Sodarace creatures (called models) don’t have any controllers, but AI could be used in the construction of their bodies.
I created a thread on the sodarace AI forums, but have included that information here, along with a few other things I’ve found out.
They have API documentation and the DTD for the model XML.
There are two existing “use AI to create/optimize creatures” projects, Wodka and AI Central’s SodaRace.
And a re-implementation of Sodarace with a few changes:
The maximum values for:
gravity: 4.0
friction: 1.0
springyness: 0.5
The Soda Ultimate Race!!! thread has some good terrains, such as the “agility” terrain on page 3: http://sodarace.net/upload/SodaBuilder/AgilityZone.jnlp
Here’s a simple python client that evaluates a single model:
import socket model = """<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?> <!DOCTYPE sodaconstructor> <model> <container width="651" height="422"/> <environment gravity="0.2938248" friction="0.05031007" springyness="0.20193903"/> <collisions surface_friction="0.1" surface_reflection="-0.75"/> <wave amplitude="0.5" phase="0.0" speed="0.009803922"/> <settings gravitydirection="down" wavedirection="forward" autoreverse="on"/> <nodes> <mass id="m0" x="294.0" y="265.0" vx="0.0" vy="0.0"/> <mass id="m1" x="220.0" y="122.0" vx="0.0" vy="0.0"/> <mass id="m2" x="340.0" y="122.0" vx="0.0" vy="0.0"/> </nodes> <links> <muscle a="m0" b="m1" restlength="161" amplitude="0.54761904" phase="0.7529412"/> <muscle a="m1" b="m2" restlength="115.0" amplitude="0.52380955" phase="0.5019608"/> <muscle a="m2" b="m0" restlength="147.80054" amplitude="0.71428573" phase="0.2509804"/> </links> </model> """ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('localhost', 7777)) sockfile = sock.makefile(mode='r+') # Read and check the header header = sockfile.readline() assert header.startswith('Hello client: ') print "Connected to sodarace" # Read and check the request request = sockfile.readline() qmark_pos = request.find('?') assert qmark_pos > 0 print "got request: ", request id = request[0:qmark_pos] # Send the model sockfile.write(model) sockfile.flush() print "Sent model" # Wait for the finishing time while True: racer = sockfile.readline() print "Received: ", racer if racer.startswith(id + '>'): break print "Time: ", racer[racer.find('>')+1:-1]