Add project README, fix holdings parser, update bot config for #monop-dev

This commit is contained in:
Jarvis 2026-02-20 21:06:36 +00:00
parent c85ace5d7f
commit a336bf0663
7 changed files with 725 additions and 4 deletions

40
README.md Normal file
View file

@ -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)

Binary file not shown.

Binary file not shown.

View file

@ -3,7 +3,7 @@
"port": 6697,
"tls": true,
"nick": "monopbot",
"channel": "#monop-test",
"channel": "#monop-dev",
"game_nick": "monop",
"state_file": "../game-state.json"
}

View file

@ -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()

View file

@ -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)

678
game-state.json Normal file
View file

@ -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"
}