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

CLIPS rules run in process through clipspy, on the installed Python binding.
The robot core owns parsing, tracking, helpers and acts. Match templates and
field tables are generated from `protocol/v2/schema.json`; every canonical
query and control is a `cy-*` foreign function generated from
`protocol/v2/api.json`. Install with `make install SDK=/opt/clunkyard/sdk`
after installing Python. Run with
`PYTHONPATH=/opt/clunkyard/sdk/bindings/clips:/opt/clunkyard/sdk/bindings/python python3 bot.py`.

`(cy-me-heading)` reads a property; `(cy-gun-shot-speed 2.0)` calls a query.
A record is a multifield in its declared field order, nested records inline.
A list starts with its count, followed by its records. An absent result is
`nil`; booleans are `TRUE` and `FALSE`. A control takes its canonical field
name and value: `(cy-drive-set "throttle" 0.5)`. Bare fire uses
`(cy-gun-fire)`; getters take the field name. The generated reference gives
record layouts and every callable name.

Compatibility facts include `game`, `me`, `state`, `contact`, `cue`, `zone`,
`storm`, `pickup`, `hill` and the match's mechanics. The adapter resets the
environment for each state, restores hello facts, asserts state facts and
runs your rules. Globals persist between turns. Output facts `drive`,
`forces`, `aim`, `scan`, `fire`, `status`, `extra` and `forfeit` remain available;
later facts override earlier fields. The familiar geometry functions forward
to the core. `shot-damage` includes the core's current damage scale and uses
the current tick. Direct `cy-*` calls preserve canonical core semantics.

## A tiny robot

Save these rules as `tiny.clp`:

```clips
(defrule tiny
  (state)
  =>
  (bind ?target (cy-sensors-nearest))
  (if (eq ?target nil)
    then
      (cy-drive-set "throttle" 0.75)
      (cy-drive-set "turn" 0.25)
      (cy-scanner-set "heading" (cy-me-heading))
      (cy-scanner-set "arc" 40)
      (cy-status-set "text" "SEARCH")
      (cy-status-set "value" (nth$ 3 (cy-scanner-last)))
    else
      (bind ?range (nth$ 3 ?target))
      (bind ?bearing (nth$ 4 ?target))
      (bind ?elevation (nth$ 5 ?target))
      (bind ?power (cy-gun-power-for-flight-time ?range 1))
      (bind ?aim (cy-gun-lead (expand$ ?target) ?power))
      (cy-gun-aim "heading" (if (eq ?aim nil) then ?bearing else (nth$ 1 ?aim)))
      (cy-gun-aim "pitch" (if (eq ?aim nil) then ?elevation else (nth$ 2 ?aim)))
      (if (eq (cy-gun-can-fire ?power 10) TRUE) then (cy-gun-fire "power" ?power))
      (cy-drive-set "throttle" 0.5)
      (cy-drive-set "turn" (cy-angles-clamp (cy-angles-angle-diff ?bearing (cy-me-heading)) -1 1))
      (cy-scanner-set "heading" ?bearing)
      (cy-scanner-set "arc" 10)
      (cy-status-set "text" "TRACK")
      (cy-status-set "value" ?range)))
```

Save the launcher as `bot.py`:

```python
import clunkyard_clips
clunkyard_clips.run("tiny.clp")
```

`run` and `play` use Python's core session. Foreign call errors are reported
after rules run; user errors preserve controls set so far. Raise a forfeit
fact to give up a match. `make test` exercises the actual CLIPS function
surface against every API vector. Non-finite inputs cannot be represented
by CLIPS. [Complete names](clips.md).

## Names

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

