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

The generated Erlang API calls one in-process NIF over the robot core.
Facts are functions of the robot handle, records are maps, controls take a
map of fields, and an absent result is `undefined`. Numeric and enum
arguments are explicit. The fold's `on_start/1` returns its memory and
`on_turn/2` returns the next memory. All geometry and tracking live in core.

Install with `make install SDK=/opt/clunkyard/sdk`. Build a robot with
`erlc -pa /opt/clunkyard/sdk/bindings/erlang bot.erl`. Run with
`erl -noshell -pa /opt/clunkyard/sdk/bindings/erlang -pa . -s bot start`.
The NIF is compiled in the builder and loads `libclunkyard.so.2`.

## A tiny robot

```erlang
-module(bot).
-export([start/0,on_turn/2]).
start()->clunkyard:run(?MODULE),halt().
on_turn(R,State)->
  case clunkyard:sensors_nearest(R) of
    undefined->
      clunkyard:drive_set(R,#{throttle=>0.75,turn=>0.25}),
      clunkyard:scanner_set(R,#{heading=>clunkyard:me_heading(R),arc=>40}),
      clunkyard:status_set(R,#{text=><<"SEARCH">>,value=>maps:get(arc,clunkyard:scanner_last(R))});
    Target->
      Power=clunkyard:gun_power_for_flight_time(R,maps:get(range,Target),1),
      Aim=clunkyard:gun_lead(R,Target,Power),
      case Aim of undefined->clunkyard:gun_aim(R,#{heading=>maps:get(bearing,Target),pitch=>maps:get(elevation,Target)});_->clunkyard:gun_aim(R,#{heading=>maps:get(heading,Aim),pitch=>maps:get(pitch,Aim)})end,
      case clunkyard:gun_can_fire(R,Power,10)of true->clunkyard:gun_fire(R,#{power=>Power});false->ok end,
      Turn=clunkyard:angles_clamp(clunkyard:angles_angle_diff(maps:get(bearing,Target),clunkyard:me_heading(R)),-1,1),
      clunkyard:drive_set(R,#{throttle=>0.5,turn=>Turn}),
      clunkyard:scanner_set(R,#{heading=>maps:get(bearing,Target),arc=>10}),
      clunkyard:status_set(R,#{text=><<"TRACK">>,value=>maps:get(range,Target)})
  end,State.
```

