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

The generated OCaml API uses typed records and subsystem modules over
compiled C stubs. Facts are functions of the robot handle, optional results
are options, and controls take optional labelled arguments. Later controls
merge with earlier ones in the same tick. Enum values are strings; an enum
argument takes `Some name`, or `None` for the API's default.

Install with `make install SDK=/opt/clunkyard/sdk`. Build with
`ocamlopt -I /opt/clunkyard/sdk/bindings/ocaml -o bot
/opt/clunkyard/sdk/bindings/ocaml/clunkyard.cmxa bot.ml`, then run `./bot`.
The precompiled stubs link into the robot; the core remains the image's
`libclunkyard.so.2`. No compiler is needed in the runtime image.

## A tiny robot

```ocaml
open Clunkyard
let on_turn r =
  match Sensors.nearest r with
  | None ->
    Drive.set r ~throttle:0.75 ~turn:0.25 ();
    Scanner.set r ~heading:(Me.heading r) ~arc:40. ();
    Status.set r ~text:"SEARCH" ~value:(Scanner.last r).arc ()
  | Some target ->
    let power=Gun.power_for_flight_time r target.range 1. in
    (match Gun.lead r target power with
    | None -> Gun.aim r ~heading:target.bearing ~pitch:target.elevation ()
    | Some aim -> Gun.aim r ~heading:aim.heading ~pitch:aim.pitch ());
    if Gun.can_fire r power 10. then Gun.fire r ~power ();
    Drive.set r ~throttle:0.5 ~turn:(Angles.clamp (Angles.angle_diff target.bearing (Me.heading r)) (-1.) 1.) ();
    Scanner.set r ~heading:target.bearing ~arc:10. ();
    Status.set r ~text:"TRACK" ~value:target.range ()
let () = run ~on_turn ()
```

`make test SDK=...` checks the actual generated API against every core
vector, including exact floating-point results and act lines. Core errors
raise a language error carrying their status. A core fault during input
sends its empty act and continues with the next state. User exceptions are
logged and send the controls already set. Use the binding’s forfeit helper
to give up a match; `play` runs protocol lines in memory for tests.

## Names

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

