Commit Graph
36 Commits
Author SHA1 Message Date
KoalaTrapLord 4e8a999ebd feat: add Unity/Godot WebSocket server (Phase 1 stub)
- pom.xml: add Java-WebSocket 1.5.6 dependency
- bridge/GameWsServer.java: WS server on ws://localhost:7654
- bridge/GameSession.java: Phase 1 stub game loop with human-input queue
- cli/LabCli.java: add ws-server subcommand via picocli
2026-03-18 00:02:18 -04:00
Claude 0b623ec39e feat: add lobby UI, build integration, and test suite (Phases 9, 11, 12)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 02:56:16 +00:00
ClaudeandClaude Opus 4.6 d1bed9ac20 feat: scaffold React+TS frontend with types and Tailwind tokens (Phases 1, 2, 10)
Phase 1 — Project Scaffold:
- Vite + React-TS project in frontend/ with Tailwind v3, PostCSS, Autoprefixer
- clsx and react-router-dom installed
- Vite proxy configured for /api and /ws to localhost:8000
- Tailwind directives in src/index.css
- Makefile targets: frontend-dev, frontend-build
- app.py updated to serve frontend/dist/ with SPA catch-all fallback

Phase 2 — Type Definitions:
- TypeScript types in frontend/src/types/game.ts (Phase, Card, Player,
  GameState, WsIncoming, NarrationLine)
- Constants in frontend/src/constants.ts (SEAT_COLOURS, PHASES)

Phase 10 — Tailwind Colour Tokens:
- Custom color tokens for bg, accent, life, seat, card color groups
- Additional tokens from index.html audit: border, phase, btn, text, highlight
- Custom pulse animation keyframe

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 02:35:50 +00:00
KoalaTrapLord 09b0708c4d fix(models): commander_tax int→dict to match engine per-commander tax tracking 2026-03-16 23:58:07 -04:00
KoalaTrapLord 1121e1cb26 feat: add commander_bonus weight to score_card()
Commanders get +5.0 priority in AI spell selection, making the
AI prioritize casting its commander when affordable.
2026-03-17 03:38:14 +00:00
KoalaTrapLord 4bade21220 feat: route commander deaths to command zone instead of graveyard
Added _send_to_graveyard() helper that checks card.is_commander
and routes to command_zone (resetting tapped/turn_played) or
graveyard. Applied to all 4 death paths: removal, board wipe,
blocker death, and attacker death in combat.
2026-03-17 03:36:36 +00:00
KoalaTrapLord 46421fe8c4 feat: add commander casting from command zone with tax tracking
Second pass in _play_spells() checks command_zone for castable
commanders, applies commander_tax, taps lands, places on
battlefield, and increments tax by 2 for subsequent casts.
2026-03-17 03:34:25 +00:00
KoalaTrapLord da5e9bd74f feat: set is_commander during deck loading, place in command_zone
- Add commander_names param to run(), run_n(), _create_state()
- Commander card flagged is_commander=True and placed in
  player.command_zone instead of shuffled into library/hand
- Only first matching card is extracted (handles singleton rule)
- Backward compatible: commander_names defaults to None
2026-03-17 03:31:35 +00:00
KoalaTrapLord 019a710acd feat: add command_zone and commander_tax to Player dataclass
Adds command_zone (list[Card]) and commander_tax (int, +2 per cast)
to the base Player model so the headless engine can track commander
zone and tax natively without requiring CommanderPlayer wrappers.
2026-03-17 03:18:06 +00:00
KoalaTrapLord 9f7fbef7f8 fix: implement all 19 simulator audit bug fixes
Bug fixes across 7 Python files from the deep-dive audit:

engine.py (bugs 1-6):
- Fix summoning sickness (was disabled after turn 0)
- Move untap step before draw (correct MTG ordering)
- Rebuild playable list each iteration (fix mana overspend)
- Menace now allows 2+ blockers instead of preventing all
- Add double strike damage handling (blocked + unblocked)
- (Finish position sort already correct, no change needed)

