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

The generated C++ API wraps the core's C ABI with subsystem objects,
value records, `std::optional` results and exceptions for negative statuses.
There is no protocol parser, tracker or physics implementation in the binding.
Controls take optional fields and merge with earlier controls in the turn.
Typed getters such as `drive.get_throttle()` read a pending field back.

Install with `make install SDK=/opt/clunkyard/sdk`. Build with
`c++ -std=c++20 -O2 -I/opt/clunkyard/sdk/include
-I/opt/clunkyard/sdk/bindings/cpp bot.cpp
/opt/clunkyard/sdk/lib/libclunkyard.a -lpthread -ldl -lm -o bot`.
The core is linked statically. The artifact carries the robot executable.

## A tiny robot

```cpp
#include "clunkyard.hpp"

class Tiny : public clunkyard::Robot {
  void on_turn() override {
    const auto target=sensors.nearest();
    if(!target) {
      drive.set(0.75,0.25);
      scanner.set(me.heading(),40);
      status.set("SEARCH",scanner.last().arc);
      return;
    }
    const auto power=gun.power_for_flight_time(target->range,1);
    const auto aim=gun.lead(*target,power);
    gun.aim(aim?aim->heading:target->bearing,aim?aim->pitch:target->elevation);
    if(gun.can_fire(power,10))gun.fire(power);
    drive.set(0.5,angles.clamp(angles.angle_diff(target->bearing,me.heading())));
    scanner.set(target->bearing,10);
    status.set("TRACK",target->range);
  }
};

int main() { Tiny robot; robot.run(); }
```

Override `on_start()` and `on_turn()`, then call `run()`. An exception logs
its message and sends the controls already set. Throw
`clunkyard::Forfeit(code, message)` to forfeit. `play(lines)` opens a memory
session, runs the same callbacks and returns the core's replies for tests.

`make test` checks the idiomatic generated wrapper against the complete
core conformance transcript, including exact floating-point bits, optional
records, controls and serialized acts.

## Names

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

| Canonical | Form | C++ |
| --- | --- | --- |
| `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_<field>() |
| `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_<field>() |
| `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_<field>() |
| `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_<field>() |
| `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() |