`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 Erlang / Elixir.
[names.md](names.md) has every language side by side.

| Canonical | Form | Erlang / Elixir |
| --- | --- | --- |
| `match.mode` | property | clunkyard:match_mode |
| `match.ruleset` | property | clunkyard:match_ruleset |
| `match.control` | property | clunkyard:match_control |
| `match.robots` | property | clunkyard:match_robots |
| `match.is_3d` | property | clunkyard:match_is_3d |
| `match.tick_rate` | property | clunkyard:match_tick_rate |
| `match.max_ticks` | property | clunkyard:match_max_ticks |
| `match.robot_id` | call | clunkyard:match_robot_id |
| `clock.tick` | property | clunkyard:clock_tick |
| `clock.seconds` | property | clunkyard:clock_seconds |
| `clock.remaining_ticks` | property | clunkyard:clock_remaining_ticks |
| `arena.size` | property | clunkyard:arena_size |
| `arena.gravity` | property | clunkyard:arena_gravity |
| `arena.terrain_kind` | property | clunkyard:arena_terrain_kind |
| `arena.ground_height` | call | clunkyard:arena_ground_height |
| `me.health` | property | clunkyard:me_health |
| `me.position` | property | clunkyard:me_position |
| `me.velocity` | property | clunkyard:me_velocity |
| `me.heading` | property | clunkyard:me_heading |
| `me.pitch` | property | clunkyard:me_pitch |
| `me.roll` | property | clunkyard:me_roll |
| `me.angular_velocity` | property | clunkyard:me_angular_velocity |
| `me.attitude` | property | clunkyard:me_attitude |
| `me.grounded` | property | clunkyard:me_grounded |
| `me.altitude` | property | clunkyard:me_altitude |
| `me.applied` | property | clunkyard:me_applied |
| `battery.charge` | property | clunkyard:battery_charge |
| `battery.capacity` | property | clunkyard:battery_capacity |
| `battery.regen` | property | clunkyard:battery_regen |
| `battery.sustainable_drive` | property | clunkyard:battery_sustainable_drive |
| `battery.compute` | property | clunkyard:battery_compute |
| `battery.drive_cost` | call | clunkyard:battery_drive_cost |
| `drive.hover_lift` | property | clunkyard:drive_hover_lift |
| `drive.set` | control | clunkyard:drive_set |
| `drive.forces` | control | clunkyard:drive_forces |
| `drive.get` | call | clunkyard:drive_get |
| `gun.aim_now` | property | clunkyard:gun_aim_now |
| `gun.cooldown_ticks` | property | clunkyard:gun_cooldown_ticks |
| `gun.spread` | property | clunkyard:gun_spread |
| `gun.max_power` | property | clunkyard:gun_max_power |
| `gun.damage_scale` | property | clunkyard:gun_damage_scale |
| `gun.can_fire` | call | clunkyard:gun_can_fire |
| `gun.shot_speed` | call | clunkyard:gun_shot_speed |
| `gun.shot_cost` | call | clunkyard:gun_shot_cost |
| `gun.reload_ticks` | call | clunkyard:gun_reload_ticks |
| `gun.shot_damage` | call | clunkyard:gun_shot_damage |
| `gun.power_for_speed` | call | clunkyard:gun_power_for_speed |
| `gun.power_for_flight_time` | call | clunkyard:gun_power_for_flight_time |
| `gun.lead` | call | clunkyard:gun_lead |
| `gun.lead_point` | call | clunkyard:gun_lead_point |
| `gun.aim` | control | clunkyard:gun_aim |
| `gun.fire` | control | clunkyard:gun_fire |
| `gun.get` | call | clunkyard:gun_get |
| `scanner.last` | property | clunkyard:scanner_last |
| `scanner.proximity_range` | property | clunkyard:scanner_proximity_range |
| `scanner.reach` | call | clunkyard:scanner_reach |
| `scanner.arc_for_reach` | call | clunkyard:scanner_arc_for_reach |
| `scanner.set` | control | clunkyard:scanner_set |
| `scanner.get` | call | clunkyard:scanner_get |
| `sensors.contacts` | property | clunkyard:sensors_contacts |
| `sensors.nearest` | property | clunkyard:sensors_nearest |
| `sensors.cues` | property | clunkyard:sensors_cues |
| `sensors.contact` | call | clunkyard:sensors_contact |
| `sensors.position_of` | call | clunkyard:sensors_position_of |
| `tracker.cue` | property | clunkyard:tracker_cue |
| `tracker.nearest_bearing_rate` | property | clunkyard:tracker_nearest_bearing_rate |
| `tracker.velocity` | call | clunkyard:tracker_velocity |
| `tracker.position` | call | clunkyard:tracker_position |
| `tracker.last_seen` | call | clunkyard:tracker_last_seen |
| `tracker.configure` | call | clunkyard:tracker_configure |
| `nav.zone` | property | clunkyard:nav_zone |
| `nav.zone.margin` | call | clunkyard:nav_zone_margin |
| `nav.zone.contains` | call | clunkyard:nav_zone_contains |
| `nav.zone.distance_from` | call | clunkyard:nav_zone_distance_from |
| `nav.storm` | property | clunkyard:nav_storm |
| `nav.storm.margin` | call | clunkyard:nav_storm_margin |
| `nav.storm.contains` | call | clunkyard:nav_storm_contains |
| `nav.storm.distance_from` | call | clunkyard:nav_storm_distance_from |
| `nav.hill` | property | clunkyard:nav_hill |
| `nav.hill.margin` | call | clunkyard:nav_hill_margin |
| `nav.hill.contains` | call | clunkyard:nav_hill_contains |
| `nav.hill.distance_from` | call | clunkyard:nav_hill_distance_from |
| `nav.pickups` | property | clunkyard:nav_pickups |
| `nav.nearest_pickup` | call | clunkyard:nav_nearest_pickup |
| `nav.field_distance` | call | clunkyard:nav_field_distance |
| `score.me` | property | clunkyard:score_me |
| `score.best` | property | clunkyard:score_best |
| `score.armour` | property | clunkyard:score_armour |
| `angles.normalize` | call | clunkyard:angles_normalize |
| `angles.angle_diff` | call | clunkyard:angles_angle_diff |
| `angles.bearing_to` | call | clunkyard:angles_bearing_to |
| `angles.elevation_to` | call | clunkyard:angles_elevation_to |
| `angles.direction` | call | clunkyard:angles_direction |
| `angles.distance` | call | clunkyard:angles_distance |
| `angles.clamp` | call | clunkyard:angles_clamp |
| `status.set` | control | clunkyard:status_set |
| `status.get` | call | clunkyard:status_get |
| `raw.number` | call | clunkyard:raw_number |
| `raw.text` | call | clunkyard:raw_text |
| `raw.has` | call | clunkyard:raw_has |
| `raw.flag` | call | clunkyard:raw_flag |
| `raw.count` | call | clunkyard:raw_count |
| `raw.line` | call | clunkyard:raw_line |
| `raw.extra` | call | clunkyard:raw_extra |
| `session.event` | property | clunkyard:session_event |
| `session.next` | call | clunkyard:session_next |
| `session.send` | call | clunkyard:session_send |
| `session.forfeit` | call | clunkyard:session_forfeit |
| `session.log` | call | clunkyard:session_log |
| `session.feed` | call | clunkyard:session_feed |
| `session.reply` | call | clunkyard:session_reply |
