2014-10-02 14:48:59 -07:00
"""
. . module : : Scramble
: synopsis : Module to provide a word scramble game
. . moduleauthor : : Dave Pedu < dave @davepedu.com >
"""
2015-06-18 19:37:08 -07:00
from pyircbot . modulebase import ModuleBase , ModuleHook
2013-12-28 09:58:20 -08:00
import random
import yaml
import os
import time
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 ) ;
self . hooks = [ ModuleHook ( " PRIVMSG " , self . scramble ) ]
self . loadConfig ( )
# Dictionary
self . wordsCount = 0 ;
2014-10-02 14:48:59 -07:00
self . wordsFile = self . getFilePath ( " words.txt " )
2013-12-28 09:58:20 -08:00
print ( self . wordsFile )
wordsF = open ( self . wordsFile , " r " )
while True :
word = wordsF . readline ( )
if word == " " :
break
self . wordsCount + = 1
wordsF . close
self . log . info ( " Scramble: Loaded %s words " % str ( self . wordsCount ) )
# Load scores
self . scoresFile = self . getFilePath ( " scores.yml " )
if not os . path . exists ( self . scoresFile ) :
yaml . dump ( { } , file ( self . scoresFile , ' w ' ) )
self . scores = yaml . load ( file ( self . scoresFile , ' r ' ) )
# Per channel games
self . games = { }
# Hook in
self . hooks = [ ModuleBase . ModuleHook ( " PRIVMSG " , self . scramble ) ]
def scramble ( self , args , prefix , trailing ) :
channel = args [ 0 ]
if channel [ 0 ] == " # " :
if not channel in self . games :
self . games [ channel ] = scrambleGame ( self , channel )
self . games [ channel ] . scramble ( args , prefix , trailing )
def saveScores ( self ) :
yaml . dump ( self . scores , file ( self . scoresFile , ' w ' ) )
def getScore ( self , player , add = 0 ) :
player = player . lower ( )
if not player 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 guesses 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 ) :
prefix = self . master . bot . decodePrefix ( prefix )
sender = prefix . nick
cmd = self . master . bot . messageHasCommand ( " .scrambleon " , trailing )
if cmd and not self . running :
self . running = True
self . startScramble ( )
return
cmd = self . master . bot . messageHasCommand ( " .scrambleoff " , trailing )
if cmd and self . running :
self . gameover ( )
self . running = False
return
cmd = self . master . bot . 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 = self . master . bot . 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 ( )