The Zig binding
Clunkyard's Zig API calls the shared core through direct typed extern
functions. C layouts, declarations, subsystem methods and conformance
bridges are generated from protocol/v2/api.json. The run loop and error
mapping are written by hand. Tracking, geometry, parsing and serialization
stay in the core.
Install with make install SDK=/opt/clunkyard/sdk. Build a robot with:
zig build-exe -O ReleaseSafe -mcpu=baseline --dep clunkyard -Mroot=bot.zig \
-Mclunkyard=/opt/clunkyard/sdk/bindings/zig/clunkyard.zig \
/opt/clunkyard/sdk/lib/libclunkyard.a -lc -lunwind -lm -ldl -lpthread \
-femit-bin=bot
Subsystem methods return error unions. Core errors set robot.core.last_status
and return error.Core; cy.c.cy_last_error retrieves the core's message.
Optional results use null, records are copied values, and enums are i32
constants so unknown values can reach the core for validation. Text and list
results are allocated with robot.core.allocator and belong to the caller;
free each with that allocator. Controls take an options struct and merge
within the turn. Getters such as drive.get_throttle() read pending fields.
robot.forfeit(code,message) sends a forfeit and returns error.Forfeit.
Other callback errors are logged before sending the controls already set.
cy.play(Strategy,lines,allocator) returns owned reply lines.
A tiny robot
const cy=@import("clunkyard");
const Bot=struct {
pub fn onStart(_: *@This(),_: *cy.Robot) !void {}
pub fn onTurn(_: *@This(),robot:*cy.Robot) !void {
const target=(try robot.sensors.nearest()) orelse {
try robot.drive.set(.{.throttle=0.75,.turn=0.25});
try robot.scanner.set(.{.heading=try robot.me.heading(),.arc=40});
try robot.status.set(.{.text="SEARCH",.value=(try robot.scanner.last()).arc});
return;
};
const power=try robot.gun.power_for_flight_time(target.range,1);
const aim=try robot.gun.lead(target,power);
try robot.gun.aim(.{.heading=if(aim) |a| a.heading else target.bearing,.pitch=if(aim) |a| a.pitch else target.elevation});
if(try robot.gun.can_fire(power,10))try robot.gun.fire(.{.power=power});
try robot.drive.set(.{.throttle=0.5,.turn=try robot.angles.clamp(try robot.angles.angle_diff(target.bearing,try robot.me.heading()),-1,1)});
try robot.scanner.set(.{.heading=target.bearing,.arc=10});
try robot.status.set(.{.text="TRACK",.value=target.range});
}
};
pub fn main() !void {try cy.run(Bot);}
make test SDK=... compares every API vector with the core transcript,
including exact floating-point bits and act lines.
Names
Every entry of the robot API 2.0.0 in Zig. names.md has every language side by side.
| Canonical | Form | Zig |
|---|---|---|
match.mode |
property | match.mode() |
match.ruleset |
property | match.ruleset() |
match.control |
property | match.control() |
match.robots |
property | match.robots() |
match.is_3d |
property | match.is_3d() |
match.tick_rate |
property | match.tick_rate() |
match.max_ticks |
property | match.max_ticks() |
match.robot_id |
call | match.robot_id() |
clock.tick |
property | clock.tick() |
clock.seconds |
property | clock.seconds() |
clock.remaining_ticks |
property | clock.remaining_ticks() |
arena.size |
property | arena.size() |
arena.gravity |
property | arena.gravity() |
arena.terrain_kind |
property | arena.terrain_kind() |
arena.ground_height |
call | arena.ground_height() |
me.health |
property | me.health() |
me.position |
property | me.position() |
me.velocity |
property | me.velocity() |
me.heading |
property | me.heading() |
me.pitch |
property | me.pitch() |
me.roll |
property | me.roll() |
me.angular_velocity |
property | me.angular_velocity() |
me.attitude |
property | me.attitude() |
me.grounded |
property | me.grounded() |
me.altitude |
property | me.altitude() |
me.applied |
property | me.applied() |
battery.charge |
property | battery.charge() |
battery.capacity |
property | battery.capacity() |
battery.regen |
property | battery.regen() |
battery.sustainable_drive |
property | battery.sustainable_drive() |
battery.compute |
property | battery.compute() |
battery.drive_cost |
call | battery.drive_cost() |
drive.hover_lift |
property | drive.hover_lift() |
drive.set |
control | drive.set() |
drive.forces |
control | drive.forces() |
drive.get |
call | drive.get() |
gun.aim_now |
property | gun.aim_now() |
gun.cooldown_ticks |
property | gun.cooldown_ticks() |
gun.spread |
property | gun.spread() |
gun.max_power |
property | gun.max_power() |
gun.damage_scale |
property | gun.damage_scale() |
gun.can_fire |
call | gun.can_fire() |
gun.shot_speed |
call | gun.shot_speed() |
gun.shot_cost |
call | gun.shot_cost() |
gun.reload_ticks |
call | gun.reload_ticks() |
gun.shot_damage |
call | gun.shot_damage() |
gun.power_for_speed |
call | gun.power_for_speed() |
gun.power_for_flight_time |
call | gun.power_for_flight_time() |
gun.lead |
call | gun.lead() |
gun.lead_point |
call | gun.lead_point() |
gun.aim |
control | gun.aim() |
gun.fire |
control | gun.fire() |
gun.get |
call | gun.get() |
scanner.last |
property | scanner.last() |
scanner.proximity_range |
property | scanner.proximity_range() |
scanner.reach |
call | scanner.reach() |
scanner.arc_for_reach |
call | scanner.arc_for_reach() |
scanner.set |
control | scanner.set() |
scanner.get |
call | scanner.get() |
sensors.contacts |
property | sensors.contacts() |
sensors.nearest |
property | sensors.nearest() |
sensors.cues |
property | sensors.cues() |
sensors.contact |
call | sensors.contact() |
sensors.position_of |
call | sensors.position_of() |
tracker.cue |
property | tracker.cue() |
tracker.nearest_bearing_rate |
property | tracker.nearest_bearing_rate() |
tracker.velocity |
call | tracker.velocity() |
tracker.position |
call | tracker.position() |
tracker.last_seen |
call | tracker.last_seen() |
tracker.configure |
call | tracker.configure() |
nav.zone |
property | nav.zone() |
nav.zone.margin |
call | nav.zone_margin() |
nav.zone.contains |
call | nav.zone_contains() |
nav.zone.distance_from |
call | nav.zone_distance_from() |
nav.storm |
property | nav.storm() |
nav.storm.margin |
call | nav.storm_margin() |
nav.storm.contains |
call | nav.storm_contains() |
nav.storm.distance_from |
call | nav.storm_distance_from() |
nav.hill |
property | nav.hill() |
nav.hill.margin |
call | nav.hill_margin() |
nav.hill.contains |
call | nav.hill_contains() |
nav.hill.distance_from |
call | nav.hill_distance_from() |
nav.pickups |
property | nav.pickups() |
nav.nearest_pickup |
call | nav.nearest_pickup() |
nav.field_distance |
call | nav.field_distance() |
score.me |
property | score.me() |
score.best |
property | score.best() |
score.armour |
property | score.armour() |
angles.normalize |
call | angles.normalize() |
angles.angle_diff |
call | angles.angle_diff() |
angles.bearing_to |
call | angles.bearing_to() |
angles.elevation_to |
call | angles.elevation_to() |
angles.direction |
call | angles.direction() |
angles.distance |
call | angles.distance() |
angles.clamp |
call | angles.clamp() |
status.set |
control | status.set() |
status.get |
call | status.get() |
raw.number |
call | raw.number() |
raw.text |
call | raw.text() |
raw.has |
call | raw.has() |
raw.flag |
call | raw.flag() |
raw.count |
call | raw.count() |
raw.line |
call | raw.line() |
raw.extra |
call | raw.extra() |
session.event |
property | session.event() |
session.next |
call | session.next() |
session.send |
call | session.send() |
session.forfeit |
call | session.forfeit() |
session.log |
call | session.log() |
session.feed |
call | session.feed() |
session.reply |
call | session.reply() |