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]