151 lines
4.3 KiB
Python
151 lines
4.3 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""Simple IRC bot that plays monop by sending dot-prefixed commands."""
|
||
|
|
|
||
|
|
import ssl
|
||
|
|
import sys
|
||
|
|
import time
|
||
|
|
import random
|
||
|
|
import irc.client
|
||
|
|
import irc.connection
|
||
|
|
|
||
|
|
SERVER = "irc.darkscience.net"
|
||
|
|
PORT = 6697
|
||
|
|
CHANNEL = "#monop-dev"
|
||
|
|
|
||
|
|
class PlayerBot:
|
||
|
|
def __init__(self, nick, commands):
|
||
|
|
self.nick = nick
|
||
|
|
self.commands = list(commands) # list of (delay, command) tuples
|
||
|
|
self.cmd_idx = 0
|
||
|
|
self.connection = None
|
||
|
|
self.joined = False
|
||
|
|
self.last_cmd_time = 0
|
||
|
|
|
||
|
|
def on_connect(self, conn, event):
|
||
|
|
print(f"[{self.nick}] Connected, joining {CHANNEL}", flush=True)
|
||
|
|
self.connection = conn
|
||
|
|
conn.join(CHANNEL)
|
||
|
|
|
||
|
|
def on_join(self, conn, event):
|
||
|
|
if event.source.nick == self.nick:
|
||
|
|
print(f"[{self.nick}] Joined {CHANNEL}", flush=True)
|
||
|
|
self.joined = True
|
||
|
|
self.last_cmd_time = time.time()
|
||
|
|
|
||
|
|
def on_pubmsg(self, conn, event):
|
||
|
|
msg = event.arguments[0] if event.arguments else ""
|
||
|
|
nick = event.source.nick if event.source else ""
|
||
|
|
# React to game prompts
|
||
|
|
if nick == "monopoly" and self.joined:
|
||
|
|
if "Do you want to buy?" in msg:
|
||
|
|
time.sleep(0.5)
|
||
|
|
conn.privmsg(CHANNEL, ".yes")
|
||
|
|
elif "How many players?" in msg:
|
||
|
|
time.sleep(0.5)
|
||
|
|
conn.privmsg(CHANNEL, ".3")
|
||
|
|
|
||
|
|
def send_next_command(self):
|
||
|
|
if self.cmd_idx < len(self.commands) and self.joined:
|
||
|
|
delay, cmd = self.commands[self.cmd_idx]
|
||
|
|
if time.time() - self.last_cmd_time >= delay:
|
||
|
|
print(f"[{self.nick}] Sending: {cmd}", flush=True)
|
||
|
|
self.connection.privmsg(CHANNEL, cmd)
|
||
|
|
self.last_cmd_time = time.time()
|
||
|
|
self.cmd_idx += 1
|
||
|
|
return True
|
||
|
|
return False
|
||
|
|
|
||
|
|
|
||
|
|
def main():
|
||
|
|
# Script the game setup and several turns
|
||
|
|
# Player 1 starts the game with ".3" (3 players)
|
||
|
|
# Then each player provides their name
|
||
|
|
# Then they take turns rolling (just press enter = ".roll" or ".")
|
||
|
|
|
||
|
|
alice_cmds = [
|
||
|
|
(3, ".3"), # start 3 player game
|
||
|
|
(2, ".Alice"), # enter name
|
||
|
|
(8, "."), # roll (first turn after setup)
|
||
|
|
(4, "."), # action/roll
|
||
|
|
(6, "."),
|
||
|
|
(6, "."),
|
||
|
|
(6, "."),
|
||
|
|
(6, "."),
|
||
|
|
(6, "."),
|
||
|
|
(6, "."),
|
||
|
|
(6, "."),
|
||
|
|
(6, "."),
|
||
|
|
]
|
||
|
|
|
||
|
|
bob_cmds = [
|
||
|
|
(6, ".Bob"), # enter name
|
||
|
|
(10, "."), # roll
|
||
|
|
(6, "."),
|
||
|
|
(6, "."),
|
||
|
|
(6, "."),
|
||
|
|
(6, "."),
|
||
|
|
(6, "."),
|
||
|
|
(6, "."),
|
||
|
|
(6, "."),
|
||
|
|
(6, "."),
|
||
|
|
]
|
||
|
|
|
||
|
|
charlie_cmds = [
|
||
|
|
(8, ".Charlie"), # enter name
|
||
|
|
(12, "."), # roll
|
||
|
|
(6, "."),
|
||
|
|
(6, "."),
|
||
|
|
(6, "."),
|
||
|
|
(6, "."),
|
||
|
|
(6, "."),
|
||
|
|
(6, "."),
|
||
|
|
(6, "."),
|
||
|
|
(6, "."),
|
||
|
|
]
|
||
|
|
|
||
|
|
bots = [
|
||
|
|
PlayerBot("alice_m", alice_cmds),
|
||
|
|
PlayerBot("bob_m", bob_cmds),
|
||
|
|
PlayerBot("charlie_m", charlie_cmds),
|
||
|
|
]
|
||
|
|
|
||
|
|
reactor = irc.client.Reactor()
|
||
|
|
ssl_ctx = ssl.create_default_context()
|
||
|
|
|
||
|
|
for bot in bots:
|
||
|
|
factory = irc.connection.Factory(
|
||
|
|
wrapper=lambda s: ssl_ctx.wrap_socket(s, server_hostname=SERVER))
|
||
|
|
server = reactor.server()
|
||
|
|
server.connect(SERVER, PORT, bot.nick, connect_factory=factory)
|
||
|
|
server.add_global_handler("welcome", bot.on_connect)
|
||
|
|
server.add_global_handler("join", bot.on_join)
|
||
|
|
server.add_global_handler("pubmsg", bot.on_pubmsg)
|
||
|
|
time.sleep(1) # stagger connections
|
||
|
|
|
||
|
|
print("All bots connecting...", flush=True)
|
||
|
|
|
||
|
|
start = time.time()
|
||
|
|
timeout = 180 # 3 minutes
|
||
|
|
|
||
|
|
while time.time() - start < timeout:
|
||
|
|
reactor.process_once(timeout=0.5)
|
||
|
|
for bot in bots:
|
||
|
|
bot.send_next_command()
|
||
|
|
|
||
|
|
# Check if all bots are done
|
||
|
|
if all(b.cmd_idx >= len(b.commands) for b in bots):
|
||
|
|
print("All commands sent. Waiting 10s for final output...", flush=True)
|
||
|
|
end = time.time() + 10
|
||
|
|
while time.time() < end:
|
||
|
|
reactor.process_once(timeout=0.5)
|
||
|
|
break
|
||
|
|
|
||
|
|
print("Done!", flush=True)
|
||
|
|
for bot in bots:
|
||
|
|
if bot.connection:
|
||
|
|
bot.connection.quit("Game over!")
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main()
|