| Canonical | Form | OCaml |
| --- | --- | --- |
| `match.mode` | property | Match.mode robot |
| `match.ruleset` | property | Match.ruleset robot |
| `match.control` | property | Match.control robot |
| `match.robots` | property | Match.robots robot |
| `match.is_3d` | property | Match.is_3d robot |
| `match.tick_rate` | property | Match.tick_rate robot |
| `match.max_ticks` | property | Match.max_ticks robot |
| `match.robot_id` | call | Match.robot_id robot |
| `clock.tick` | property | Clock.tick robot |
| `clock.seconds` | property | Clock.seconds robot |
| `clock.remaining_ticks` | property | Clock.remaining_ticks robot |
| `arena.size` | property | Arena.size robot |
| `arena.gravity` | property | Arena.gravity robot |
| `arena.terrain_kind` | property | Arena.terrain_kind robot |
| `arena.ground_height` | call | Arena.ground_height robot |
| `me.health` | property | Me.health robot |
| `me.position` | property | Me.position robot |
| `me.velocity` | property | Me.velocity robot |
| `me.heading` | property | Me.heading robot |
| `me.pitch` | property | Me.pitch robot |
| `me.roll` | property | Me.roll robot |
| `me.angular_velocity` | property | Me.angular_velocity robot |
| `me.attitude` | property | Me.attitude robot |
| `me.grounded` | property | Me.grounded robot |
| `me.altitude` | property | Me.altitude robot |
| `me.applied` | property | Me.applied robot |
| `battery.charge` | property | Battery.charge robot |
| `battery.capacity` | property | Battery.capacity robot |
| `battery.regen` | property | Battery.regen robot |
| `battery.sustainable_drive` | property | Battery.sustainable_drive robot |
| `battery.compute` | property | Battery.compute robot |
| `battery.drive_cost` | call | Battery.drive_cost robot |
| `drive.hover_lift` | property | Drive.hover_lift robot |
| `drive.set` | control | Drive.set robot |
| `drive.forces` | control | Drive.forces robot |
| `drive.get` | call | Drive.get robot |
| `gun.aim_now` | property | Gun.aim_now robot |
| `gun.cooldown_ticks` | property | Gun.cooldown_ticks robot |
| `gun.spread` | property | Gun.spread robot |
| `gun.max_power` | property | Gun.max_power robot |
| `gun.damage_scale` | property | Gun.damage_scale robot |
| `gun.can_fire` | call | Gun.can_fire robot |
| `gun.shot_speed` | call | Gun.shot_speed robot |
| `gun.shot_cost` | call | Gun.shot_cost robot |
| `gun.reload_ticks` | call | Gun.reload_ticks robot |
| `gun.shot_damage` | call | Gun.shot_damage robot |
| `gun.power_for_speed` | call | Gun.power_for_speed robot |
| `gun.power_for_flight_time` | call | Gun.power_for_flight_time robot |
| `gun.lead` | call | Gun.lead robot |
| `gun.lead_point` | call | Gun.lead_point robot |
| `gun.aim` | control | Gun.aim robot |
| `gun.fire` | control | Gun.fire robot |
| `gun.get` | call | Gun.get robot |
| `scanner.last` | property | Scanner.last robot |
| `scanner.proximity_range` | property | Scanner.proximity_range robot |
| `scanner.reach` | call | Scanner.reach robot |
| `scanner.arc_for_reach` | call | Scanner.arc_for_reach robot |
| `scanner.set` | control | Scanner.set robot |
| `scanner.get` | call | Scanner.get robot |
| `sensors.contacts` | property | Sensors.contacts robot |
| `sensors.nearest` | property | Sensors.nearest robot |
| `sensors.cues` | property | Sensors.cues robot |
| `sensors.contact` | call | Sensors.contact robot |
| `sensors.position_of` | call | Sensors.position_of robot |
| `tracker.cue` | property | Tracker.cue robot |
| `tracker.nearest_bearing_rate` | property | Tracker.nearest_bearing_rate robot |
| `tracker.velocity` | call | Tracker.velocity robot |
| `tracker.position` | call | Tracker.position robot |
| `tracker.last_seen` | call | Tracker.last_seen robot |
| `tracker.configure` | call | Tracker.configure robot |
| `nav.zone` | property | Nav.zone robot |
| `nav.zone.margin` | call | Nav.zone_margin robot |
| `nav.zone.contains` | call | Nav.zone_contains robot |
| `nav.zone.distance_from` | call | Nav.zone_distance_from robot |
| `nav.storm` | property | Nav.storm robot |
| `nav.storm.margin` | call | Nav.storm_margin robot |
| `nav.storm.contains` | call | Nav.storm_contains robot |
| `nav.storm.distance_from` | call | Nav.storm_distance_from robot |
| `nav.hill` | property | Nav.hill robot |
| `nav.hill.margin` | call | Nav.hill_margin robot |
| `nav.hill.contains` | call | Nav.hill_contains robot |
| `nav.hill.distance_from` | call | Nav.hill_distance_from robot |
| `nav.pickups` | property | Nav.pickups robot |
| `nav.nearest_pickup` | call | Nav.nearest_pickup robot |
| `nav.field_distance` | call | Nav.field_distance robot |
| `score.me` | property | Score.me robot |
| `score.best` | property | Score.best robot |
| `score.armour` | property | Score.armour robot |
| `angles.normalize` | call | Angles.normalize robot |
| `angles.angle_diff` | call | Angles.angle_diff robot |
| `angles.bearing_to` | call | Angles.bearing_to robot |
| `angles.elevation_to` | call | Angles.elevation_to robot |
| `angles.direction` | call | Angles.direction robot |
| `angles.distance` | call | Angles.distance robot |
| `angles.clamp` | call | Angles.clamp robot |
| `status.set` | control | Status.set robot |
| `status.get` | call | Status.get robot |
| `raw.number` | call | Raw.number robot |
| `raw.text` | call | Raw.text robot |
| `raw.has` | call | Raw.has robot |
| `raw.flag` | call | Raw.flag robot |
| `raw.count` | call | Raw.count robot |
| `raw.line` | call | Raw.line robot |
| `raw.extra` | call | Raw.extra robot |
| `session.event` | property | Session.event robot |
| `session.next` | call | Session.next robot |
| `session.send` | call | Session.send robot |
| `session.forfeit` | call | Session.forfeit robot |
| `session.log` | call | Session.log robot |
| `session.feed` | call | Session.feed robot |
| `session.reply` | call | Session.reply robot |
