Docs / Bot Guide
Bot Writing Guide
Structure
Your bot must define a class named Player in a file called main.py:
from megagem import Controller
class Player:
def __init__(self, players: int, player: int):
"""Called once at game start."""
self.players = players # total players in game
self.player = player # your 0-based index
def main(self, ct: Controller) -> tuple[int, int]:
"""Called each turn. Return (bid, reveal_index)."""
# Bid up to 5 coins on gem auctions
bid = 0
if ct.is_gem_auction():
bid = min(5, ct.get_balance())
# Reveal first card in hand
reveal = 0
return bid, reveal
Bots can span multiple files. Upload a .zip containing main.py plus any helpers, model weights, or data files:
my_bot/
├── main.py ← entry point, defines Player
├── strategy.py ← helper module
└── weights/
└── model.npy ← pre-trained weights
Sibling modules are importable directly: import strategy works as expected.
Available Packages
The following packages are available in the sandbox in addition to the Python standard library:
- •
megagem— the game engine and Controller API - •
numpy - •
pandas - •
scipy - •
tensorflow(CPU only) andkeras
Key Controller Methods
ct.get_balance()→ your current coinsct.is_gem_auction()→ True if gems are on offerct.gems_on_offer()→ list of gems you'd winct.win_effect(bid)→ (delta_balance, delta_adj, gems) if you won at this bidct.missions_if_i_win()→ missions you'd claim by winningct.mission_bonus_if_i_win()→ bonus coins from claiming missionsct.beats_on_tie(other)→ True if you'd win a tie against playerother
Limits
- • Upload size: configurable by admin (default 256 KB for
.py, increase for zips with weights) - • Per-turn time limit: configurable by admin (default 500ms)
- • Per-game total budget: configurable by admin (default 10s)
- • Memory limit enforced at the container level
- • Exceeding limits → your turn defaults to
(0, 0), game continues - • No network access; no filesystem writes outside your process
Debugging your bot
Use print() freely — your bot's stdout is captured and displayed in the match log as stdout, separate from actual exceptions.
def main(self, ct):
print(f"my balance: {ct.get_balance()}, gems: {ct.gems_on_offer()}")
bid = min(5, ct.get_balance())
return bid, 0
Where to find logs after a match:
- Go to Matches and open your match.
- In the Games table, expand bot stdout on any game row to see your
print()output. - If your bot raised an uncaught exception, a separate bot errors section appears in red.
- Click Logs ↓ to download the full log file (both stdout and errors) as JSON.
- In the Replay viewer, stdout and error panels appear above the scrubber if logs exist.
Tips:
- • Print output is per-game, not per-turn — add a turn counter if you need turn-level tracing.
- • Output is capped at 64 KB per bot per game; excess is silently dropped.
- • Uncaught exceptions cause your bot to return
(0, 0)for that turn; the game continues. - • Time-limit violations (TLE) are flagged as errors, not stdout.
Uploading
Via web: Go to My Bots, enter your bot name, select a .py file or a .zip containing your bot directory, click Upload.
Via CLI:
pip install megagem --extra-index-url https://megagem.hrvt.dev/simple/
megagem auth --server https://megagem.hrvt.dev
# Upload a single file
megagem push main.py --name my-bot --activate
# Upload a whole directory (zipped automatically)
megagem push my_bot/ --name my-bot --activate
# Upload a pre-made zip
megagem push my_bot.zip --name my-bot --activate