<!-- Generated from sdk/bindings/julia/README.md and protocol/v2/api.json by protocol/v2/codegen/docs.js; do not edit. Run `make api`. -->
# The Julia binding

The Clunkyard robot API in Julia, directly over the core's C ABI through
`ccall`. The API, native records and declarations are generated from
`protocol/v2/api.json`. Only loading, the run loop and exception mapping
are written by hand. Physics, tracking, parsing and serialization run in
the core.

Install with `make install SDK=/opt/clunkyard/sdk`. Run with
`JULIA_LOAD_PATH=/opt/clunkyard/sdk/bindings/julia:@stdlib julia bot.jl`.
The hosted runtime's system image precompiles this package. Library symbols
are resolved at process initialization, so it loads `libclunkyard.so.2`, or
the file named by `CLUNKYARD_LIB`, even from a system image.

A `Robot` takes `on_start` and `on_turn` callbacks. Subsystems and facts are
properties; calls use snake_case. Optional results are `nothing`, records
have named fields and enums use symbols matching their protocol names.
Controls take keyword fields and merge in the turn. `drive.get("throttle")`
reads a pending field. Throw `ClunkyardSDK.Forfeit(code, message)` to
forfeit; other exceptions are logged and send the controls already set.
`ClunkyardSDK.play(robot, lines)` plays lines in memory for tests.

## A tiny robot

```julia
using ClunkyardSDK
const cy=ClunkyardSDK
function turn(bot)
    target=bot.sensors.nearest
    if target===nothing
        bot.drive.set(throttle=0.75,turn=0.25)
        bot.scanner.set(heading=bot.me.heading,arc=40)
        bot.status.set(text="SEARCH",value=bot.scanner.last.arc)
        return
    end
    power=bot.gun.power_for_flight_time(target.range,1)
    aim=bot.gun.lead(target,power)
    heading,pitch=aim===nothing ? (target.bearing,target.elevation) : (aim.heading,aim.pitch)
    bot.gun.aim(heading=heading,pitch=pitch)
    bot.gun.can_fire(power,10) && bot.gun.fire(power=power)
    bot.drive.set(throttle=0.5,turn=bot.angles.clamp(bot.angles.angle_diff(target.bearing,bot.me.heading)))
    bot.scanner.set(heading=target.bearing,arc=10)
    bot.status.set(text="TRACK",value=target.range)
end
cy.run(cy.Robot(on_turn=turn))
```

`make test SDK=...` compares every API vector with the core's transcript,
including exact floating-point bits and act lines. The README example
also participates in the cross-language identity check.

## Names

Every entry of the robot API 2.0.0 in Julia.
[names.md](names.md) has every language side by side.

| Canonical | Form | Julia |
| --- | --- | --- |
| `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 |