game_state.py (bugs 7,9,18,19):
- Add .players property returning commander_players
- Add get_legal_moves()/apply_move() stubs
- Initialize commander zone in from_sim_state()
- Sync land_drop_used from engine stats

turn_manager.py (bugs 8,10,11):
- Use sim_state.get_battlefield() + card.tapped attr access
- Replace asyncio.get_event_loop() with get_running_loop()
- Fix APNAP iterations counter (always increment)
- Fix drawn.name and discarded.name (was dict .get())

threat_assessor.py (bugs 12,13,14):
- Use game_state.battlefield(seat) for card iteration
- Use Card dataclass attrs (c.type_line, c.oracle_text, etc)
- Move import re to module top level

models.py (bug 15):
- Word-boundary regex in has_keyword() (fixes reach/ward FPs)

prompt_builder.py (bug 16):
- Remove @staticmethod from module-level _category_label()

rules.py (bug 17):
- Evaluate ramp detection independently of is_removal flag
2026-03-16 20:50:09 +00:00
KoalaTrapLord 2f117eedcb fix: Java 17 compat - inline ternary in this() call instead of local var 2026-03-16 20:34:05 +00:00
KoalaTrapLord 8f8abb79c6 fix: match actual Forge verbose log format - cast/played/Life:/Zone Change: patterns 2026-03-16 20:25:35 +00:00
KoalaTrapLord 78898f6da0 fix: regex patterns match Forge verbose output, single-winner resolution, 300s clock for 4p 2026-03-16 17:34:12 +00:00
KoalaTrapLord 69242a8f6e fix: remove duplicate numPlayers declaration in parseForgeOutput 2026-03-16 17:13:48 +00:00
KoalaTrapLord 2b6ccac3ea fix: hardcoded 3-element arrays in BatchRunner causing empty stats for 4-player games 2026-03-16 17:09:57 +00:00
KoalaTrapLord 94bb369866 feat: add --deck4/--commander4 support for 4-player games in LabCli + BatchRunner 2026-03-16 02:28:06 +00:00
KoalaTrapLord 463b7c1483 Phase 8: Full multiplayer — lobby, private hands, LAN discovery, spectator mode, chat 2026-03-14 23:04:32 -04:00
KoalaTrapLord b6b1616dad Phase 6: AI politics engine (deal-making, threat comms, spite logic) + targeting memory 2026-03-14 20:42:48 -04:00
KoalaTrapLord 92bb9b9445 Phase 5: FastAPI server, WebSocket game channel, Scryfall art proxy, REST API, static web client, tests 2026-03-14 20:36:06 -04:00
KoalaTrapLord 3c3dceb737 Phase 4: Add Pygame prototype GUI (gui/ package + tests/test_phase4.py) 2026-03-14 20:10:43 -04:00
KoalaTrapLord 605ff774ed Phase 3: Add turn_manager.py, threat_assessor.py, tests/test_phase3.py 2026-03-14 19:35:50 -04:00
KoalaTrapLord 441ba7dd74 Phase 2: Add ai_opponent.py, personality_prompts.py, tests/test_phase2.py 2026-03-14 16:53:43 -04:00
KoalaTrapLord d0e2824038 Phase 1: Add game_state.py, prompt_builder.py, state_logger.py 2026-03-14 16:43:16 -04:00
KoalaTrapLord 2c6748a736 feat(brain): swap default model to GPT-OSS 20B via Ollama (localhost:11434) 2026-03-14 14:34:14 -04:00
KoalaTrapLord 585cc1d4a3 feat(engine): load learned_weights.json automatically via load_weights() 2026-03-14 14:30:28 -04:00
KoalaTrapLord f05067bbfe feat(brain): pipe GameResult winner_seat + per-player life totals into flush_log() for RL training 2026-03-14 00:13:50 -04:00
KoalaTrapLord 6cafa36ce4 feat(rules): add load_weights() / save_weights() for simulation-driven weight learning 2026-03-13 23:58:59 -04:00
KoalaTrapLord 841e861bea feat: N-player deepseek engine (Task 2A — Issue #27)
- run_n() accepts 2-4 decks; run() wraps for backward compat
- _select_attack_target() heuristic for multiplayer combat targeting
- N-player elimination order tracking with finish positions
- Removal scans all opponents for scariest creature
- ML snapshot captures all N players
- Log entries use per-seat boards dict with legacy boardA/boardB for 2-player
2026-03-13 16:58:23 -04:00
KoalaTrapLord 0be8841cec feat: N-player engine turn loop (Task 2A — Issue #27)
- engine.py: new run_n() method accepts 2-4 decks; run() wraps for backward compat
- _select_attack_target() heuristic: attack weakest non-eliminated opponent
- N-player elimination order tracking with correct finish positions
- Removal spells scan all opponents for best target
- Game logs use per-seat boards dict with boardA/boardB legacy keys for 2-player
- Tested: 2/3/4-player, elimination order, attack targeting
2026-03-13 16:54:55 -04:00
KoalaTrapLord a1fd290d5f refactor: adopt Python logging module with named loggers
Replace all print() calls with structured logging using the Python
logging module. This provides:

- Named loggers per subsystem: commander_ai_lab.api, .batch, .sim,
  .coach, .deckgen, .collection, .scanner, .ml, .cache, .pplx
- Dual output: console (StreamHandler) + rotating file (RotatingFileHandler)
  at logs/commander-ai-lab.log (25 MB x 5 backups = 125 MB max)
- Configurable via env vars: CAL_LOG_DIR, CAL_LOG_MAX_MB, CAL_LOG_BACKUP_COUNT
- --verbose / -v flag for DEBUG-level output
- overnight-run.py: separate rotating log at logs/overnight-run.log (10 MB x 5)
- Sub-module loggers in ml/, scanner/, deck_sources/, src/ all propagate
  to the root commander_ai_lab logger
- Stripped redundant [TAG] prefixes from messages (logger name carries context)
- Format: '2026-03-13 14:00:00 INFO  [commander_ai_lab.batch] message'

Files changed: lab_api.py, overnight-run.py, and 11 sub-module .py files
176 total print() calls converted (101 in lab_api.py, 76 in sub-modules)
2026-03-13 18:09:52 +00:00
KoalaTrapLord 3d8e81f88e Phase 2: score_card() num_opponents scaling + enrich_card() determinism fix (#32)
- score_card() now accepts num_opponents: int parameter (default 1)
- Keywords/effects scale with pod size via _MULTI_OPP_SCALING dict
- Multiplayer-specific oracle patterns: 'each opponent', pillowfort, 'each player'
- Board wipe and counter spell bonuses scale with opponent count
- Expanded keyword coverage (double strike, first strike, hexproof, indestructible,
  menace, vigilance, ward, infect, annihilator, cascade, defender)
- Triggered ability bonuses: ETB, attack triggers, dies triggers
- enrich_card() replaced random.randint() with hashlib.md5 name-based hash
  for deterministic CMC estimation across games (#32)
- Backward compatible: existing score_card(card, weights) calls unaffected
2026-03-12 20:22:44 +00:00
KoalaTrapLord 648e1b8d38 Fix simulator button stuck on Running — to_dict() backward compat
GameResult.to_dict() now returns both legacy keys (winner, playerA, playerB)
that the UI expects AND new N-player keys (winningSeat, playerResults) for
the Java BatchResult schema.
2026-03-12 18:25:22 +00:00
KoalaTrapLord de4f119d40 Phase 1: N-player data model refactoring
- New PlayerResult dataclass with seat_index, name, life, eliminated, finish_position, stats
- Refactored GameResult to use players: list[PlayerResult] + winner_seat (no hardcoded 2-player fields)
- Backward-compat @property accessors (player_a_stats, player_b_stats, winner, etc.) for existing consumers
- SimState.battlefields is now per-player (list-of-lists) with helper methods:
  get_battlefield(), add_to_battlefield(), remove_from_battlefield(), all_battlefield_cards()
- Updated engine.py, deepseek_engine.py, deepseek_brain.py to use per-player battlefields
- GameResult.to_dict() matches Java BatchResult schema (playerResults array)
- lab_api.py and experiments.py unchanged — backward-compat properties handle all existing access patterns
2026-03-12 18:10:57 +00:00
KoalaTrapLord a0adfc37e8 v24: Resolve GitHub Issues #1-#5
Issue #1 — Winner's life total now captured:
  - Parse verbose Forge log for life-total-change events
  - Track last-known life per seat via 3 regex patterns
  - Winner's final life set from log data (not left at default 40)
  - Losers who died to mill/poison retain their actual life total

Issue #2 — Win condition classification formalized:
  - New WinCondition enum (schema/WinCondition.java) with 8 categories
  - Centralized Forge loss-reason-string → enum mapping (regex-based)
  - UNKNOWN fallback with logging for unrecognized loss reasons
  - All classification now goes through WinCondition.classify()

Issue #3 — JVM startup overhead reduced:
  - Added -XX:+UseSerialGC (lighter GC for batch processes)
  - Added -XX:TieredStopAtLevel=1 (faster JIT, less compilation)
  - ForgeWorker stub class for future persistent batch mode
  - Estimated reduction: ~2-3s → ~1-1.5s per game startup

Issue #4 — Single-threaded throughput optimization:
  - New CLI flags: --ai-simplified, --ai-think-time, --benchmark
  - JVM flags passed through to Forge subprocess
  - Benchmark mode: run 1 game before batch, report wall/Forge/overhead times
  - API support: aiSimplified, aiThinkTimeMs in StartRequest

Issue #5 — Threading, progress, and backpressure:
  - --threads 0 or -1 auto-detects optimal count from CPU topology
  - detectOptimalThreads() estimates physical cores (excludes HT)
  - ProgressCallback interface for real-time sims/sec reporting
  - Per-game progress emitted as [PROGRESS] lines, parsed by lab_api.py
  - --max-queue flag for graceful backpressure (limits concurrent JVMs)
  - Final throughput summary printed at batch completion
  - StatusResponse now includes simsPerSec field

Also: .gitignore restored, lab_api.py updated with all new API fields
2026-03-12 01:26:36 +00:00
KoalaTrapLord a5fe8cb3fa v23: React + TypeScript SPA migration
Complete frontend rewrite from vanilla HTML/CSS/JS to React 19 + TypeScript + Tailwind CSS v4.

Frontend (frontend/commander-ai-lab-ui/):
- Vite + React 19 + TypeScript + Tailwind CSS v4 + React Router
- 7 pages: BatchSim, Collection, Decks, AutoGen, Simulator, Coach, Training
- Reusable components: Spinner, StatusBadge, CardImage, ManaSymbols, EmptyState
- Full typed API client layer (8 modules matching all backend endpoints)
- Recharts for mana curves, win rate charts, progress bars
- Lucide icons throughout
- Custom dark theme with MTG mana color tokens
- Code splitting (recharts + react in separate chunks)

Backend (lab_api.py):
- SPA-aware static file serving with catch-all for client-side routing
- Fallback to legacy ui/ folder if React dist not built
- Updated startup log with SPA route list

Build system:
- .gitignore added (was missing - removes pyc, db, node_modules, etc.)
- build-full-installer-v2.py: v23 with Node.js check + React build step
- Vite build config with manual chunks for optimal loading

Also includes: V3 deck generator fixes, coach improvements, DeepSeek sim modules
2026-03-12 01:12:02 +00:00
KoalaTrapLord e6b5e0cedb Initial commit 2026-03-10 12:13:56 -04:00