Complete API reference

nano-bot — Habitas Games
Every commandOne page

Using an AI assistant? Paste the raw markdown version into the chat rather than this page — it is written to be machine-read.

nano-bot — Strategy API (complete, authoritative)

Writing a strategy for nano-bot? Read this whole file. It is the entire API. If you are an LLM, do not infer anything beyond what is written here — everything you need is below, and anything not here does not exist.

The one thing to get right first

You are not writing a network client. There is:

Instead you write one Python class that subclasses NanoStrategy and implements two methods. The engine imports your file, constructs your class once, and calls your methods — what_to_do_next once per turn for 1500 turns. You issue commands by calling methods on the bot objects the engine hands you. That's the whole model.

Minimal working strategy (copy this, it compiles and scores)

from nanobot.api.nano_strategy import NanoStrategy


class MyStrategy(NanoStrategy):
    def choose_injection_point(self, map_info):
        # Called ONCE. Return the (x, y) cell where your NanoAI spawns.
        # Must be inside your injection zone; (0, 0) is a safe default —
        # the engine relocates it to a valid cell if needed.
        return (0, 0)

    def what_to_do_next(self, map_info, my_bots):
        # Called once per turn. Issue at most one command per bot.
        ai = next((b for b in my_bots if b.type == "NanoAI" and b.is_alive), None)
        collector = next((b for b in my_bots if b.type == "NanoCollector" and b.is_alive), None)
        needle = next((b for b in my_bots if b.type == "NanoNeedle" and b.is_alive), None)
        if ai is None:
            return

        # 1) Build a collector next to the AI.
        if collector is None and map_info.azn_bank >= 20:
            x, y = ai.position
            for nx, ny in ((x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)):
                cell = map_info.get_cell(nx, ny)
                if cell is not None and not cell.is_bone:
                    ai.build("NanoCollector", (nx, ny))
                    break

        # 2) Walk the AI to the NEAREST unclaimed Habitas Point and plant
        #    a needle on it. (Nearest, not habitas_points[0] — the first
        #    in the list can be across the map.)
        elif needle is None:
            unclaimed = [hp for hp in map_info.habitas_points if hp.owner_id == -1]
            if unclaimed:
                point = min(unclaimed, key=lambda hp:
                            abs(hp.position[0] - ai.position[0])
                            + abs(hp.position[1] - ai.position[1])).position
                if abs(ai.position[0] - point[0]) + abs(ai.position[1] - point[1]) == 1:
                    if map_info.azn_bank >= 40:
                        ai.build("NanoNeedle", point)
                else:
                    ai.move_to(point)

        # 3) Collector: harvest AZN, deliver it to the needle to score.
        if collector is not None:
            node = min((n for n in map_info.azn_nodes if n.quantity > 0),
                       key=lambda n: abs(n.position[0] - collector.position[0])
                                   + abs(n.position[1] - collector.position[1]), default=None)
            if needle is not None and collector.azn >= 10:
                if collector.position == needle.position:
                    collector.transfer_to(needle.position)   # standing ON it
                else:
                    collector.move_to(needle.position)
            elif node is not None:
                if collector.position == node.position:
                    collector.collect_from(node.position)     # standing ON it
                else:
                    collector.move_to(node.position)

Rules for the file: exactly one NanoStrategy subclass per file (loading fails if there are zero or more than one). Put it anywhere under strategies/ as a .py file. The class name can be anything.

The two methods you implement

choose_injection_point(self, map_info) -> (x, y)      # once, at match start
what_to_do_next(self, map_info, my_bots) -> None      # once per turn (1500 turns)

BotProxy — your bots (read state, issue commands)

Read-only properties:

propertytypemeaning
bot.idintunique id
bot.typestrone of the 8 type names below
bot.position(x, y) int tuplecurrent cell
bot.hpintcurrent health
bot.max_hpintmax health
bot.aznintAZN currently carried
bot.is_alivebool
bot.is_movingboolmid-move (has a movement cooldown)
bot.has_pathboolhas a cached path to a destination

Command methods (call at most one per bot per turn; all positions are (x, y) int tuples):

methodwhat it does
bot.move_to((x, y))pathfind toward the cell and step along it
bot.collect_from((x, y))harvest AZN — you must be standing on that AZN node
bot.transfer_to((x, y))deposit AZN into a friendly bot with capacity (needle/container/collector) you are standing on, or into your bank if you're standing in any of your injection zones
bot.defend((x, y))attack that cell — NanoCollector only, range 12 (Euclidean), 1–5 damage, blocked by Bone and by any alive NanoWall on the line of sight
bot.build("TypeName", (x, y))NanoAI only — build a bot on a passable cell exactly 1 step away (Manhattan distance 1); costs AZN from your bank, appears the same turn
bot.open_ip()NanoIPCreator only — register a permanent new injection point at its current cell
bot.stop()cancel movement / do nothing this turn
bot.self_destruct()destroy this bot

The golden rule: collect_from and transfer_to only work when the bot is standing on the target cell. There is no acting at a distance — move_to there first, then issue the command each turn until done.

MapInfo — the map snapshot passed to your methods

propertytypemeaning
map_info.size(width, height)grid dimensions (shipped maps are 50×50 and 60×60)
map_info.turnintcurrent turn (1–1500)
map_info.azn_bankintyour build budget (AZN available to build)
map_info.bonus_hold_allintextra points/turn while you hold every Habitas Point (0 = none)
map_info.habitas_pointslist[HabitasPointInfo]all scoring points
map_info.azn_nodeslist[AZNNodeInfo]all AZN resource nodes
map_info.visible_enemieslist[dict]enemy bots within your bots' scan radius — each {"id", "type", "position", "hp"} (fog of war: only what you can see)
map_info.hazardslist[dict]white cells within scan — each {"id", "position", "hp"}
map_info.get_cell(x, y)CellInfo or Noneterrain at a cell (None if out of bounds)

HabitasPointInfo: .position (x,y), .owner_id (int, -1 = unclaimed), .azn_stored (int). AZNNodeInfo: .position (x,y), .quantity (int). CellInfo: .position (x,y), .is_bone (bool — impassable), .density, .stream_direction.

Note visible_enemies / hazards elements are dicts (use enemy["position"]), while habitas_points / azn_nodes elements are objects (use hp.position).

The 8 bot types (stats from data/bot_types.json)

TypeCostHPKey statsRole
NanoAI— (spawns free)20scan 5The only bot that can build(). If it dies you can never build again. Protect it.
NanoExplorer1520scan 30, ignores tissue densityFast scout / eyes under fog. Can't collect, attack, or build.
NanoCollector2050capacity 20, transfer 5/turn, attack: 1–5 dmg, range 12Harvests AZN, delivers it, and is the only bot that can shoot.
NanoContainer2560capacity 60, transfer 5/turnMobile storage for long supply relays. No attack.
NanoNeedle40150capacity 100, stationaryPlant ON a Habitas Point to score. Cannot move.
NanoIPCreator3020scan 30, expires after 500 turnsopen_ip() makes a permanent new injection point.
NanoBlocker2090+6 turn traversal penaltyRoadblock on a chokepoint.
NanoWall25100expires after 50 turnsBlocks enemy movement and all shots through its cell.

Every player starts with one NanoAI and a starting AZN budget (150 by default). Build everything else with NanoAI.build(...).

Scoring

Computed every turn from live state; the winner is decided at turn 1500 (or when only one side has bots left) by the score at that moment.

Common mistakes (all of these are wrong)

That's the entire API. Study strategies/example_strategy_v2.py for a complete, competitive example.


View the markdown source · this page is generated from it.