The MiniZinc adapter

The installed adapter solves your model once at hello, then Python plays its plan through the canonical robot core. clunkyard.mzn declares typed hello parameters generated from protocol/v2/schema.json. Its core_* tables are computed through core queries; the model contains no copied game formula. Install with make install SDK=/opt/clunkyard/sdk in this directory, after the Python binding. Run with PYTHONPATH=/opt/clunkyard/sdk/bindings/minizinc:/opt/clunkyard/sdk/bindings/python python3 bot.py.

Subclass Planner, set model, and implement on_turn. self.plan reads the solver's JSON output. Override model_data for extra parameters; self.core_query("gun.shot_speed", power) calls any canonical core API while preparing them. This hook returns the Python binding's typed records and optional None values. Controls, helpers, tracker and live turn data use the Python API. MiniZinc runs only at hello; it never starts a solver per turn. run and play accept a Planner; exceptions and forfeits use the Python binding's behaviour.

core_steer and core_home index -180..180. core_power and core_cue_arc index 0..core_range_steps with core_range_step pixels between entries. core_sustainable_drive and core_hover_lift are core values. Plan.at rounds a requested index and bounds it to the table. Solver JSON represents floating point numbers at solver precision.

A tiny robot

Save this model as tiny.mzn:

include "clunkyard.mzn";
output ["{}"];

Save this launcher as bot.py:

import clunkyard as cy
import clunkyard_minizinc as mz


class Tiny(mz.Planner):
    model = "tiny.mzn"

    def on_turn(self):
        target = self.sensors.nearest
        if target is None:
            self.drive.set(throttle=0.75, turn=0.25)
            self.scanner.set(heading=self.me.heading, arc=40)
            self.status.set("SEARCH", self.scanner.last.arc)
            return
        power = self.gun.power_for_flight_time(target.range, 1)
        aim = self.gun.lead(target, power)
        if aim is None:
            self.gun.aim(target.bearing, target.elevation)
        else:
            self.gun.aim(aim.heading, aim.pitch)
        if self.gun.can_fire(power, 10):
            self.gun.fire(power)
        self.drive.set(throttle=0.5, turn=cy.angles.clamp(cy.angles.angle_diff(target.bearing, self.me.heading)))
        self.scanner.set(heading=target.bearing, arc=10)
        self.status.set("TRACK", target.range)


mz.run(Tiny())

make test checks the complete query hook against the API vectors and runs six real solver plans, comparing their tables with core query results. The complete API reference is MiniZinc names.

Names

Every entry of the robot API 2.0.0 in MiniZinc. names.md has every language side by side.

