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

The generated Go binding calls the core through cgo. Subsystems are fields
of `*Robot`; methods return a value and an error. Optional results are
pointers and use `nil` for absent. Records have public fields with the core's
C layout. Controls take generated structs of optional fields: `Num` and
`Text` create pointers for literal values. Later controls merge in the core.

Install with `make install SDK=/opt/clunkyard/sdk`. A bare starter imports
`clunkyard` and builds with `GO111MODULE=off
GOPATH=/opt/clunkyard/sdk/bindings/go go build -trimpath -o bot bot.go`.
The installed cgo package links the static core. A project using Go modules
can replace its `clunkyard` dependency with the installed package directory.
Only the resulting executable goes in the artifact.

Implement `Turn(*Robot) error`, and optionally `Start(*Robot) error`, then
call `Run(strategy)`. A returned error or recovered panic is logged and the
turn sends its controls already set. Return `&Forfeit{Code, Message}` to
forfeit. `Play(strategy, lines)` plays protocol lines in memory for tests.

## A tiny robot

```go
package main
import cy "clunkyard"
type Tiny struct{}
func value[T any](../../sdk/bindings/go/out T,err error)T{if err!=nil{panic(err)};return out}
func check(err error){if err!=nil{panic(err)}}
func(Tiny)Turn(r *cy.Robot)error{
    target:=value(r.Sensors.Nearest())
    if target==nil{
        check(r.Drive.Set(cy.DriveSet{Throttle:cy.Num(0.75),Turn:cy.Num(0.25)}))
        check(r.Scanner.Set(cy.ScannerSet{Heading:cy.Num(value(r.Me.Heading())),Arc:cy.Num(40)}))
        check(r.Status.Set(cy.StatusSet{Text:cy.Text("SEARCH"),Value:cy.Num(value(r.Scanner.Last()).Arc)}))
        return nil
    }
    power:=value(r.Gun.PowerForFlightTime(target.Range,1));aim:=value(r.Gun.Lead(*target,power))
    heading,pitch:=target.Bearing,target.Elevation;if aim!=nil{heading,pitch=aim.Heading,aim.Pitch}
    check(r.Gun.Aim(cy.GunAim{Heading:cy.Num(heading),Pitch:cy.Num(pitch)}))
    if value(r.Gun.CanFire(power,10)){check(r.Gun.Fire(cy.GunFire{Power:cy.Num(power)}))}
    check(r.Drive.Set(cy.DriveSet{Throttle:cy.Num(0.5),Turn:cy.Num(value(r.Angles.Clamp(value(r.Angles.AngleDiff(target.Bearing,value(r.Me.Heading()))),-1,1)))}))
    check(r.Scanner.Set(cy.ScannerSet{Heading:cy.Num(target.Bearing),Arc:cy.Num(10)}))
    check(r.Status.Set(cy.StatusSet{Text:cy.Text("TRACK"),Value:cy.Num(target.Range)}))
    return nil
}
func main(){if err:=cy.Run(Tiny{});err!=nil{panic(err)}}
```

`make test` exercises the generated Go methods and record marshalling
against the complete core conformance transcript, including exact numeric
bits and serialized acts.

## Names

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

| Canonical | Form | Go |
| --- | --- | --- |
| `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<Field>() |
| `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<Field>() |
| `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<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.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.ZoneMargin() |
| `nav.zone.contains` | call | Nav.ZoneContains() |
| `nav.zone.distance_from` | call | Nav.ZoneDistanceFrom() |
| `nav.storm` | property | Nav.Storm() |
| `nav.storm.margin` | call | Nav.StormMargin() |
| `nav.storm.contains` | call | Nav.StormContains() |
| `nav.storm.distance_from` | call | Nav.StormDistanceFrom() |
| `nav.hill` | property | Nav.Hill() |
| `nav.hill.margin` | call | Nav.HillMargin() |
| `nav.hill.contains` | call | Nav.HillContains() |
| `nav.hill.distance_from` | call | Nav.HillDistanceFrom() |
| `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<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() |
