Awesome IRC bot
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

245 lines
8.4 KiB

"""
.. module:: Scramble
:synopsis: Module to provide a word scramble game
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
"""
from pyircbot.modulebase import ModuleBase, hook
from pyircbot.common import messageHasCommand
import random
import json
import os
from threading import Timer
from operator import itemgetter
class Scramble(ModuleBase):
def __init__(self, bot, moduleName):
# init the base module
ModuleBase.__init__(self, bot, moduleName)
# Dictionary
self.wordsCount = 0
self.wordsFile = self.getFilePath("words.txt")
print(self.wordsFile)
wordsF = open(self.wordsFile, "r")
while True:
word = wordsF.readline()
if not word:
break
self.wordsCount += 1
wordsF.close
self.log.info("Scramble: Loaded %s words" % str(self.wordsCount))
# Load scores
self.scoresFile = self.getFilePath("scores.json")
if not os.path.exists(self.scoresFile):
json.dump({}, open(self.scoresFile, 'w'))
self.scores = json.load(open(self.scoresFile, 'r'))
# Per channel games
self.games = {}
# Hook in
@hook("PRIVMSG")
def scramble(self, msg, cmd):
channel = msg.args[0]
if channel[0] == "#":
if channel not in self.games:
self.games[channel] = scrambleGame(self, channel)
self.games[channel].scramble(msg.args, msg.prefix, msg.trailing)
def saveScores(self):
json.dump(self.scores, open(self.scoresFile, 'w'))
def getScore(self, player, add=0):
player = player.lower()
if player not in self.scores:
self.scores[player] = 0
if not add == 0:
self.scores[player] += add
self.saveScores()
return self.scores[player]
def getScoreNoWrite(self, player):
if not player.lower() in self.scores:
return 0
else:
return self.getScore(player)
def ondisable(self):
self.log.info("Scramble: Unload requested, ending games...")
for game in self.games:
self.games[game].gameover()
self.saveScores()
class scrambleGame:
def __init__(self, master, channel):
self.master = master
self.channel = channel
# Running?
self.running = False
# Current word
self.currentWord = None
# Current word, scrambled
self.scrambled = None
# Online?
self.scrambleOn = False
# Count down to hints
self.hintTimer = None
# of hints given
self.hintsGiven = 0
# Cooldown between words
self.nextTimer = None
# How many gamesWithoutGuesses submitted this round
self.guesses = 0
# How many games in a row where nobody guessed
self.gamesWithoutGuesses = 0
self.delayHint = self.master.config["hintDelay"]
self.delayNext = self.master.config["delayNext"]
self.maxHints = self.master.config["maxHints"]
self.abortAfterNoGuesses = self.master.config["abortAfterNoGuesses"]
def gameover(self):
self.clearTimers()
self.running = False
def clearTimers(self):
self.clearTimer(self.nextTimer)
self.clearTimer(self.hintTimer)
def clearTimer(self, timer):
if timer:
timer.cancel()
def scramble(self, args, prefix, trailing):
sender = prefix.nick
cmd = messageHasCommand(".scrambleon", trailing)
if cmd and not self.running:
self.running = True
self.startScramble()
return
cmd = messageHasCommand(".scrambleoff", trailing)
if cmd and self.running:
self.gameover()
self.running = False
return
cmd = messageHasCommand(".scramble top", trailing)
if cmd:
sortedscores = []
for player in self.master.scores:
sortedscores.append({'name': player, 'score': self.master.scores[player]})
sortedscores = sorted(sortedscores, key=itemgetter('score'))
sortedscores.reverse()
numScores = len(sortedscores)
if numScores > 3:
numScores = 3
resp = "Top %s: " % str(numScores)
which = 1
while which <= numScores:
resp += "%s: %s, " % (sortedscores[which - 1]["name"], sortedscores[which - 1]["score"])
which += 1
self.master.bot.act_PRIVMSG(self.channel, resp[:-2])
cmd = messageHasCommand(".scramble score", trailing)
if cmd:
someone = cmd.args.strip()
if len(someone) > 0:
self.master.bot.act_PRIVMSG(self.channel, "%s: %s has a score of %s" %
(sender, someone, self.master.getScoreNoWrite(someone)))
else:
self.master.bot.act_PRIVMSG(self.channel, "%s: %s" % (sender, self.master.getScore(sender)))
if self.currentWord and trailing.strip().lower() == self.currentWord:
playerScore = self.master.getScore(sender, 1)
self.master.bot.act_PRIVMSG(self.channel, "%s guessed the word - %s! %s now has %s points. Next word in %s "
"seconds." % (sender, self.currentWord, sender, playerScore, self.delayNext))
self.currentWord = None
self.clearTimers()
self.hintsGiven = 0
self.nextTimer = Timer(self.delayNext, self.startNewWord)
self.nextTimer.start()
self.guesses = 0
else:
self.guesses += 1
def startScramble(self):
self.clearTimer(self.nextTimer)
self.nextTimer = Timer(0, self.startNewWord)
self.nextTimer.start()
def startNewWord(self):
self.currentWord = self.pickWord()
self.master.log.info("Scramble: New word for %s: %s" % (self.channel, self.currentWord))
self.scrambled = self.scrambleWord(self.currentWord)
self.master.bot.act_PRIVMSG(self.channel, "New word - %s " % (self.scrambled))
self.clearTimer(self.hintTimer)
self.hintTimer = Timer(self.delayHint, self.giveHint)
self.hintTimer.start()
def giveHint(self):
self.hintsGiven += 1
if self.hintsGiven >= len(self.currentWord) or self.hintsGiven > self.maxHints:
self.abortWord()
return
blanks = ""
for letter in list(self.currentWord):
if letter == " ":
blanks += " "
else:
blanks += "_"
partFromWord = self.currentWord[0:self.hintsGiven]
partFromBlanks = blanks[self.hintsGiven:]
hintstr = partFromWord + partFromBlanks
self.master.bot.act_PRIVMSG(self.channel, "Hint: - %s" % (hintstr))
self.clearTimer(self.hintTimer)
self.hintTimer = Timer(self.delayHint, self.giveHint)
self.hintTimer.start()
def abortWord(self):
cur = self.currentWord
self.currentWord = None
self.master.bot.act_PRIVMSG(self.channel, "Word expired - the answer was %s. Next word in %s seconds." %
(cur, self.delayNext))
self.hintsGiven = 0
self.clearTimer(self.nextTimer)
if self.guesses == 0:
self.gamesWithoutGuesses += 1
if self.gamesWithoutGuesses >= self.abortAfterNoGuesses:
self.master.bot.act_PRIVMSG(self.channel, "No one seems to be playing - type .scrambleon to "
"start again.")
self.gameover()
return
else:
self.gamesWithoutGuesses = 0
self.nextTimer = Timer(self.delayNext, self.startNewWord)
self.nextTimer.start()
def pickWord(self):
f = open(self.master.wordsFile, "r")
skip = random.randint(0, self.master.wordsCount)
while skip >= 0:
f.readline()
skip -= 1
picked = f.readline().strip().lower()
f.close()
return picked
def scrambleWord(self, word):
scrambled = ""
for subword in word.split(" "):
scrambled += self.scrambleIndividualWord(subword) + " "
return scrambled.strip()
def scrambleIndividualWord(self, word):
scrambled = list(word)
random.shuffle(scrambled)
return ''.join(scrambled).lower()