Canonical Form MiniZinc
match.mode property Planner.core_query("match.mode", ...)
match.ruleset property Planner.core_query("match.ruleset", ...)
match.control property Planner.core_query("match.control", ...)
match.robots property Planner.core_query("match.robots", ...)
match.is_3d property Planner.core_query("match.is_3d", ...)
match.tick_rate property Planner.core_query("match.tick_rate", ...)
match.max_ticks property Planner.core_query("match.max_ticks", ...)
match.robot_id call Planner.core_query("match.robot_id", ...)
clock.tick property Planner.core_query("clock.tick", ...)
clock.seconds property Planner.core_query("clock.seconds", ...)
clock.remaining_ticks property Planner.core_query("clock.remaining_ticks", ...)
arena.size property Planner.core_query("arena.size", ...)
arena.gravity property Planner.core_query("arena.gravity", ...)
arena.terrain_kind property Planner.core_query("arena.terrain_kind", ...)
arena.ground_height call Planner.core_query("arena.ground_height", ...)
me.health property Planner.core_query("me.health", ...)
me.position property Planner.core_query("me.position", ...)
me.velocity property Planner.core_query("me.velocity", ...)
me.heading property Planner.core_query("me.heading", ...)
me.pitch property Planner.core_query("me.pitch", ...)
me.roll property Planner.core_query("me.roll", ...)
me.angular_velocity property Planner.core_query("me.angular_velocity", ...)
me.attitude property Planner.core_query("me.attitude", ...)
me.grounded property Planner.core_query("me.grounded", ...)
me.altitude property Planner.core_query("me.altitude", ...)
me.applied property Planner.core_query("me.applied", ...)
battery.charge property Planner.core_query("battery.charge", ...)
battery.capacity property Planner.core_query("battery.capacity", ...)
battery.regen property Planner.core_query("battery.regen", ...)
battery.sustainable_drive property Planner.core_query("battery.sustainable_drive", ...)
battery.compute property Planner.core_query("battery.compute", ...)
battery.drive_cost call Planner.core_query("battery.drive_cost", ...)
drive.hover_lift property Planner.core_query("drive.hover_lift", ...)
drive.set control Planner.core_query("drive.set", ...)
drive.forces control Planner.core_query("drive.forces", ...)
drive.get call Planner.core_query("drive.get", ...)
gun.aim_now property Planner.core_query("gun.aim_now", ...)
gun.cooldown_ticks property Planner.core_query("gun.cooldown_ticks", ...)
gun.spread property Planner.core_query("gun.spread", ...)
gun.max_power property Planner.core_query("gun.max_power", ...)
gun.damage_scale property Planner.core_query("gun.damage_scale", ...)
gun.can_fire call Planner.core_query("gun.can_fire", ...)
gun.shot_speed call Planner.core_query("gun.shot_speed", ...)
gun.shot_cost call Planner.core_query("gun.shot_cost", ...)
gun.reload_ticks call Planner.core_query("gun.reload_ticks", ...)
gun.shot_damage call Planner.core_query("gun.shot_damage", ...)
gun.power_for_speed call Planner.core_query("gun.power_for_speed", ...)
gun.power_for_flight_time call Planner.core_query("gun.power_for_flight_time", ...)
gun.lead call Planner.core_query("gun.lead", ...)
gun.lead_point call Planner.core_query("gun.lead_point", ...)
gun.aim control Planner.core_query("gun.aim", ...)
gun.fire control Planner.core_query("gun.fire", ...)
gun.get call Planner.core_query("gun.get", ...)
scanner.last property Planner.core_query("scanner.last", ...)
scanner.proximity_range property Planner.core_query("scanner.proximity_range", ...)
scanner.reach call Planner.core_query("scanner.reach", ...)
scanner.arc_for_reach call Planner.core_query("scanner.arc_for_reach", ...)
scanner.set control Planner.core_query("scanner.set", ...)
scanner.get call Planner.core_query("scanner.get", ...)
sensors.contacts property Planner.core_query("sensors.contacts", ...)
sensors.nearest property Planner.core_query("sensors.nearest", ...)
sensors.cues property Planner.core_query("sensors.cues", ...)
sensors.contact call Planner.core_query("sensors.contact", ...)
sensors.position_of call Planner.core_query("sensors.position_of", ...)
tracker.cue property Planner.core_query("tracker.cue", ...)
tracker.nearest_bearing_rate property Planner.core_query("tracker.nearest_bearing_rate", ...)
tracker.velocity call Planner.core_query("tracker.velocity", ...)
tracker.position call Planner.core_query("tracker.position", ...)
tracker.last_seen call Planner.core_query("tracker.last_seen", ...)
tracker.configure call Planner.core_query("tracker.configure", ...)
nav.zone property Planner.core_query("nav.zone", ...)
nav.zone.margin call Planner.core_query("nav.zone.margin", ...)
nav.zone.contains call Planner.core_query("nav.zone.contains", ...)
nav.zone.distance_from call Planner.core_query("nav.zone.distance_from", ...)
nav.storm property Planner.core_query("nav.storm", ...)
nav.storm.margin call Planner.core_query("nav.storm.margin", ...)
nav.storm.contains call Planner.core_query("nav.storm.contains", ...)
nav.storm.distance_from call Planner.core_query("nav.storm.distance_from", ...)
nav.hill property Planner.core_query("nav.hill", ...)
nav.hill.margin call Planner.core_query("nav.hill.margin", ...)
nav.hill.contains call Planner.core_query("nav.hill.contains", ...)
nav.hill.distance_from call Planner.core_query("nav.hill.distance_from", ...)
nav.pickups property Planner.core_query("nav.pickups", ...)
nav.nearest_pickup call Planner.core_query("nav.nearest_pickup", ...)
nav.field_distance call Planner.core_query("nav.field_distance", ...)
score.me property Planner.core_query("score.me", ...)
score.best property Planner.core_query("score.best", ...)
score.armour property Planner.core_query("score.armour", ...)
angles.normalize call Planner.core_query("angles.normalize", ...)
angles.angle_diff call Planner.core_query("angles.angle_diff", ...)
angles.bearing_to call Planner.core_query("angles.bearing_to", ...)
angles.elevation_to call Planner.core_query("angles.elevation_to", ...)
angles.direction call Planner.core_query("angles.direction", ...)
angles.distance call Planner.core_query("angles.distance", ...)
angles.clamp call Planner.core_query("angles.clamp", ...)
status.set control Planner.core_query("status.set", ...)
status.get call Planner.core_query("status.get", ...)
raw.number call Planner.core_query("raw.number", ...)
raw.text call Planner.core_query("raw.text", ...)
raw.has call Planner.core_query("raw.has", ...)
raw.flag call Planner.core_query("raw.flag", ...)
raw.count call Planner.core_query("raw.count", ...)
raw.line call Planner.core_query("raw.line", ...)
raw.extra call Planner.core_query("raw.extra", ...)
session.event property Planner.core_query("session.event", ...)
session.next call Planner.core_query("session.next", ...)
session.send call Planner.core_query("session.send", ...)
session.forfeit call Planner.core_query("session.forfeit", ...)
session.log call Planner.core_query("session.log", ...)
session.feed call Planner.core_query("session.feed", ...)
session.reply call Planner.core_query("session.reply", ...)

Download this page as Markdown