No description
  • Python 69.5%
  • C 18.6%
  • HTML 11.4%
  • Shell 0.5%
Find a file
2026-03-30 22:08:13 +00:00
dev fix: remove stale monop-player COPY from Dockerfile.cardinal 2026-02-28 03:24:21 +00:00
docs Add docs/BUGS_AND_FIXES.md — regression reference for all fixed bugs 2026-02-21 19:15:16 +00:00
plugins Fix: log @monop commands to irc.log before handling 2026-03-28 08:39:17 +00:00
reference Re-add test data and reference files after reboot 2026-02-21 02:37:37 +00:00
screenshots Add integration screenshots and screenshot tooling 2026-02-21 20:01:57 +00:00
scripts Auto-replay on startup, @monop commands, weechat-to-irc-log converter 2026-03-28 08:37:45 +00:00
site Right-align house/hotel/mortgage indicators in player cards 2026-03-30 22:08:13 +00:00
test_data chore: remove unused autopilot log files 2026-02-27 20:48:13 +00:00
.gitignore Remove game-state.json from tracking, add to .gitignore 2026-02-28 06:44:53 +00:00
monop_bridge.py Fix setup registration: names appear as each player joins 2026-02-21 11:54:53 +00:00
monop_players.py Fix setup registration: names appear as each player joins 2026-02-21 11:54:53 +00:00
README.md docs: update README with full feature list, config reference, resync docs 2026-03-01 19:47:16 +00:00
run_game.py Fix setup visibility: bridge waits for players, observer sees registration 2026-02-21 11:33:28 +00:00
screenshot_integration.py Add integration screenshots and screenshot tooling 2026-02-21 20:01:57 +00:00
screenshot_states.py Add integration screenshots and screenshot tooling 2026-02-21 20:01:57 +00:00
test_house_parser.py refactor: single canonical location for parser files 2026-03-03 03:37:04 +00:00
test_integration_bugs.py refactor: single canonical location for parser files 2026-03-03 03:37:04 +00:00
test_midgame_edge_cases.py refactor: single canonical location for parser files 2026-03-03 03:37:04 +00:00
test_midgame_join.py refactor: single canonical location for parser files 2026-03-03 03:37:04 +00:00
test_midgame_resync.py refactor: single canonical location for parser files 2026-03-03 03:37:04 +00:00
test_parser.py refactor: single canonical location for parser files 2026-03-03 03:37:04 +00:00
test_parser_bugs.py Fix restore_from_state() re-adding bankrupt players as active 2026-03-09 06:46:58 +00:00
test_parser_commands.py refactor: single canonical location for parser files 2026-03-03 03:37:04 +00:00
test_parser_resign.py refactor: single canonical location for parser files 2026-03-03 03:37:04 +00:00
test_players.py Fix trade race condition: move trade/roll decision to -- Command: handler 2026-02-21 10:55:33 +00:00
test_plugin_features.py Add test coverage for IRC log replay, rotation, and rebuild script 2026-03-28 08:40:52 +00:00

monop-state

Live Monopoly board viewer for IRC games using monop-irc.

Watches an IRC channel where monop-irc is running, parses the game output in real time, and serves a web board that auto-refreshes every 2 seconds.

Architecture

monop-irc binary
      │  (stdout → IRC via bridge)
      ▼
monop_bridge.py  ──────────────────────  IRC channel (#monop)
                                              │
                                    Cardinal IRC bot
                                    (monop plugin)
                                              │
                              ┌───────────────┼───────────────┐
                              │               │               │
                       game-state.json  heartbeat.json   api/v1/
                              │               │          (MiSTy-compatible)
                              └───────┬───────┘
                                      │
                               site/index.html
                            (auto-refreshes @ 2s)

Components:

Path Description
plugins/monop/ Cardinal plugin — watches IRC, parses monop output, writes state files
monop_parser.py Core parser — state machine that tracks the full game from IRC log lines
monop_bridge.py Bridge — connects the monop binary's stdin/stdout to an IRC channel
site/index.html Web board viewer — reads game-state.json and renders the board
scripts/weechat_to_state.py CLI tool — parse a WeeChat log file and emit game-state.json
reference/ Source for the monop-irc binary (BSD monop with IRC support)
dev/ Docker Compose dev environment (see below)

Features

Board viewer:

  • Authentic Monopoly board colors with property color bars
  • Player tokens with jdenticon avatars and initial badges
  • Jail corner with dedicated token placement
  • Rent tooltips with gold-highlighted current rent tier
  • Houses/hotels rendered inside color bars
  • Dice roll flash animation on new rolls
  • Monopoly crown (♛) indicator for complete color groups
  • Net worth progress bar per player
  • GOJF card badges
  • Mobile-responsive layout (3→2→1 column breakpoints)
  • Debug panel (long-press status dot or Ctrl+Shift+D)

Parser:

  • Tracks all game actions: rolls, purchases, auctions, trades, rent, taxes, cards, jail, resign/bankruptcy
  • Mid-game join support via .where, .print, and .holdings parsing
  • State restoration on restart — survives Cardinal reconnects without losing ownership
  • Heartbeat every 60s (independent of game activity)
  • MiSTy-compatible static API file output (api/v1/board, api/v1/players, etc.)

Parser

monop_parser.py is a pure-Python state machine that processes IRC log lines and reconstructs the full game state: player positions, cash, properties, houses/hotels, mortgages, jail status, GOJF cards, and turn order.

python3 -m pytest -v   # 219 tests

Reconnect / Mid-game resync

The parser can bootstrap game state from mid-game by parsing:

  • .where — player names, numbers, locations, current player
  • .print — full board ownership, mortgages, houses/hotels
  • .holdings / .own — per-player cash, properties, GOJF cards

On Cardinal restart, the plugin restores the parser from the last saved game-state.json so ownership data isn't lost.

WeeChat log replay

Convert a WeeChat #monop log file into a game state:

python3 scripts/weechat_to_state.py path/to/monop.log --out game-state.json --pretty

Plugin Config

In Cardinal's plugin config (e.g. monop-config.json):

{
    "channel": "#monop",
    "state_file": "site/game-state.json",
    "irc_port": 6697,
    "irc_ssl": true
}
Key Default Description
channel (required) IRC channel to watch
bot_nick "monop" Nick of the monop bot
state_file "game-state.json" Path for game state output
irc_port 6697 IRC port (for display in UI)
irc_ssl true Whether TLS is used (for display in UI)
api_dir "api/v1/" Directory for MiSTy-compatible API files

The server hostname is read from cardinal.network automatically.

Dev Environment

Spin up a full local stack with Docker Compose:

docker compose -f dev/docker-compose.yml up --build

This starts:

  • Ergo IRCd on localhost:6667 (no auth, no TLS)
  • monop bridge — starts a game in #monop when the first player joins
  • Cardinal — observer bot that writes game-state.json
  • Web server — board viewer at http://localhost:8080

Connect any IRC client to localhost:6667, join #monop, and play. The board updates live in the browser.

See dev/README.md for more detail.

Running the site standalone

cd site/
python3 -m http.server 8080
# open http://localhost:8080

The viewer shows a demo board when no game-state.json is present. Use the debug panel (long-press the status dot) to switch between demo states.