The Haskell binding
Clunkyard provides the core's C functions as Haskell IO actions, native
record types with generated Storable instances and camel case names such
as cySensorsNearest. Functions return a status and copy values through
pointers. check robot status throws CoreError for a negative status;
query robot action copies a required result and optional robot action
returns Nothing for cyNone.
Install with make install SDK=/opt/clunkyard/sdk. Compile with
ghc -O2 -i/opt/clunkyard/sdk/bindings/haskell -odir build -hidir build bot.hs /opt/clunkyard/sdk/lib/libclunkyard.a -lpthread -ldl -lm -o bot.
Create build first. The core links statically; only the executable goes in
the robot artifact.
run onTurn onStart owns the protocol loop and closes the session. Both
callbacks receive the core handle; use const (pure ()) when no start hook
is needed. Exceptions are logged and the turn sends controls already set.
Throw Forfeit code message for an explicit forfeit. A core fault sends the
empty reply and continues. play lines onTurn onStart returns the replies
from a memory session. withText scopes a UTF-8 text pointer and byte count.
A tiny robot
module Main where
import Clunkyard
import Foreign
import Control.Monad
turnBot robot = do
target <- optional robot (cySensorsNearest robot)
heading <- query robot (cyMeHeading robot)
case target of
Nothing -> do
cyDriveThrottle robot 0.75 >>= check robot
cyDriveTurn robot 0.25 >>= check robot
cyScannerHeading robot heading >>= check robot
cyScannerArc robot 40 >>= check robot
lastScan <- query robot (cyScannerLast robot)
withText "SEARCH" (cyStatusText robot) >>= check robot
cyStatusValue robot (scanArc lastScan) >>= check robot
Just t -> do
power <- query robot (cyGunPowerForFlightTime robot (contactRange t) 1)
lead <- with t $ \contact -> optional robot (cyGunLead robot contact power)
let (aimHeading,aimPitch) = maybe (contactBearing t,contactElevation t) (\s -> (solutionHeading s,solutionPitch s)) lead
cyGunAimHeading robot aimHeading >>= check robot
cyGunAimPitch robot aimPitch >>= check robot
canFire <- query robot (cyGunCanFire robot power 10)
when (canFire /= 0) $ do
cyGunFire robot >>= check robot
cyGunPower robot power >>= check robot
delta <- query robot (cyAnglesAngleDiff (contactBearing t) heading)
control <- query robot (cyAnglesClamp delta (-1) 1)
cyDriveThrottle robot 0.5 >>= check robot
cyDriveTurn robot control >>= check robot
cyScannerHeading robot (contactBearing t) >>= check robot
cyScannerArc robot 10 >>= check robot
withText "TRACK" (cyStatusText robot) >>= check robot
cyStatusValue robot (contactRange t) >>= check robot
main = run turnBot (const (pure ()))
make test checks every Haskell declaration against the core's full vectors,
including typed foreign arguments, records, exact floating-point results and
serialized acts.
Names
Every entry of the robot API 2.0.0 in Haskell. names.md has every language side by side.
| Canonical | Form | Haskell |
|---|---|---|
match.mode |
property | cyMatchMode |
match.ruleset |
property | cyMatchRuleset |
match.control |
property | cyMatchControl |
match.robots |
property | cyMatchRobots |
match.is_3d |
property | cyMatchIs3d |
match.tick_rate |
property | cyMatchTickRate |
match.max_ticks |
property | cyMatchMaxTicks |
match.robot_id |
call | cyRobotId |
clock.tick |
property | cyClockTick |
clock.seconds |
property | cyClockSeconds |
clock.remaining_ticks |
property | cyClockRemainingTicks |
arena.size |
property | cyArenaSize |
arena.gravity |
property | cyArenaGravity |
arena.terrain_kind |
property | cyArenaTerrainKind |
arena.ground_height |
call | cyArenaGroundHeight |
me.health |
property | cyMeHealth |
me.position |
property | cyMePosition |
me.velocity |
property | cyMeVelocity |
me.heading |
property | cyMeHeading |
me.pitch |
property | cyMePitch |
me.roll |
property | cyMeRoll |
me.angular_velocity |
property | cyMeAngularVelocity |
me.attitude |
property | cyMeAttitude |
me.grounded |
property | cyMeGrounded |
me.altitude |
property | cyMeAltitude |
me.applied |
property | cyMeApplied |
battery.charge |
property | cyBatteryCharge |
battery.capacity |
property | cyBatteryCapacity |
battery.regen |
property | cyBatteryRegen |
battery.sustainable_drive |
property | cyBatterySustainableDrive |
battery.compute |
property | cyBatteryCompute |
battery.drive_cost |
call | cyBatteryDriveCost |
drive.hover_lift |
property | cyDriveHoverLift |
drive.set |
control | cyDriveThrottle, cyDriveTurn, cyDrivePitchTurn |
drive.forces |
control | cyDriveThrust, cyDriveStrafe, cyDriveLift, cyDriveYawTorque, cyDrivePitchTorque, cyDriveRollTorque, cyDriveBrake |
drive.get |
call | cyDriveGetThrottle, cyDriveGetTurn, cyDriveGetPitchTurn, cyDriveGetThrust, cyDriveGetStrafe, cyDriveGetLift, cyDriveGetYawTorque, cyDriveGetPitchTorque, cyDriveGetRollTorque, cyDriveGetBrake |
gun.aim_now |
property | cyGunAimNow |
gun.cooldown_ticks |
property | cyGunCooldownTicks |
gun.spread |
property | cyGunSpread |
gun.max_power |
property | cyGunMaxPower |
gun.damage_scale |
property | cyGunDamageScale |
gun.can_fire |
call | cyGunCanFire |
gun.shot_speed |
call | cyGunShotSpeed |
gun.shot_cost |
call | cyGunShotCost |
gun.reload_ticks |
call | cyGunReloadTicks |
gun.shot_damage |
call | cyGunShotDamage |
gun.power_for_speed |
call | cyGunPowerForSpeed |
gun.power_for_flight_time |
call | cyGunPowerForFlightTime |
gun.lead |
call | cyGunLead |
gun.lead_point |
call | cyGunLeadPoint |
gun.aim |
control | cyGunAimHeading, cyGunAimPitch |
gun.fire |
control | cyGunFire, cyGunPower |
gun.get |
call | cyGunGetAimHeading, cyGunGetAimPitch, cyGunGetFire, cyGunGetPower |
scanner.last |
property | cyScannerLast |
scanner.proximity_range |
property | cyScannerProximityRange |
scanner.reach |
call | cyScannerReach |
scanner.arc_for_reach |
call | cyScannerArcForReach |
scanner.set |
control | cyScannerHeading, cyScannerArc, cyScannerPitch |
scanner.get |
call | cyScannerGetHeading, cyScannerGetArc, cyScannerGetPitch |
sensors.contacts |
property | cySensorsContacts |
sensors.nearest |
property | cySensorsNearest |
sensors.cues |
property | cySensorsCues |
sensors.contact |
call | cySensorsContact |
sensors.position_of |
call | cySensorsPositionOf |
tracker.cue |
property | cyTrackerCue |
tracker.nearest_bearing_rate |
property | cyTrackerNearestBearingRate |
tracker.velocity |
call | cyTrackerVelocity |
tracker.position |
call | cyTrackerPosition |
tracker.last_seen |
call | cyTrackerLastSeen |
tracker.configure |
call | cyTrackerConfigure |
nav.zone |
property | cyNavZone |
nav.zone.margin |
call | cyNavZoneMargin |
nav.zone.contains |
call | cyNavZoneContains |
nav.zone.distance_from |
call | cyNavZoneDistanceFrom |
nav.storm |
property | cyNavStorm |
nav.storm.margin |
call | cyNavStormMargin |
nav.storm.contains |
call | cyNavStormContains |
nav.storm.distance_from |
call | cyNavStormDistanceFrom |
nav.hill |
property | cyNavHill |
nav.hill.margin |
call | cyNavHillMargin |
nav.hill.contains |
call | cyNavHillContains |
nav.hill.distance_from |
call | cyNavHillDistanceFrom |
nav.pickups |
property | cyNavPickups |
nav.nearest_pickup |
call | cyNavNearestPickup |
nav.field_distance |
call | cyNavFieldDistance |
score.me |
property | cyScoreMe |
score.best |
property | cyScoreBest |
score.armour |
property | cyScoreArmour |
angles.normalize |
call | cyAnglesNormalize |
angles.angle_diff |
call | cyAnglesAngleDiff |
angles.bearing_to |
call | cyAnglesBearingTo |
angles.elevation_to |
call | cyAnglesElevationTo |
angles.direction |
call | cyAnglesDirection |
angles.distance |
call | cyAnglesDistance |
angles.clamp |
call | cyAnglesClamp |
status.set |
control | cyStatusText, cyStatusValue |
status.get |
call | cyStatusGetText, cyStatusGetValue |
raw.number |
call | cyRawNumber |
raw.text |
call | cyRawText |
raw.has |
call | cyRawHas |
raw.flag |
call | cyRawFlag |
raw.count |
call | cyRawCount |
raw.line |
call | cyRawLine |
raw.extra |
call | cyRawExtra |
session.event |
property | cySessionEvent |
session.next |
call | cySessionNext |
session.send |
call | cySessionSend |
session.forfeit |
call | cySessionForfeit |
session.log |
call | cySessionLog |
session.feed |
call | cySessionFeed |
session.reply |
call | cySessionReply |