The Python binding
The Clunkyard robot API in Python, over the robot core's C ABI through
ctypes (docs/design/robot-core.md,
section 5.3). clunkyard/_api.py is generated by
protocol/v2/codegen/bindings/python.js (make api); the run loop in
clunkyard/__init__.py and the loader in clunkyard/_core.py are written by
hand. docs/sdk/names.md gives every name.
- Install:
make install SDK=/opt/clunkyard/sdkcopies the package, compiled, into$(SDK)/bindings/python. It needs no compiler at run time. - Run:
PYTHONPATH=/opt/clunkyard/sdk/bindings/python python3 bot.py. The package loadslibclunkyard.so.2through the loader's cache, or the fileCLUNKYARD_LIBnames. - Test:
make test SDK=...runs the installed package against every API vector, exact against the core.
Subsystems are attributes of the robot (self.me, self.match,
self.scanner.last); facts are properties and the rest are calls. A control
sets only the fields given, so self.drive.set(turn=0.5) keeps the throttle,
and self.drive.get("throttle") reads a field back. An absent result is
None. cy.angles holds the angle helpers, the core's to the last bit. Raise
cy.Forfeit(code, message) to forfeit; any other exception is logged with its
trace and the turn answers with what it had set.
A tiny robot
import clunkyard as cy
class Tiny(cy.Robot):
def on_turn(self):
target = self.sensors.nearest
if target is None:
self.drive.set(throttle=0.75, turn=0.25)
self.scanner.set(heading=self.me.heading, arc=40)
self.status.set("SEARCH", self.scanner.last.arc)
return
power = self.gun.power_for_flight_time(target.range, 1)
aim = self.gun.lead(target, power)
if aim is None:
self.gun.aim(target.bearing, target.elevation)
else:
self.gun.aim(aim.heading, aim.pitch)
if self.gun.can_fire(power, 10):
self.gun.fire(power)
self.drive.set(throttle=0.5, turn=cy.angles.clamp(cy.angles.angle_diff(target.bearing, self.me.heading)))
self.scanner.set(heading=target.bearing, arc=10)
self.status.set("TRACK", target.range)
cy.run(Tiny())
Names
Every entry of the robot API 2.0.0 in Python. names.md has every language side by side.
| Canonical | Form | Python |
|---|---|---|
match.mode |
property | self.match.mode |
match.ruleset |
property | self.match.ruleset |
match.control |
property | self.match.control |
match.robots |
property | self.match.robots |
match.is_3d |
property | self.match.is_3d |
match.tick_rate |
property | self.match.tick_rate |
match.max_ticks |
property | self.match.max_ticks |
match.robot_id |
call | self.match.robot_id(slot) |
clock.tick |
property | self.clock.tick |
clock.seconds |
property | self.clock.seconds |
clock.remaining_ticks |
property | self.clock.remaining_ticks |
arena.size |
property | self.arena.size |
arena.gravity |
property | self.arena.gravity |
arena.terrain_kind |
property | self.arena.terrain_kind |
arena.ground_height |
call | self.arena.ground_height(x, y) |
me.health |
property | self.me.health |
me.position |
property | self.me.position |
me.velocity |
property | self.me.velocity |
me.heading |
property | self.me.heading |
me.pitch |
property | self.me.pitch |
me.roll |
property | self.me.roll |
me.angular_velocity |
property | self.me.angular_velocity |
me.attitude |
property | self.me.attitude |
me.grounded |
property | self.me.grounded |
me.altitude |
property | self.me.altitude |
me.applied |
property | self.me.applied |
battery.charge |
property | self.battery.charge |
battery.capacity |
property | self.battery.capacity |
battery.regen |
property | self.battery.regen |
battery.sustainable_drive |
property | self.battery.sustainable_drive |
battery.compute |
property | self.battery.compute |
battery.drive_cost |
call | self.battery.drive_cost(fraction) |
drive.hover_lift |
property | self.drive.hover_lift |
drive.set |
control | self.drive.set(throttle=None, turn=None, pitch_turn=None) |
drive.forces |
control | self.drive.forces(thrust=None, strafe=None, lift=None, yaw_torque=None, pitch_torque=None, roll_torque=None, brake=None) |
drive.get |
call | self.drive.get("throttle") |
gun.aim_now |
property | self.gun.aim_now |
gun.cooldown_ticks |
property | self.gun.cooldown_ticks |
gun.spread |
property | self.gun.spread |
gun.max_power |
property | self.gun.max_power |
gun.damage_scale |
property | self.gun.damage_scale |
gun.can_fire |
call | self.gun.can_fire(power, reserve) |
gun.shot_speed |
call | self.gun.shot_speed(power) |
gun.shot_cost |
call | self.gun.shot_cost(power) |
gun.reload_ticks |
call | self.gun.reload_ticks(power) |
gun.shot_damage |
call | self.gun.shot_damage(power) |
gun.power_for_speed |
call | self.gun.power_for_speed(speed) |
gun.power_for_flight_time |
call | self.gun.power_for_flight_time(range, seconds) |
gun.lead |
call | self.gun.lead(contact, power) |
gun.lead_point |
call | self.gun.lead_point(position, velocity, power) |
gun.aim |
control | self.gun.aim(heading=None, pitch=None) |
gun.fire |
control | self.gun.fire(power=None) |
gun.get |
call | self.gun.get("heading") |
scanner.last |
property | self.scanner.last |
scanner.proximity_range |
property | self.scanner.proximity_range |
scanner.reach |
call | self.scanner.reach(arc) |
scanner.arc_for_reach |
call | self.scanner.arc_for_reach(range) |
scanner.set |
control | self.scanner.set(heading=None, arc=None, pitch=None) |
scanner.get |
call | self.scanner.get("heading") |
sensors.contacts |
property | self.sensors.contacts |
sensors.nearest |
property | self.sensors.nearest |
sensors.cues |
property | self.sensors.cues |
sensors.contact |
call | self.sensors.contact(slot) |
sensors.position_of |
call | self.sensors.position_of(contact) |
tracker.cue |
property | self.tracker.cue |
tracker.nearest_bearing_rate |
property | self.tracker.nearest_bearing_rate |
tracker.velocity |
call | self.tracker.velocity(slot) |
tracker.position |
call | self.tracker.position(slot) |
tracker.last_seen |
call | self.tracker.last_seen(slot) |
tracker.configure |
call | self.tracker.configure(smoothing=0.5, forget_ticks=40, cue_ticks=60) |
nav.zone |
property | self.nav.zone |
nav.zone.margin |
call | self.nav.zone.margin(point) |
nav.zone.contains |
call | self.nav.zone.contains(point, margin=0) |
nav.zone.distance_from |
call | self.nav.zone.distance_from(point) |
nav.storm |
property | self.nav.storm |
nav.storm.margin |
call | self.nav.storm.margin(point) |
nav.storm.contains |
call | self.nav.storm.contains(point, margin=0) |
nav.storm.distance_from |
call | self.nav.storm.distance_from(point) |
nav.hill |
property | self.nav.hill |
nav.hill.margin |
call | self.nav.hill.margin(point) |
nav.hill.contains |
call | self.nav.hill.contains(point, margin=0) |
nav.hill.distance_from |
call | self.nav.hill.distance_from(point) |
nav.pickups |
property | self.nav.pickups |
nav.nearest_pickup |
call | self.nav.nearest_pickup(kind=None) |
nav.field_distance |
call | self.nav.field_distance(a, b) |
score.me |
property | self.score.me |
score.best |
property | self.score.best |
score.armour |
property | self.score.armour |
angles.normalize |
call | cy.angles.normalize(degrees) |
angles.angle_diff |
call | cy.angles.angle_diff(target, current) |
angles.bearing_to |
call | cy.angles.bearing_to(from_, to) |
angles.elevation_to |
call | cy.angles.elevation_to(from_, to) |
angles.direction |
call | cy.angles.direction(heading, pitch) |
angles.distance |
call | cy.angles.distance(a, b) |
angles.clamp |
call | cy.angles.clamp(value, low=-1, high=1) |
status.set |
control | self.status.set(text=None, value=None) |
status.get |
call | self.status.get("text") |
raw.number |
call | self.raw.number(path) |
raw.text |
call | self.raw.text(path) |
raw.has |
call | self.raw.has(path) |
raw.flag |
call | self.raw.flag(path) |
raw.count |
call | self.raw.count(path) |
raw.line |
call | self.raw.line() |
raw.extra |
call | self.raw.extra(json) |
session.next |
call | self.session.next() |
session.send |
call | self.session.send() |
session.forfeit |
call | self.session.forfeit(code, message) |
session.log |
call | self.session.log(line) |