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

The generated SWI-Prolog predicates call a compiled foreign module over
the robot core. Facts return through the final argument, records are dicts,
and controls take a list of `field=value` pairs. Absent results are the
atom `null`, distinct from the valid enum name `none`. Numeric arguments
accept arithmetic expressions. A robot is a fold: optional `on_start/2`
sets memory and `on_turn/3` returns its next value.

Install with `make install SDK=/opt/clunkyard/sdk`. Run with
`swipl -q -p library=/opt/clunkyard/sdk/bindings/prolog
-p library=/opt/clunkyard/sdk/bindings/chr -s bot.pl -g main -t halt`.
The foreign module loads `libclunkyard.so.2`; no compiler runs in the robot.

## A tiny robot

```prolog
:- use_module(library(clunkyard_chr)).
main :- run(user).
on_turn(R,State,State) :-
  sensors_nearest(R,Target),
  (Target==null->
    drive_set(R,[throttle=0.75,turn=0.25]),
    me_heading(R,Heading),scanner_set(R,[heading=Heading,arc=40]),
    scanner_last(R,Scan),status_set(R,[text="SEARCH",value=Scan.arc]);
    gun_power_for_flight_time(R,Target.range,1,Power),gun_lead(R,Target,Power,Aim),
    (Aim==null->gun_aim(R,[heading=Target.bearing,pitch=Target.elevation]);gun_aim(R,[heading=Aim.heading,pitch=Aim.pitch])),
    (gun_can_fire(R,Power,10,true)->gun_fire(R,[power=Power]);true),
    me_heading(R,Heading),angles_angle_diff(Target.bearing,Heading,Off),angles_clamp(Off,-1,1,Turn),
    drive_set(R,[throttle=0.5,turn=Turn]),scanner_set(R,[heading=Target.bearing,arc=10]),status_set(R,[text="TRACK",value=Target.range])).
```

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

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