Fix trade logic in player bots
- Handle 'Which player do you wish to trade with?' prompt when in_trade is True (was silently returning, causing bot to roll during an active trade prompt) - Simplify property trade offers to always say 'done' (cash-only trades) to avoid getting stuck on property list prompts
This commit is contained in:
parent
d2bd66ba78
commit
d31a09e754
4 changed files with 634 additions and 86 deletions
Binary file not shown.
|
|
@ -358,7 +358,16 @@ class PlayerBot:
|
||||||
return
|
return
|
||||||
|
|
||||||
if msg.startswith("Which player do you wish to trade with?"):
|
if msg.startswith("Which player do you wish to trade with?"):
|
||||||
# We don't trade proactively — shouldn't hit this
|
if self.in_trade and self.is_my_turn():
|
||||||
|
# Pick a random other player to trade with
|
||||||
|
others = [n for n in self.player_names if n.lower() != self.nick.lower()]
|
||||||
|
if others:
|
||||||
|
target = random.choice(others)
|
||||||
|
self.log(f"Trading with {target}")
|
||||||
|
self.say_delayed(target, force=True)
|
||||||
|
else:
|
||||||
|
self.say_delayed("done", force=True)
|
||||||
|
self.in_trade = False
|
||||||
return
|
return
|
||||||
|
|
||||||
# (Trade property prompt handled in TRADING section below)
|
# (Trade property prompt handled in TRADING section below)
|
||||||
|
|
@ -524,12 +533,8 @@ class PlayerBot:
|
||||||
# "Which property do you wish to trade?" — pick a property or done
|
# "Which property do you wish to trade?" — pick a property or done
|
||||||
if msg == "Which property do you wish to trade?":
|
if msg == "Which property do you wish to trade?":
|
||||||
if self.in_trade:
|
if self.in_trade:
|
||||||
if self.trade_props_offered == 0 and random.random() < 0.5:
|
# Keep it simple — cash-only trades, skip property offers
|
||||||
# Offer one property then done
|
self.say_delayed("done", force=True)
|
||||||
self.trade_props_offered = 1
|
|
||||||
self.say_delayed("?", force=True) # get the list
|
|
||||||
else:
|
|
||||||
self.say_delayed("done", force=True)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# "You have $X. How much are you trading?" — offer some cash
|
# "You have $X. How much are you trading?" — offer some cash
|
||||||
|
|
|
||||||
112
run_game.py
Normal file
112
run_game.py
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Run a simulated game: player bots + parser writing game-state.json to site/."""
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import socket
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.dirname(__file__))
|
||||||
|
from monop_parser import MonopParser
|
||||||
|
from monop_players import PlayerBot
|
||||||
|
|
||||||
|
STATE_PATH = os.path.join(os.path.dirname(__file__), "site", "game-state.json")
|
||||||
|
HOST = "127.0.0.1"
|
||||||
|
PORT = 6667
|
||||||
|
CHANNEL = "#monop"
|
||||||
|
BOT_NICK = "monop"
|
||||||
|
|
||||||
|
class ParserClient:
|
||||||
|
"""IRC client that watches the game and writes game-state.json."""
|
||||||
|
def __init__(self):
|
||||||
|
self.parser = MonopParser()
|
||||||
|
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
self.buffer = ""
|
||||||
|
self.running = True
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
self.sock.connect((HOST, PORT))
|
||||||
|
self.sock.sendall(b"NICK observer\r\nUSER observer 0 * :observer\r\n")
|
||||||
|
time.sleep(1)
|
||||||
|
self.sock.sendall(f"JOIN {CHANNEL}\r\n".encode())
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.connect()
|
||||||
|
while self.running:
|
||||||
|
try:
|
||||||
|
data = self.sock.recv(4096)
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
self.buffer += data.decode("utf-8", errors="replace")
|
||||||
|
while "\r\n" in self.buffer:
|
||||||
|
line, self.buffer = self.buffer.split("\r\n", 1)
|
||||||
|
self._handle(line)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[parser] Error: {e}")
|
||||||
|
break
|
||||||
|
|
||||||
|
def _handle(self, line):
|
||||||
|
if line.startswith("PING"):
|
||||||
|
self.sock.sendall(f"PONG {line[5:]}\r\n".encode())
|
||||||
|
return
|
||||||
|
# Parse PRIVMSG from bot
|
||||||
|
if "PRIVMSG" in line and CHANNEL in line:
|
||||||
|
# :nick!user@host PRIVMSG #chan :message
|
||||||
|
parts = line.split(f"PRIVMSG {CHANNEL} :", 1)
|
||||||
|
if len(parts) == 2:
|
||||||
|
prefix = parts[0].strip()
|
||||||
|
sender = prefix.split("!")[0].lstrip(":")
|
||||||
|
message = parts[1]
|
||||||
|
ts = time.strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
log_line = f"{ts}\t{sender}\t{message}"
|
||||||
|
self.parser.parse_line(log_line)
|
||||||
|
state = self.parser.get_state()
|
||||||
|
if state:
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
state["lastUpdated"] = datetime.now(timezone.utc).isoformat()
|
||||||
|
try:
|
||||||
|
with open(STATE_PATH, "w") as f:
|
||||||
|
json.dump(state, f, indent=2)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[parser] Write error: {e}")
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.running = False
|
||||||
|
try:
|
||||||
|
self.sock.close()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
player_names = ["alice", "bob", "charlie"]
|
||||||
|
|
||||||
|
# Start parser client
|
||||||
|
pc = ParserClient()
|
||||||
|
parser_thread = threading.Thread(target=pc.run, daemon=True)
|
||||||
|
parser_thread.start()
|
||||||
|
print(f"[game] Parser writing to {STATE_PATH}")
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
|
# Start player bots
|
||||||
|
bots = []
|
||||||
|
for i, name in enumerate(player_names):
|
||||||
|
bot = PlayerBot(name, CHANNEL, HOST, PORT, player_names, i)
|
||||||
|
t = threading.Thread(target=bot.run, daemon=True)
|
||||||
|
t.start()
|
||||||
|
bots.append(bot)
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
print(f"[game] {len(bots)} player bots started")
|
||||||
|
|
||||||
|
# Run until killed
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
time.sleep(1)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("[game] Shutting down...")
|
||||||
|
pc.stop()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
@ -1,91 +1,522 @@
|
||||||
{
|
{
|
||||||
"players": [
|
"players": [
|
||||||
{
|
{
|
||||||
"name": "Alice",
|
"name": "charlie",
|
||||||
"number": 1,
|
|
||||||
"money": 1500,
|
|
||||||
"location": 0,
|
|
||||||
"inJail": false,
|
|
||||||
"jailTurns": 0,
|
|
||||||
"doublesCount": 0,
|
|
||||||
"getOutOfJailFreeCards": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Bob",
|
|
||||||
"number": 2,
|
|
||||||
"money": 1500,
|
|
||||||
"location": 0,
|
|
||||||
"inJail": false,
|
|
||||||
"jailTurns": 0,
|
|
||||||
"doublesCount": 0,
|
|
||||||
"getOutOfJailFreeCards": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Charlie",
|
|
||||||
"number": 3,
|
"number": 3,
|
||||||
"money": 1500,
|
"money": 985,
|
||||||
"location": 0,
|
"location": 40,
|
||||||
|
"inJail": true,
|
||||||
|
"jailTurns": 1,
|
||||||
|
"doublesCount": 0,
|
||||||
|
"getOutOfJailFreeCards": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "alice",
|
||||||
|
"number": 1,
|
||||||
|
"money": 1375,
|
||||||
|
"location": 40,
|
||||||
|
"inJail": true,
|
||||||
|
"jailTurns": 0,
|
||||||
|
"doublesCount": 0,
|
||||||
|
"getOutOfJailFreeCards": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "bob",
|
||||||
|
"number": 2,
|
||||||
|
"money": 800,
|
||||||
|
"location": 31,
|
||||||
"inJail": false,
|
"inJail": false,
|
||||||
"jailTurns": 0,
|
"jailTurns": 0,
|
||||||
"doublesCount": 0,
|
"doublesCount": 0,
|
||||||
"getOutOfJailFreeCards": 0
|
"getOutOfJailFreeCards": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"currentPlayer": 1,
|
"currentPlayer": 3,
|
||||||
"squares": [
|
"squares": [
|
||||||
{ "id": 0, "name": "=== GO ===", "type": "safe" },
|
{
|
||||||
{ "id": 1, "name": "Mediterranean ave. (P)", "type": "property", "group": "purple", "cost": 60, "owner": null, "mortgaged": false, "houses": 0, "rent": [2, 10, 30, 90, 160, 250] },
|
"id": 0,
|
||||||
{ "id": 2, "name": "Community Chest i", "type": "cc" },
|
"name": "=== GO ===",
|
||||||
{ "id": 3, "name": "Baltic ave. (P)", "type": "property", "group": "purple", "cost": 60, "owner": null, "mortgaged": false, "houses": 0, "rent": [4, 20, 60, 180, 320, 450] },
|
"type": "safe"
|
||||||
{ "id": 4, "name": "Income Tax", "type": "tax" },
|
},
|
||||||
{ "id": 5, "name": "Reading RR", "type": "railroad", "group": "railroad", "cost": 200, "owner": null, "mortgaged": false },
|
{
|
||||||
{ "id": 6, "name": "Oriental ave. (L)", "type": "property", "group": "lightblue", "cost": 100, "owner": null, "mortgaged": false, "houses": 0, "rent": [6, 30, 90, 270, 400, 550] },
|
"id": 1,
|
||||||
{ "id": 7, "name": "Chance i", "type": "chance" },
|
"name": "Mediterranean ave. (P)",
|
||||||
{ "id": 8, "name": "Vermont ave. (L)", "type": "property", "group": "lightblue", "cost": 100, "owner": null, "mortgaged": false, "houses": 0, "rent": [6, 30, 90, 270, 400, 550] },
|
"type": "property",
|
||||||
{ "id": 9, "name": "Connecticut ave. (L)", "type": "property", "group": "lightblue", "cost": 120, "owner": null, "mortgaged": false, "houses": 0, "rent": [8, 40, 100, 300, 450, 600] },
|
"owner": null,
|
||||||
{ "id": 10, "name": "Just Visiting", "type": "safe" },
|
"mortgaged": false,
|
||||||
{ "id": 11, "name": "St. Charles pl. (V)", "type": "property", "group": "violet", "cost": 140, "owner": null, "mortgaged": false, "houses": 0, "rent": [10, 50, 150, 450, 625, 750] },
|
"group": "purple",
|
||||||
{ "id": 12, "name": "Electric Co.", "type": "utility", "group": "utility", "cost": 150, "owner": null, "mortgaged": false },
|
"cost": 60,
|
||||||
{ "id": 13, "name": "States ave. (V)", "type": "property", "group": "violet", "cost": 140, "owner": null, "mortgaged": false, "houses": 0, "rent": [10, 50, 150, 450, 625, 750] },
|
"houses": 0
|
||||||
{ "id": 14, "name": "Virginia ave. (V)", "type": "property", "group": "violet", "cost": 160, "owner": null, "mortgaged": false, "houses": 0, "rent": [12, 60, 180, 500, 700, 900] },
|
},
|
||||||
{ "id": 15, "name": "Pennsylvania RR", "type": "railroad", "group": "railroad", "cost": 200, "owner": null, "mortgaged": false },
|
{
|
||||||
{ "id": 16, "name": "St. James pl. (O)", "type": "property", "group": "orange", "cost": 180, "owner": null, "mortgaged": false, "houses": 0, "rent": [14, 70, 200, 550, 750, 950] },
|
"id": 2,
|
||||||
{ "id": 17, "name": "Community Chest ii", "type": "cc" },
|
"name": "Community Chest i",
|
||||||
{ "id": 18, "name": "Tennessee ave. (O)", "type": "property", "group": "orange", "cost": 180, "owner": null, "mortgaged": false, "houses": 0, "rent": [14, 70, 200, 550, 750, 950] },
|
"type": "cc"
|
||||||
{ "id": 19, "name": "New York ave. (O)", "type": "property", "group": "orange", "cost": 200, "owner": null, "mortgaged": false, "houses": 0, "rent": [16, 80, 220, 600, 800, 1000] },
|
},
|
||||||
{ "id": 20, "name": "Free Parking", "type": "safe" },
|
{
|
||||||
{ "id": 21, "name": "Kentucky ave. (R)", "type": "property", "group": "red", "cost": 220, "owner": null, "mortgaged": false, "houses": 0, "rent": [18, 90, 250, 700, 875, 1050] },
|
"id": 3,
|
||||||
{ "id": 22, "name": "Chance ii", "type": "chance" },
|
"name": "Baltic ave. (P)",
|
||||||
{ "id": 23, "name": "Indiana ave. (R)", "type": "property", "group": "red", "cost": 220, "owner": null, "mortgaged": false, "houses": 0, "rent": [18, 90, 250, 700, 875, 1050] },
|
"type": "property",
|
||||||
{ "id": 24, "name": "Illinois ave. (R)", "type": "property", "group": "red", "cost": 240, "owner": null, "mortgaged": false, "houses": 0, "rent": [20, 100, 300, 750, 925, 1100] },
|
"owner": null,
|
||||||
{ "id": 25, "name": "B&O RR", "type": "railroad", "group": "railroad", "cost": 200, "owner": null, "mortgaged": false },
|
"mortgaged": false,
|
||||||
{ "id": 26, "name": "Atlantic ave. (Y)", "type": "property", "group": "yellow", "cost": 260, "owner": null, "mortgaged": false, "houses": 0, "rent": [22, 110, 330, 800, 975, 1150] },
|
"group": "purple",
|
||||||
{ "id": 27, "name": "Ventnor ave. (Y)", "type": "property", "group": "yellow", "cost": 260, "owner": null, "mortgaged": false, "houses": 0, "rent": [22, 110, 330, 800, 975, 1150] },
|
"cost": 60,
|
||||||
{ "id": 28, "name": "Water Works", "type": "utility", "group": "utility", "cost": 150, "owner": null, "mortgaged": false },
|
"houses": 0
|
||||||
{ "id": 29, "name": "Marvin Gardens (Y)", "type": "property", "group": "yellow", "cost": 280, "owner": null, "mortgaged": false, "houses": 0, "rent": [24, 120, 360, 850, 1025, 1200] },
|
},
|
||||||
{ "id": 30, "name": "GO TO JAIL", "type": "gotojail" },
|
{
|
||||||
{ "id": 31, "name": "Pacific ave. (G)", "type": "property", "group": "green", "cost": 300, "owner": null, "mortgaged": false, "houses": 0, "rent": [26, 130, 390, 900, 1100, 1275] },
|
"id": 4,
|
||||||
{ "id": 32, "name": "N. Carolina ave. (G)", "type": "property", "group": "green", "cost": 300, "owner": null, "mortgaged": false, "houses": 0, "rent": [26, 130, 390, 900, 1100, 1275] },
|
"name": "Income Tax",
|
||||||
{ "id": 33, "name": "Community Chest iii", "type": "cc" },
|
"type": "tax"
|
||||||
{ "id": 34, "name": "Pennsylvania ave. (G)", "type": "property", "group": "green", "cost": 320, "owner": null, "mortgaged": false, "houses": 0, "rent": [28, 150, 450, 1000, 1200, 1400] },
|
},
|
||||||
{ "id": 35, "name": "Short Line RR", "type": "railroad", "group": "railroad", "cost": 200, "owner": null, "mortgaged": false },
|
{
|
||||||
{ "id": 36, "name": "Chance iii", "type": "chance" },
|
"id": 5,
|
||||||
{ "id": 37, "name": "Park place (D)", "type": "property", "group": "darkblue", "cost": 350, "owner": null, "mortgaged": false, "houses": 0, "rent": [35, 175, 500, 1100, 1300, 1500] },
|
"name": "Reading RR",
|
||||||
{ "id": 38, "name": "Luxury Tax", "type": "tax" },
|
"type": "railroad",
|
||||||
{ "id": 39, "name": "Boardwalk (D)", "type": "property", "group": "darkblue", "cost": 400, "owner": null, "mortgaged": false, "houses": 0, "rent": [50, 200, 600, 1400, 1700, 2000] }
|
"owner": null,
|
||||||
|
"mortgaged": false,
|
||||||
|
"group": "railroad",
|
||||||
|
"cost": 200
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"name": "Oriental ave. (L)",
|
||||||
|
"type": "property",
|
||||||
|
"owner": 2,
|
||||||
|
"mortgaged": false,
|
||||||
|
"group": "lightblue",
|
||||||
|
"cost": 100,
|
||||||
|
"houses": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 7,
|
||||||
|
"name": "Chance i",
|
||||||
|
"type": "chance"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 8,
|
||||||
|
"name": "Vermont ave. (L)",
|
||||||
|
"type": "property",
|
||||||
|
"owner": 1,
|
||||||
|
"mortgaged": false,
|
||||||
|
"group": "lightblue",
|
||||||
|
"cost": 100,
|
||||||
|
"houses": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 9,
|
||||||
|
"name": "Connecticut ave. (L)",
|
||||||
|
"type": "property",
|
||||||
|
"owner": null,
|
||||||
|
"mortgaged": false,
|
||||||
|
"group": "lightblue",
|
||||||
|
"cost": 120,
|
||||||
|
"houses": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 10,
|
||||||
|
"name": "Just Visiting",
|
||||||
|
"type": "safe"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 11,
|
||||||
|
"name": "St. Charles pl. (V)",
|
||||||
|
"type": "property",
|
||||||
|
"owner": 3,
|
||||||
|
"mortgaged": false,
|
||||||
|
"group": "violet",
|
||||||
|
"cost": 140,
|
||||||
|
"houses": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 12,
|
||||||
|
"name": "Electric Co.",
|
||||||
|
"type": "utility",
|
||||||
|
"owner": 2,
|
||||||
|
"mortgaged": false,
|
||||||
|
"group": "utility",
|
||||||
|
"cost": 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 13,
|
||||||
|
"name": "States ave. (V)",
|
||||||
|
"type": "property",
|
||||||
|
"owner": null,
|
||||||
|
"mortgaged": false,
|
||||||
|
"group": "violet",
|
||||||
|
"cost": 140,
|
||||||
|
"houses": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 14,
|
||||||
|
"name": "Virginia ave. (V)",
|
||||||
|
"type": "property",
|
||||||
|
"owner": null,
|
||||||
|
"mortgaged": false,
|
||||||
|
"group": "violet",
|
||||||
|
"cost": 160,
|
||||||
|
"houses": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 15,
|
||||||
|
"name": "Pennsylvania RR",
|
||||||
|
"type": "railroad",
|
||||||
|
"owner": null,
|
||||||
|
"mortgaged": false,
|
||||||
|
"group": "railroad",
|
||||||
|
"cost": 200
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 16,
|
||||||
|
"name": "St. James pl. (O)",
|
||||||
|
"type": "property",
|
||||||
|
"owner": null,
|
||||||
|
"mortgaged": false,
|
||||||
|
"group": "orange",
|
||||||
|
"cost": 180,
|
||||||
|
"houses": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 17,
|
||||||
|
"name": "Community Chest ii",
|
||||||
|
"type": "cc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 18,
|
||||||
|
"name": "Tennessee ave. (O)",
|
||||||
|
"type": "property",
|
||||||
|
"owner": null,
|
||||||
|
"mortgaged": false,
|
||||||
|
"group": "orange",
|
||||||
|
"cost": 180,
|
||||||
|
"houses": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 19,
|
||||||
|
"name": "New York ave. (O)",
|
||||||
|
"type": "property",
|
||||||
|
"owner": 3,
|
||||||
|
"mortgaged": false,
|
||||||
|
"group": "orange",
|
||||||
|
"cost": 200,
|
||||||
|
"houses": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 20,
|
||||||
|
"name": "Free Parking",
|
||||||
|
"type": "safe"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 21,
|
||||||
|
"name": "Kentucky ave. (R)",
|
||||||
|
"type": "property",
|
||||||
|
"owner": null,
|
||||||
|
"mortgaged": false,
|
||||||
|
"group": "red",
|
||||||
|
"cost": 220,
|
||||||
|
"houses": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 22,
|
||||||
|
"name": "Chance ii",
|
||||||
|
"type": "chance"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 23,
|
||||||
|
"name": "Indiana ave. (R)",
|
||||||
|
"type": "property",
|
||||||
|
"owner": null,
|
||||||
|
"mortgaged": false,
|
||||||
|
"group": "red",
|
||||||
|
"cost": 220,
|
||||||
|
"houses": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 24,
|
||||||
|
"name": "Illinois ave. (R)",
|
||||||
|
"type": "property",
|
||||||
|
"owner": null,
|
||||||
|
"mortgaged": false,
|
||||||
|
"group": "red",
|
||||||
|
"cost": 240,
|
||||||
|
"houses": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 25,
|
||||||
|
"name": "B&O RR",
|
||||||
|
"type": "railroad",
|
||||||
|
"owner": 3,
|
||||||
|
"mortgaged": false,
|
||||||
|
"group": "railroad",
|
||||||
|
"cost": 200
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 26,
|
||||||
|
"name": "Atlantic ave. (Y)",
|
||||||
|
"type": "property",
|
||||||
|
"owner": null,
|
||||||
|
"mortgaged": false,
|
||||||
|
"group": "yellow",
|
||||||
|
"cost": 260,
|
||||||
|
"houses": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 27,
|
||||||
|
"name": "Ventnor ave. (Y)",
|
||||||
|
"type": "property",
|
||||||
|
"owner": null,
|
||||||
|
"mortgaged": false,
|
||||||
|
"group": "yellow",
|
||||||
|
"cost": 260,
|
||||||
|
"houses": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 28,
|
||||||
|
"name": "Water Works",
|
||||||
|
"type": "utility",
|
||||||
|
"owner": 2,
|
||||||
|
"mortgaged": false,
|
||||||
|
"group": "utility",
|
||||||
|
"cost": 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 29,
|
||||||
|
"name": "Marvin Gardens (Y)",
|
||||||
|
"type": "property",
|
||||||
|
"owner": null,
|
||||||
|
"mortgaged": false,
|
||||||
|
"group": "yellow",
|
||||||
|
"cost": 280,
|
||||||
|
"houses": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 30,
|
||||||
|
"name": "GO TO JAIL",
|
||||||
|
"type": "gotojail"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 31,
|
||||||
|
"name": "Pacific ave. (G)",
|
||||||
|
"type": "property",
|
||||||
|
"owner": 2,
|
||||||
|
"mortgaged": false,
|
||||||
|
"group": "green",
|
||||||
|
"cost": 300,
|
||||||
|
"houses": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 32,
|
||||||
|
"name": "N. Carolina ave. (G)",
|
||||||
|
"type": "property",
|
||||||
|
"owner": null,
|
||||||
|
"mortgaged": false,
|
||||||
|
"group": "green",
|
||||||
|
"cost": 300,
|
||||||
|
"houses": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 33,
|
||||||
|
"name": "Community Chest iii",
|
||||||
|
"type": "cc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 34,
|
||||||
|
"name": "Pennsylvania ave. (G)",
|
||||||
|
"type": "property",
|
||||||
|
"owner": null,
|
||||||
|
"mortgaged": false,
|
||||||
|
"group": "green",
|
||||||
|
"cost": 320,
|
||||||
|
"houses": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 35,
|
||||||
|
"name": "Short Line RR",
|
||||||
|
"type": "railroad",
|
||||||
|
"owner": null,
|
||||||
|
"mortgaged": false,
|
||||||
|
"group": "railroad",
|
||||||
|
"cost": 200
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 36,
|
||||||
|
"name": "Chance iii",
|
||||||
|
"type": "chance"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 37,
|
||||||
|
"name": "Park place (D)",
|
||||||
|
"type": "property",
|
||||||
|
"owner": null,
|
||||||
|
"mortgaged": false,
|
||||||
|
"group": "darkblue",
|
||||||
|
"cost": 350,
|
||||||
|
"houses": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 38,
|
||||||
|
"name": "Luxury Tax",
|
||||||
|
"type": "tax"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 39,
|
||||||
|
"name": "Boardwalk (D)",
|
||||||
|
"type": "property",
|
||||||
|
"owner": null,
|
||||||
|
"mortgaged": false,
|
||||||
|
"group": "darkblue",
|
||||||
|
"cost": 400,
|
||||||
|
"houses": 0
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"groups": {
|
"log": [
|
||||||
"purple": { "letter": "P", "size": 2, "houseCost": 50, "squares": [1, 3] },
|
{
|
||||||
"lightblue": { "letter": "L", "size": 3, "houseCost": 50, "squares": [6, 8, 9] },
|
"text": "Landed on Community Chest ii",
|
||||||
"violet": { "letter": "V", "size": 3, "houseCost": 100, "squares": [11, 13, 14] },
|
"player": "alice",
|
||||||
"orange": { "letter": "O", "size": 3, "houseCost": 100, "squares": [16, 18, 19] },
|
"timestamp": "2026-02-21 10:41:53"
|
||||||
"red": { "letter": "R", "size": 3, "houseCost": 150, "squares": [21, 23, 24] },
|
},
|
||||||
"yellow": { "letter": "Y", "size": 3, "houseCost": 150, "squares": [26, 27, 29] },
|
{
|
||||||
"green": { "letter": "G", "size": 3, "houseCost": 200, "squares": [31, 32, 34] },
|
"text": "You are Assessed for street repairs.",
|
||||||
"darkblue": { "letter": "D", "size": 2, "houseCost": 200, "squares": [37, 39] },
|
"player": "alice"
|
||||||
"railroad": { "size": 4, "squares": [5, 15, 25, 35], "rentByCount": [25, 50, 100, 200] },
|
},
|
||||||
"utility": { "size": 2, "squares": [12, 28], "rollMultiplierByCount": [4, 10] }
|
{
|
||||||
},
|
"text": "bob's turn \u2014 $1400 on Oriental ave. (L)",
|
||||||
"log": [],
|
"player": "bob",
|
||||||
"lastUpdated": null
|
"timestamp": "2026-02-21 10:41:57"
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
"text": "roll is 1, 5",
|
||||||
|
"player": "bob",
|
||||||
|
"timestamp": "2026-02-21 10:41:58"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Landed on Electric Co.",
|
||||||
|
"player": "bob",
|
||||||
|
"timestamp": "2026-02-21 10:41:58"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "charlie's turn \u2014 $1160 on New York ave. (O)",
|
||||||
|
"player": "charlie",
|
||||||
|
"timestamp": "2026-02-21 10:42:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "roll is 3, 3",
|
||||||
|
"player": "charlie",
|
||||||
|
"timestamp": "2026-02-21 10:42:01"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Landed on B&O RR",
|
||||||
|
"player": "charlie",
|
||||||
|
"timestamp": "2026-02-21 10:42:01"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "charlie's turn \u2014 $960 on B&O RR",
|
||||||
|
"player": "charlie",
|
||||||
|
"timestamp": "2026-02-21 10:42:04"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "roll is 4, 1",
|
||||||
|
"player": "charlie",
|
||||||
|
"timestamp": "2026-02-21 10:42:05"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Landed on GO TO JAIL!",
|
||||||
|
"player": "charlie",
|
||||||
|
"timestamp": "2026-02-21 10:42:05"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "alice's turn \u2014 $1400 on Community Chest ii",
|
||||||
|
"player": "alice",
|
||||||
|
"timestamp": "2026-02-21 10:42:06"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "roll is 6, 2",
|
||||||
|
"player": "alice",
|
||||||
|
"timestamp": "2026-02-21 10:42:07"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Landed on B&O RR",
|
||||||
|
"player": "alice",
|
||||||
|
"timestamp": "2026-02-21 10:42:08"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Paid $25 rent to charlie",
|
||||||
|
"player": "alice"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "bob's turn \u2014 $1250 on Electric Co.",
|
||||||
|
"player": "bob",
|
||||||
|
"timestamp": "2026-02-21 10:42:09"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "roll is 4, 4",
|
||||||
|
"player": "bob",
|
||||||
|
"timestamp": "2026-02-21 10:42:10"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Landed on Free Parking",
|
||||||
|
"player": "bob",
|
||||||
|
"timestamp": "2026-02-21 10:42:11"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "bob's turn \u2014 $1250 on Free Parking",
|
||||||
|
"player": "bob",
|
||||||
|
"timestamp": "2026-02-21 10:42:12"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "roll is 6, 2",
|
||||||
|
"player": "bob",
|
||||||
|
"timestamp": "2026-02-21 10:42:13"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Landed on Water Works",
|
||||||
|
"player": "bob",
|
||||||
|
"timestamp": "2026-02-21 10:42:14"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "charlie's turn \u2014 $985 on JAIL",
|
||||||
|
"player": "charlie",
|
||||||
|
"timestamp": "2026-02-21 10:42:16"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "roll is 6, 5",
|
||||||
|
"player": "charlie",
|
||||||
|
"timestamp": "2026-02-21 10:42:17"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "alice's turn \u2014 $1375 on B&O RR",
|
||||||
|
"player": "alice",
|
||||||
|
"timestamp": "2026-02-21 10:42:18"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "roll is 2, 3",
|
||||||
|
"player": "alice",
|
||||||
|
"timestamp": "2026-02-21 10:42:20"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Landed on GO TO JAIL!",
|
||||||
|
"player": "alice",
|
||||||
|
"timestamp": "2026-02-21 10:42:20"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "bob's turn \u2014 $1100 on Water Works",
|
||||||
|
"player": "bob",
|
||||||
|
"timestamp": "2026-02-21 10:42:21"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "roll is 1, 2",
|
||||||
|
"player": "bob",
|
||||||
|
"timestamp": "2026-02-21 10:42:22"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Landed on Pacific ave. (G)",
|
||||||
|
"player": "bob",
|
||||||
|
"timestamp": "2026-02-21 10:42:22"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "charlie's turn \u2014 $985 on JAIL",
|
||||||
|
"player": "charlie",
|
||||||
|
"timestamp": "2026-02-21 10:42:24"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"lastUpdated": "2026-02-21T10:42:27.015680+00:00"
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue