<!-- Generated from sdk/bindings/clojure/README.md and protocol/v2/api.json by protocol/v2/codegen/docs.js; do not edit. Run `make api`. -->
# Clojure on the Java binding

Clojure calls the arena's generated Java core binding through normal Java
interop. Import the classes from `clunkyard.jar`; there is no copied SDK or
separate protocol, tracking or geometry implementation.

Run with `java --enable-native-access=ALL-UNNAMED -cp
/opt/clunkyard/sdk/bindings/java/clunkyard.jar:/usr/share/java/clojure.jar
clojure.main bot.clj`. The binding loads `libclunkyard.so.2`, or the file
named by `CLUNKYARD_LIB`.

A robot subclasses `clunkyard.Robot`. Subsystems and facts are Java
methods; absent values are Java optionals. Controls take their fields in
order or builders such as `(Drive/throttle 0.5)`; only supplied fields
change in the turn. Throw `clunkyard.Forfeit` to forfeit. Other exceptions
are logged and send the controls already set. `Clunkyard/play` plays lines
in memory for tests.

## A tiny robot

```clojure
(import '[clunkyard Robot Clunkyard Drive Contact Solution])

(defn turn [^Robot bot]
  (let [gun (.gun bot), drive (.drive bot), scanner (.scanner bot), angles (.angles bot), self (.me bot), status (.status bot)
        ^Contact target (.orElse (.nearest (.sensors bot)) nil)]
    (if (nil? target)
      (do (.set drive (.turn (Drive/throttle 0.75) 0.25))
          (.set scanner (.heading self) 40.0)
          (.set status "SEARCH" (.arc (.last scanner))))
      (let [power (.powerForFlightTime gun (.range target) 1.0), ^Solution aim (.orElse (.lead gun target power) nil)]
        (if (nil? aim) (.aim gun (.bearing target) (.elevation target)) (.aim gun (.heading aim) (.pitch aim)))
        (when (.canFire gun power 10.0) (.fire gun power))
        (.set drive (.turn (Drive/throttle 0.5) (.clamp angles (.angleDiff angles (.bearing target) (.heading self)))))
        (.set scanner (.bearing target) 10.0)
        (.set status "TRACK" (.range target))))))

(let [robot (atom nil), bot (proxy [Robot] [] (onTurn [] (turn @robot)))]
  (reset! robot bot)
  (Clunkyard/run bot))
```

`make test SDK=...` loads the Clojure entry point against the shared binding
and runs its full API conformance transcript. The example also participates
in the cross-language act identity check.

## Names

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

| Canonical | Form | Clojure |
| --- | --- | --- |
| `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().is3d() |
| `match.tick_rate` | property | match().tickRate() |
| `match.max_ticks` | property | match().maxTicks() |
| `match.robot_id` | call | match().robotId() |
| `clock.tick` | property | clock().tick() |
| `clock.seconds` | property | clock().seconds() |
| `clock.remaining_ticks` | property | clock().remainingTicks() |
| `arena.size` | property | arena().size() |
| `arena.gravity` | property | arena().gravity() |
| `arena.terrain_kind` | property | arena().terrainKind() |
| `arena.ground_height` | call | arena().groundHeight() |
| `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().angularVelocity() |
| `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().sustainableDrive() |
| `battery.compute` | property | battery().compute() |
| `battery.drive_cost` | call | battery().driveCost() |
| `drive.hover_lift` | property | drive().hoverLift() |
| `drive.set` | control | drive().set() |
| `drive.forces` | control | drive().forces() |
| `drive.get` | call | drive().get() |
| `gun.aim_now` | property | gun().aimNow() |
| `gun.cooldown_ticks` | property | gun().cooldownTicks() |
| `gun.spread` | property | gun().spread() |
| `gun.max_power` | property | gun().maxPower() |
| `gun.damage_scale` | property | gun().damageScale() |
| `gun.can_fire` | call | gun().canFire() |
| `gun.shot_speed` | call | gun().shotSpeed() |
| `gun.shot_cost` | call | gun().shotCost() |
| `gun.reload_ticks` | call | gun().reloadTicks() |
| `gun.shot_damage` | call | gun().shotDamage() |
| `gun.power_for_speed` | call | gun().powerForSpeed() |
| `gun.power_for_flight_time` | call | gun().powerForFlightTime() |
| `gun.lead` | call | gun().lead() |
| `gun.lead_point` | call | gun().leadPoint() |
| `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().proximityRange() |
| `scanner.reach` | call | scanner().reach() |
| `scanner.arc_for_reach` | call | scanner().arcForReach() |
| `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().positionOf() |
| `tracker.cue` | property | tracker().cue() |
| `tracker.nearest_bearing_rate` | property | tracker().nearestBearingRate() |
| `tracker.velocity` | call | tracker().velocity() |
| `tracker.position` | call | tracker().position() |
| `tracker.last_seen` | call | tracker().lastSeen() |
| `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().distanceFrom() |
| `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().distanceFrom() |
| `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().distanceFrom() |
| `nav.pickups` | property | nav().pickups() |
| `nav.nearest_pickup` | call | nav().nearestPickup() |
| `nav.field_distance` | call | nav().fieldDistance() |
| `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().angleDiff() |
| `angles.bearing_to` | call | angles().bearingTo() |
| `angles.elevation_to` | call | angles().elevationTo() |
| `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() |