| Canonical | Form | CLIPS |
| --- | --- | --- |
| `match.mode` | property | (cy-match-mode ...) |
| `match.ruleset` | property | (cy-match-ruleset ...) |
| `match.control` | property | (cy-match-control ...) |
| `match.robots` | property | (cy-match-robots ...) |
| `match.is_3d` | property | (cy-match-is-3d ...) |
| `match.tick_rate` | property | (cy-match-tick-rate ...) |
| `match.max_ticks` | property | (cy-match-max-ticks ...) |
| `match.robot_id` | call | (cy-match-robot-id ...) |
| `clock.tick` | property | (cy-clock-tick ...) |
| `clock.seconds` | property | (cy-clock-seconds ...) |
| `clock.remaining_ticks` | property | (cy-clock-remaining-ticks ...) |
| `arena.size` | property | (cy-arena-size ...) |
| `arena.gravity` | property | (cy-arena-gravity ...) |
| `arena.terrain_kind` | property | (cy-arena-terrain-kind ...) |
| `arena.ground_height` | call | (cy-arena-ground-height ...) |
| `me.health` | property | (cy-me-health ...) |
| `me.position` | property | (cy-me-position ...) |
| `me.velocity` | property | (cy-me-velocity ...) |
| `me.heading` | property | (cy-me-heading ...) |
| `me.pitch` | property | (cy-me-pitch ...) |
| `me.roll` | property | (cy-me-roll ...) |
| `me.angular_velocity` | property | (cy-me-angular-velocity ...) |
| `me.attitude` | property | (cy-me-attitude ...) |
| `me.grounded` | property | (cy-me-grounded ...) |
| `me.altitude` | property | (cy-me-altitude ...) |
| `me.applied` | property | (cy-me-applied ...) |
| `battery.charge` | property | (cy-battery-charge ...) |
| `battery.capacity` | property | (cy-battery-capacity ...) |
| `battery.regen` | property | (cy-battery-regen ...) |
| `battery.sustainable_drive` | property | (cy-battery-sustainable-drive ...) |
| `battery.compute` | property | (cy-battery-compute ...) |
| `battery.drive_cost` | call | (cy-battery-drive-cost ...) |
| `drive.hover_lift` | property | (cy-drive-hover-lift ...) |
| `drive.set` | control | (cy-drive-set ...) |
| `drive.forces` | control | (cy-drive-forces ...) |
| `drive.get` | call | (cy-drive-get ...) |
| `gun.aim_now` | property | (cy-gun-aim-now ...) |
| `gun.cooldown_ticks` | property | (cy-gun-cooldown-ticks ...) |
| `gun.spread` | property | (cy-gun-spread ...) |
| `gun.max_power` | property | (cy-gun-max-power ...) |
| `gun.damage_scale` | property | (cy-gun-damage-scale ...) |
| `gun.can_fire` | call | (cy-gun-can-fire ...) |
| `gun.shot_speed` | call | (cy-gun-shot-speed ...) |
| `gun.shot_cost` | call | (cy-gun-shot-cost ...) |
| `gun.reload_ticks` | call | (cy-gun-reload-ticks ...) |
| `gun.shot_damage` | call | (cy-gun-shot-damage ...) |
| `gun.power_for_speed` | call | (cy-gun-power-for-speed ...) |
| `gun.power_for_flight_time` | call | (cy-gun-power-for-flight-time ...) |
| `gun.lead` | call | (cy-gun-lead ...) |
| `gun.lead_point` | call | (cy-gun-lead-point ...) |
| `gun.aim` | control | (cy-gun-aim ...) |
| `gun.fire` | control | (cy-gun-fire ...) |
| `gun.get` | call | (cy-gun-get ...) |
| `scanner.last` | property | (cy-scanner-last ...) |
| `scanner.proximity_range` | property | (cy-scanner-proximity-range ...) |
| `scanner.reach` | call | (cy-scanner-reach ...) |
| `scanner.arc_for_reach` | call | (cy-scanner-arc-for-reach ...) |
| `scanner.set` | control | (cy-scanner-set ...) |
| `scanner.get` | call | (cy-scanner-get ...) |
| `sensors.contacts` | property | (cy-sensors-contacts ...) |
| `sensors.nearest` | property | (cy-sensors-nearest ...) |
| `sensors.cues` | property | (cy-sensors-cues ...) |
| `sensors.contact` | call | (cy-sensors-contact ...) |
| `sensors.position_of` | call | (cy-sensors-position-of ...) |
| `tracker.cue` | property | (cy-tracker-cue ...) |
| `tracker.nearest_bearing_rate` | property | (cy-tracker-nearest-bearing-rate ...) |
| `tracker.velocity` | call | (cy-tracker-velocity ...) |
| `tracker.position` | call | (cy-tracker-position ...) |
| `tracker.last_seen` | call | (cy-tracker-last-seen ...) |
| `tracker.configure` | call | (cy-tracker-configure ...) |
| `nav.zone` | property | (cy-nav-zone ...) |
| `nav.zone.margin` | call | (cy-nav-zone-margin ...) |
| `nav.zone.contains` | call | (cy-nav-zone-contains ...) |
| `nav.zone.distance_from` | call | (cy-nav-zone-distance-from ...) |
| `nav.storm` | property | (cy-nav-storm ...) |
| `nav.storm.margin` | call | (cy-nav-storm-margin ...) |
| `nav.storm.contains` | call | (cy-nav-storm-contains ...) |
| `nav.storm.distance_from` | call | (cy-nav-storm-distance-from ...) |
| `nav.hill` | property | (cy-nav-hill ...) |
| `nav.hill.margin` | call | (cy-nav-hill-margin ...) |
| `nav.hill.contains` | call | (cy-nav-hill-contains ...) |
| `nav.hill.distance_from` | call | (cy-nav-hill-distance-from ...) |
| `nav.pickups` | property | (cy-nav-pickups ...) |
| `nav.nearest_pickup` | call | (cy-nav-nearest-pickup ...) |
| `nav.field_distance` | call | (cy-nav-field-distance ...) |
| `score.me` | property | (cy-score-me ...) |
| `score.best` | property | (cy-score-best ...) |
| `score.armour` | property | (cy-score-armour ...) |
| `angles.normalize` | call | (cy-angles-normalize ...) |
| `angles.angle_diff` | call | (cy-angles-angle-diff ...) |
| `angles.bearing_to` | call | (cy-angles-bearing-to ...) |
| `angles.elevation_to` | call | (cy-angles-elevation-to ...) |
| `angles.direction` | call | (cy-angles-direction ...) |
| `angles.distance` | call | (cy-angles-distance ...) |
| `angles.clamp` | call | (cy-angles-clamp ...) |
| `status.set` | control | (cy-status-set ...) |
| `status.get` | call | (cy-status-get ...) |
| `raw.number` | call | (cy-raw-number ...) |
| `raw.text` | call | (cy-raw-text ...) |
| `raw.has` | call | (cy-raw-has ...) |
| `raw.flag` | call | (cy-raw-flag ...) |
| `raw.count` | call | (cy-raw-count ...) |
| `raw.line` | call | (cy-raw-line ...) |
| `raw.extra` | call | (cy-raw-extra ...) |
| `session.event` | property | (cy-session-event ...) |
| `session.next` | call | (cy-session-next ...) |
| `session.send` | call | (cy-session-send ...) |
| `session.forfeit` | call | (cy-session-forfeit ...) |
| `session.log` | call | (cy-session-log ...) |
| `session.feed` | call | (cy-session-feed ...) |
| `session.reply` | call | (cy-session-reply ...) |
