From a336bf06634f95a5f787069e002e477d7af6342e Mon Sep 17 00:00:00 2001 From: Jarvis Date: Fri, 20 Feb 2026 21:06:36 +0000 Subject: [PATCH] Add project README, fix holdings parser, update bot config for #monop-dev --- README.md | 40 ++ bot/__pycache__/board_data.cpython-310.pyc | Bin 0 -> 3932 bytes bot/__pycache__/parser.cpython-310.pyc | Bin 0 -> 8059 bytes bot/config.json | 2 +- bot/monopbot.py | 5 +- bot/parser.py | 4 +- game-state.json | 678 +++++++++++++++++++++ 7 files changed, 725 insertions(+), 4 deletions(-) create mode 100644 README.md create mode 100644 bot/__pycache__/board_data.cpython-310.pyc create mode 100644 bot/__pycache__/parser.cpython-310.pyc create mode 100644 game-state.json diff --git a/README.md b/README.md new file mode 100644 index 0000000..0962622 --- /dev/null +++ b/README.md @@ -0,0 +1,40 @@ +# monop-board + +A Monopoly board viewer for IRC games played with [monop-irc](https://github.com/thlc/monop-irc). + +## Components + +### IRC Bot (`bot/`) +Python bot that joins an IRC channel, watches for monop-irc game output, parses it, and writes the game state to `game-state.json`. + +### Board Viewer (`site/`) +Single-file HTML/CSS/JS static site that reads `game-state.json` and renders a visual Monopoly board with player positions, property ownership, houses/hotels, and a game log. Auto-refreshes every 2 seconds. + +## Quick Start + +```bash +# 1. Configure the bot +cp bot/config.json bot/config.local.json +# Edit config with your IRC server/channel details + +# 2. Install bot dependencies +pip install -r bot/requirements.txt + +# 3. Start the bot +cd bot && python3 monopbot.py + +# 4. Serve the board viewer +cd site && python3 -m http.server 8080 +# Open http://localhost:8080 +``` + +## How It Works + +1. monop-irc runs in an IRC channel, outputting game text +2. The bot parses messages (rolls, movement, purchases, rent, jail, etc.) +3. Game state is written to `game-state.json` after each change +4. The board viewer polls the JSON file and renders the board + +## License + +BSD (matching the original bsdgames monop license) diff --git a/bot/__pycache__/board_data.cpython-310.pyc b/bot/__pycache__/board_data.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6c775697d90c14333beeae38c4ecc5147f8638fc GIT binary patch literal 3932 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 bllGooKMd_(`sB#!*Y&Kfrqzs^L52Sh#5{GR literal 0 HcmV?d00001 diff --git a/bot/__pycache__/parser.cpython-310.pyc b/bot/__pycache__/parser.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c109a460cf106a8bfe2340a1d8e21e87941961a6 GIT binary patch literal 8059 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 A(EtDd literal 0 HcmV?d00001 diff --git a/bot/config.json b/bot/config.json index f216aff..e15a6af 100644 --- a/bot/config.json +++ b/bot/config.json @@ -3,7 +3,7 @@ "port": 6697, "tls": true, "nick": "monopbot", - "channel": "#monop-test", + "channel": "#monop-dev", "game_nick": "monop", "state_file": "../game-state.json" } diff --git a/bot/monopbot.py b/bot/monopbot.py index c04cf06..ff912e3 100644 --- a/bot/monopbot.py +++ b/bot/monopbot.py @@ -107,7 +107,10 @@ class MonopBot: try: connect_params = {} if config.get("tls", False): - ssl_factory = irc.connection.Factory(wrapper=ssl.wrap_socket) + ssl_ctx = ssl.create_default_context() + hostname = config["server"] + ssl_factory = irc.connection.Factory( + wrapper=lambda s: ssl_ctx.wrap_socket(s, server_hostname=hostname)) connect_params["connect_factory"] = ssl_factory server = reactor.server() diff --git a/bot/parser.py b/bot/parser.py index 5d6ae86..1dfc20b 100644 --- a/bot/parser.py +++ b/bot/parser.py @@ -289,8 +289,8 @@ class MonopParser: # Holdings cash line if self._parsing_holdings and self._holdings_player is not None: - m = re.match(r"\s+\$(\d+)", line) - if m: + m = re.match(r"\s+\$?(\d+)", line) + if m and line.strip()[0] in "$0123456789": self.players[self._holdings_player]["money"] = int(m.group(1)) # Check for GOJF cards gojf_m = re.search(r"(\d+) get-out-of-jail-free card", line) diff --git a/game-state.json b/game-state.json new file mode 100644 index 0000000..7211d4b --- /dev/null +++ b/game-state.json @@ -0,0 +1,678 @@ +{ + "players": [], + "currentPlayer": 0, + "squares": [ + { + "id": 0, + "name": "Go", + "type": "safe", + "owner": -1, + "cost": 0, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": null, + "rent": [ + 0 + ] + }, + { + "id": 1, + "name": "Mediterranean Ave.", + "type": "property", + "owner": -1, + "cost": 60, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "purple", + "rent": [ + 2, + 10, + 30, + 90, + 160, + 250 + ] + }, + { + "id": 2, + "name": "Community Chest", + "type": "cc", + "owner": -1, + "cost": 0, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": null, + "rent": [ + 0 + ] + }, + { + "id": 3, + "name": "Baltic Ave.", + "type": "property", + "owner": -1, + "cost": 60, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "purple", + "rent": [ + 4, + 20, + 60, + 180, + 320, + 450 + ] + }, + { + "id": 4, + "name": "Income Tax", + "type": "tax", + "owner": -1, + "cost": 0, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": null, + "rent": [ + 0 + ] + }, + { + "id": 5, + "name": "Reading Railroad", + "type": "railroad", + "owner": -1, + "cost": 200, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "railroad", + "rent": [ + 0 + ] + }, + { + "id": 6, + "name": "Oriental Ave.", + "type": "property", + "owner": -1, + "cost": 100, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "lightblue", + "rent": [ + 6, + 30, + 90, + 270, + 400, + 550 + ] + }, + { + "id": 7, + "name": "Chance", + "type": "chance", + "owner": -1, + "cost": 0, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": null, + "rent": [ + 0 + ] + }, + { + "id": 8, + "name": "Vermont Ave.", + "type": "property", + "owner": -1, + "cost": 100, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "lightblue", + "rent": [ + 6, + 30, + 90, + 270, + 400, + 550 + ] + }, + { + "id": 9, + "name": "Connecticut Ave.", + "type": "property", + "owner": -1, + "cost": 120, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "lightblue", + "rent": [ + 8, + 40, + 100, + 300, + 450, + 600 + ] + }, + { + "id": 10, + "name": "Just Visiting", + "type": "jail", + "owner": -1, + "cost": 0, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": null, + "rent": [ + 0 + ] + }, + { + "id": 11, + "name": "St. Charles Place", + "type": "property", + "owner": -1, + "cost": 140, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "pink", + "rent": [ + 10, + 50, + 150, + 450, + 625, + 750 + ] + }, + { + "id": 12, + "name": "Electric Company", + "type": "utility", + "owner": -1, + "cost": 150, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "utility", + "rent": [ + 0 + ] + }, + { + "id": 13, + "name": "States Ave.", + "type": "property", + "owner": -1, + "cost": 140, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "pink", + "rent": [ + 10, + 50, + 150, + 450, + 625, + 750 + ] + }, + { + "id": 14, + "name": "Virginia Ave.", + "type": "property", + "owner": -1, + "cost": 160, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "pink", + "rent": [ + 12, + 60, + 180, + 500, + 700, + 900 + ] + }, + { + "id": 15, + "name": "Pennsylvania Railroad", + "type": "railroad", + "owner": -1, + "cost": 200, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "railroad", + "rent": [ + 0 + ] + }, + { + "id": 16, + "name": "St. James Place", + "type": "property", + "owner": -1, + "cost": 180, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "orange", + "rent": [ + 14, + 70, + 200, + 550, + 750, + 950 + ] + }, + { + "id": 17, + "name": "Community Chest", + "type": "cc", + "owner": -1, + "cost": 0, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": null, + "rent": [ + 0 + ] + }, + { + "id": 18, + "name": "Tennessee Ave.", + "type": "property", + "owner": -1, + "cost": 180, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "orange", + "rent": [ + 14, + 70, + 200, + 550, + 750, + 950 + ] + }, + { + "id": 19, + "name": "New York Ave.", + "type": "property", + "owner": -1, + "cost": 200, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "orange", + "rent": [ + 16, + 80, + 220, + 600, + 800, + 1000 + ] + }, + { + "id": 20, + "name": "Free Parking", + "type": "safe", + "owner": -1, + "cost": 0, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": null, + "rent": [ + 0 + ] + }, + { + "id": 21, + "name": "Kentucky Ave.", + "type": "property", + "owner": -1, + "cost": 220, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "red", + "rent": [ + 18, + 90, + 250, + 700, + 875, + 1050 + ] + }, + { + "id": 22, + "name": "Chance", + "type": "chance", + "owner": -1, + "cost": 0, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": null, + "rent": [ + 0 + ] + }, + { + "id": 23, + "name": "Indiana Ave.", + "type": "property", + "owner": -1, + "cost": 220, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "red", + "rent": [ + 18, + 90, + 250, + 700, + 875, + 1050 + ] + }, + { + "id": 24, + "name": "Illinois Ave.", + "type": "property", + "owner": -1, + "cost": 240, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "red", + "rent": [ + 20, + 100, + 300, + 750, + 925, + 1100 + ] + }, + { + "id": 25, + "name": "B&O Railroad", + "type": "railroad", + "owner": -1, + "cost": 200, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "railroad", + "rent": [ + 0 + ] + }, + { + "id": 26, + "name": "Atlantic Ave.", + "type": "property", + "owner": -1, + "cost": 260, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "yellow", + "rent": [ + 22, + 110, + 330, + 800, + 975, + 1150 + ] + }, + { + "id": 27, + "name": "Ventnor Ave.", + "type": "property", + "owner": -1, + "cost": 260, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "yellow", + "rent": [ + 22, + 110, + 330, + 800, + 975, + 1150 + ] + }, + { + "id": 28, + "name": "Water Works", + "type": "utility", + "owner": -1, + "cost": 150, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "utility", + "rent": [ + 0 + ] + }, + { + "id": 29, + "name": "Marvin Gardens", + "type": "property", + "owner": -1, + "cost": 280, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "yellow", + "rent": [ + 24, + 120, + 360, + 850, + 1025, + 1200 + ] + }, + { + "id": 30, + "name": "Go to Jail", + "type": "gotojail", + "owner": -1, + "cost": 0, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": null, + "rent": [ + 0 + ] + }, + { + "id": 31, + "name": "Pacific Ave.", + "type": "property", + "owner": -1, + "cost": 300, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "green", + "rent": [ + 26, + 130, + 390, + 900, + 1100, + 1275 + ] + }, + { + "id": 32, + "name": "North Carolina Ave.", + "type": "property", + "owner": -1, + "cost": 300, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "green", + "rent": [ + 26, + 130, + 390, + 900, + 1100, + 1275 + ] + }, + { + "id": 33, + "name": "Community Chest", + "type": "cc", + "owner": -1, + "cost": 0, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": null, + "rent": [ + 0 + ] + }, + { + "id": 34, + "name": "Pennsylvania Ave.", + "type": "property", + "owner": -1, + "cost": 320, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "green", + "rent": [ + 28, + 150, + 450, + 1000, + 1200, + 1400 + ] + }, + { + "id": 35, + "name": "Short Line Railroad", + "type": "railroad", + "owner": -1, + "cost": 200, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "railroad", + "rent": [ + 0 + ] + }, + { + "id": 36, + "name": "Chance", + "type": "chance", + "owner": -1, + "cost": 0, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": null, + "rent": [ + 0 + ] + }, + { + "id": 37, + "name": "Park Place", + "type": "property", + "owner": -1, + "cost": 350, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "darkblue", + "rent": [ + 35, + 175, + 500, + 1100, + 1300, + 1500 + ] + }, + { + "id": 38, + "name": "Luxury Tax", + "type": "tax", + "owner": -1, + "cost": 0, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": null, + "rent": [ + 0 + ] + }, + { + "id": 39, + "name": "Boardwalk", + "type": "property", + "owner": -1, + "cost": 400, + "mortgaged": false, + "houses": 0, + "monopoly": false, + "group": "darkblue", + "rent": [ + 50, + 200, + 600, + 1400, + 1700, + 2000 + ] + } + ], + "log": [], + "lastUpdated": "2026-02-20T21:05:15.895061+00:00" +} \ No newline at end of file