pyircbot/pyircbot/modules/CardsAgainstHumanity.py

255 lines
11 KiB
Python
Executable File

#!/usr/bin/env python
"""
.. module::CardsAgainstHumanity
:synopsis: Cards against Humanity, in IRC. Cards against IRC?
.. moduleauthor:: Nick Krichevsky <nick@ollien.com>
"""
from pyircbot.modulebase import ModuleBase,ModuleHook
import os
import time
from threading import Timer
from operator import itemgetter
from random import choice
class CardsAgainstHumanity(ModuleBase):
def __init__(self, bot, moduleName):
# init the base module
ModuleBase.__init__(self, bot, moduleName);
self.hooks=[ModuleHook("PRIVMSG", self.scramble)]
# Dictionary
self.whitesFile = open(self.getFilePath("answers.txt"),'r')
self.blacksFile = open(self.getFilePath("questions.txt"),'r')
self.whites = [line.rstrip() for line in self.whitesFile]
self.blacks = [line.rstrip() for line in self.blacksFile]
self.currentBlack = ""
self.whitesFile.close()
self.blacksFile.close()
self.log.info("CAH: Loaded."+str(len(self.whites))+" White Cards "+str(len(self.blacks))+" Black Cards")
# Per channel games
self.games = {}
def scramble(self, args, prefix, trailing):
channel = args[0]
if channel[0] == "#":
if not channel in self.games:
self.games[channel]=cardsGame(self, channel,self.whites,self.blacks)
self.games[channel].stuff(args, prefix, trailing)
def ondisable(self):
self.log.info("CAH: Unload requested, ending games...")
# for game in self.games:
# self.games[game].gameover()
class cardsGame:
def __init__(self, master, channel,whites,blacks):
self.master = master
self.channel = channel
# Running?
self.running = False
# Current word
# self.message = 'xmopxshell has downs'
self.players = {}
self.timers = {}
self.whites = whites
self.blacks = blacks
self.lastCzar = -1
self.czar = ""
self.started = False
self.active = False
self.allowPick = 0
self.choices = {}
self.czarTimer = None
def stuff(self, args, prefix, trailing):
prefix = self.master.bot.decodePrefix(prefix)
sender = prefix.nick
if self.master.bot.messageHasCommand(".joinGame", trailing):
self.join(sender)
elif self.master.bot.messageHasCommand(".ready",trailing):
result = self.markReady(sender)
if result:
self.started = True
self.master.bot.act_PRIVMSG(self.channel,"All players are ready!")
for player in self.players:
self.master.bot.act_PRIVMSG(player,"ITS TIME TO D-D-D-D-D-DUEL!")
self.players[player]=[]
for player in self.players:
self.deal(player)
self.sendCards(player)
self.active = True
self.makeTurn()
elif self.master.bot.messageHasCommand(".pick",trailing):
if self.active:
if sender != self.czar:
print(sender,self.czar)
print(sender != self.czar)
if self.allowPick > 0:
if sender in self.players:
cards = trailing.split(' ')[1:]
if len(cards)==self.allowPick:
if self.checkBounds(cards):
if sender not in self.choices:
cardChoices = [self.players[sender][int(index)] for index in cards]
print(cardChoices)
self.choices[sender] = cardChoices
self.removeAndReplenishCards(sender, cardChoices)
self.sendCards(sender)
del self.choices[sender]
if sender in timers:
self.timers[sender].cancel()
if self.allDrawn():
self.readChoices()
self.master.bot.act_PRIVMSG(self.channel,self.czar+"! Please choose the winner!")
czarTimer = Timer(180,self.kick,(self.czar,"taking too long to pick a choice. The next turn iwll be made."))
self.makeTurn()
else:
self.master.bot.act_PRIVMSG(self.channel,sender+", you picked a card that was out of the range. Please don't do that.")
else:
self.master.bot.act_PRIVMSG(self.channel,sender+", you picked "+str(len(cards))+" cards. You were supposed to pick "+str(self.allowPick))
elif self.master.bot.messageHasCommand(".choose",trailing):
if sender==self.czar:
choice = trailing.split()[1:]
if len(choice)==1:
if self.checkChoiceBounds(int(choice[0])):
self.master.bot.act_PRIVMSG(self.channel,list(self.choices.keys())[int(choice[0])]+", you won the round!")
if self.czarTimer!=None:
self.czarTimer.cancel()
self.makeTurn()
else:
self.master.bot.act_PRIVMSG(self.channel,sender+", your choice was out of the range. Please don't do that.")
else:
self.master.bot.act_PRIVMSG(self.channel,sender+", you picked "+str(len(choice))+" "+" winners. You were only supposed to pick 1.")
elif self.master.bot.messageHasCommand('.leave',trailing):
if sender in self.players:
self.kick(sender,'choosing to leave the game you dolt')
if sender is self.czar:
self.makeTurn()
def join(self,nick):
if not self.started:
if nick not in self.players:
self.players[nick]=False
self.master.bot.act_PRIVMSG(self.channel, nick+" has joined the game! | The players currently are "+str(self.players))
else:
print("the game has already started!")
self.master.bot.act_PRIVMSG(self.channel,"The game has already started!")
def markReady(self,nick):
if not self.started:
if nick in self.players:
self.players[nick]=True
for player in self.players:
print(player)
if not self.players[player]:
print (player+" not ready")
return False
return True
else:
self.master.bot.act_PRIVMSG(self.channel, "You are not in the game! Type .joinGame!")
else:
print("game has already started!")
self.master.bot.act_PRIVMSG(self.channel,"The game has already started!")
def deal(self,nick):
self.players[nick] = [self.pickWhite() for i in range (7)]
def pickWhite(self):
card = choice(self.whites)
self.whites.remove(card)
return card
def pickBlack(self):
card = choice(self.blacks)
self.blacks.remove(card)
return card
def sendCards(self,nick):
cards = ""
for card in self.players[nick]:
cards+=str(self.players[nick].index(card))+". "
cards+=card+" "
self.master.bot.act_PRIVMSG(nick,"Your cards are "+cards)
def readCard(self,card):
count = card.count('_')
if count == 0:
if 'haiku' in card:
count = 3
else:
count = 1
self.master.bot.act_PRIVMSG(self.channel,"The black card is \""+card+"\" Pick "+str(count))
return count
def pickCzar(self):
index = self.lastCzar+1
if index < len(self.players):
self.lastCzar = index
return index
else:
self.lastCzar = 0
return 0
def announceCzar(self):
self.master.bot.act_PRIVMSG(self.channel,"The Czar is "+self.czar+"!")
def checkBounds(self,cards):
for item in cards:
if int(item)>6 or int(item)<0:
return False
return True
def checkChoiceBounds(self,choice):
if choice<0 or choice>len(self.choices)-1:
return False
return True
def makeTurn(self):
self.choices.clear()
card = self.pickBlack()
self.timers.clear()
self.currentBlack = card
self.allowPick = self.readCard(card)
self.lastCzar = self.pickCzar()
self.czar = list(self.players.keys())[self.lastCzar]
print (self.lastCzar,self.czar)
for player in self.players:
if player!=self.czar:
self.timers[player] = Timer(180,self.kick,(player,"taking more than 180 seconds for their turn."))
self.timers[player].start()
self.announceCzar()
def kick(self,nick,reason):
del self.players[nick]
if nick in self.timers:
self.timers[nick].cancel()
del self.timers[nick]
self.master.bot.act_PRIVMSG(self.channel,nick+" has been kicked due to "+reason)
if len(self.players)<=1:
self.master.bot.act_PRIVMSG(self.channel,"The game is being shut down due to having <=1 players")
self.started = False
self.active = False
for timer in self.timers:
timer.cancel()
self.timers.clear()
self.players.clear()
def removeAndReplenishCards(self,nick,cards):
for card in cards:
self.players[nick].remove(card)
self.players[nick].append(self.pickWhite())
def readChoices(self):
if '_' in self.currentBlack:
for player in list(self.choices.keys()):
cardInstance = str(list(self.choices.keys()).index(player))+". "+self.currentBlack
cardInstance = list(cardInstance) #do this as opposed to space to preserve spaces
for choice in self.choices[player]:
for char in cardInstance:
if char=='_':
print(char)
choice = choice.replace('.','')
cardInstance[cardInstance.index(char)] = choice
break
self.master.bot.act_PRIVMSG(self.channel,''.join(cardInstance))
else:
for player in self.choices:
self.master.bot.act_PRIVMSG(self.channel,self.currentBlack+' '+' '.join(self.choices[player]))
def allDrawn(self):
for player in self.players:
if player not in self.choices:
if player != self.czar:
return False
return True