Trivia: enhance code, and testStartStop()
parent
957a5532b3
commit
4f04c5cc13
|
@ -1,5 +1,6 @@
|
|||
###
|
||||
# Copyright (c) 2010, quantumlemur
|
||||
# Copyright (c) 2011, Valentin Lorentz
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
|
@ -46,36 +47,47 @@ Trivia = conf.registerPlugin('Trivia')
|
|||
# registry.Boolean(False, """Help for someConfigVariableName."""))
|
||||
|
||||
conf.registerChannelValue(Trivia, 'blankChar',
|
||||
registry.String('*', """The character used for a blank when displaying hints"""))
|
||||
registry.String('*', """The character used for a blank when
|
||||
displaying hints"""))
|
||||
|
||||
conf.registerChannelValue(Trivia, 'numHints',
|
||||
registry.PositiveInteger(3, """The number of hints to be given for each question"""))
|
||||
registry.PositiveInteger(3, """The number of hints to be given for
|
||||
each question"""))
|
||||
|
||||
conf.registerChannelValue(Trivia, 'timeout',
|
||||
registry.PositiveInteger(90, """The number of seconds to allow for each question"""))
|
||||
registry.PositiveInteger(90, """The number of seconds to allow for
|
||||
each question"""))
|
||||
|
||||
conf.registerChannelValue(Trivia, 'hintPercentage',
|
||||
registry.Probability(0.25, """The fraction of the answer that should be revealed with each hint"""))
|
||||
registry.Probability(0.25, """The fraction of the answer that
|
||||
should be revealed with each hint"""))
|
||||
|
||||
conf.registerChannelValue(Trivia, 'flexibility',
|
||||
registry.PositiveInteger(8, """The flexibility of the trivia answer checker. One typo will be allowed for every __ characters."""))
|
||||
registry.PositiveInteger(8, """The flexibility of the trivia answer
|
||||
checker. One typo will be allowed for every __ characters."""))
|
||||
|
||||
conf.registerChannelValue(Trivia, 'color',
|
||||
registry.PositiveInteger(10, """The mIRC color to use for trivia questions"""))
|
||||
registry.PositiveInteger(10, """The mIRC color to use for trivia
|
||||
questions"""))
|
||||
|
||||
conf.registerChannelValue(Trivia, 'inactiveShutoff',
|
||||
registry.Integer(6, """The number of questions that can go unanswered before the trivia stops automatically."""))
|
||||
registry.Integer(6, """The number of questions that can go
|
||||
unanswered before the trivia stops automatically."""))
|
||||
|
||||
conf.registerGlobalValue(Trivia, 'scoreFile',
|
||||
registry.String('scores.txt', """The path to the scores file. If it doesn't exist, it will be created."""))
|
||||
registry.String('scores.txt', """The path to the scores file.
|
||||
If it doesn't exist, it will be created."""))
|
||||
|
||||
conf.registerGlobalValue(Trivia, 'questionFile',
|
||||
registry.String('questions.txt', """The path to the questions file. If it doesn't exist, it will be created."""))
|
||||
registry.String('questions.txt', """The path to the questions file.
|
||||
If it doesn't exist, it will be created."""))
|
||||
|
||||
conf.registerChannelValue(Trivia, 'defaultRoundLength',
|
||||
registry.PositiveInteger(10, """The default number of questions to be asked in a round of trivia."""))
|
||||
registry.PositiveInteger(10, """The default number of questions to
|
||||
be asked in a round of trivia."""))
|
||||
|
||||
conf.registerGlobalValue(Trivia, 'questionFileSeparator',
|
||||
registry.String('*', """The separator used between the questions and answers in your trivia file."""))
|
||||
registry.String('*', """The separator used between the questions
|
||||
and answers in your trivia file."""))
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
###
|
||||
# Copyright (c) 2010, quantumlemur
|
||||
# Copyright (c) 2011, Valentin Lorentz
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
|
@ -58,7 +59,11 @@ class Trivia(callbacks.Plugin):
|
|||
questionfile = self.registryValue('questionFile')
|
||||
if not os.path.exists(questionfile):
|
||||
f = open(questionfile, 'w')
|
||||
f.write('If you\'re seeing this question, it means that the questions file that you specified wasn\'t found, and a new one has been created. Go get some questions!%sNo questions found' % self.registryValue('questionFileSeparator'))
|
||||
f.write(('If you\'re seeing this question, it means that the '
|
||||
'questions file that you specified wasn\'t found, and '
|
||||
'a new one has been created. Go get some questions!%s'
|
||||
'No questions found') %
|
||||
self.registryValue('questionFileSeparator'))
|
||||
f.close()
|
||||
self.scorefile = self.registryValue('scoreFile')
|
||||
if not os.path.exists(self.scorefile):
|
||||
|
@ -84,18 +89,18 @@ class Trivia(callbacks.Plugin):
|
|||
|
||||
|
||||
class Game:
|
||||
def __init__(self, irc, channel, num, registryValue, games, scores, scorefile):
|
||||
def __init__(self, irc, channel, num, plugin):
|
||||
self.rng = random.Random()
|
||||
self.rng.seed()
|
||||
self.registryValue = registryValue
|
||||
self.registryValue = plugin.registryValue
|
||||
self.irc = irc
|
||||
self.channel = channel
|
||||
self.num = num
|
||||
self.numAsked = 0
|
||||
self.hints = 0
|
||||
self.games = games
|
||||
self.scores = scores
|
||||
self.scorefile = scorefile
|
||||
self.games = plugin.games
|
||||
self.scores = plugin.scores
|
||||
self.scorefile = plugin.scorefile
|
||||
self.questionfile = self.registryValue('questionFile')
|
||||
self.total = num
|
||||
self.active = True
|
||||
|
@ -116,9 +121,11 @@ class Trivia(callbacks.Plugin):
|
|||
|
||||
|
||||
def newquestion(self):
|
||||
inactiveShutoff = self.registryValue('inactiveShutoff',
|
||||
self.channel)
|
||||
if self.num == 0:
|
||||
self.active = False
|
||||
elif self.unanswered > self.registryValue('inactiveShutoff', self.channel) and self.registryValue('inactiveShutoff', self.channel) >= 0:
|
||||
elif self.unanswered > inactiveShutoff and inactiveShutoff >= 0:
|
||||
self.reply('Seems like no one\'s playing any more.')
|
||||
self.active = False
|
||||
elif len(self.questions) == 0:
|
||||
|
@ -135,10 +142,14 @@ class Trivia(callbacks.Plugin):
|
|||
sep = self.registryValue('questionFileSeparator')
|
||||
self.q = q[:q.find(sep)]
|
||||
self.a = q[q.find(sep)+len(sep):].split(sep)
|
||||
self.reply('\x03%s#%d of %d: %s' % (self.registryValue('color', self.channel), self.numAsked, self.total, self.q))
|
||||
color = self.registryValue('color', self.channel)
|
||||
self.reply('\x03%s#%d of %d: %s' % (color, self.numAsked,
|
||||
self.total, self.q))
|
||||
def event():
|
||||
self.timedEvent()
|
||||
eventTime = time.time() + self.registryValue('timeout', self.channel) / (self.registryValue('numHints', self.channel) + 1)
|
||||
timeout = self.registryValue('timeout', self.channel)
|
||||
numHints = self.registryValue('numHints', self.channel)
|
||||
eventTime = time.time() + timeout / (numHints + 1)
|
||||
if self.active:
|
||||
schedule.addEvent(event, eventTime, 'next_%s' % self.channel)
|
||||
|
||||
|
@ -161,7 +172,7 @@ class Trivia(callbacks.Plugin):
|
|||
max = 3
|
||||
if len(sorted) < max:
|
||||
max = len(sorted)
|
||||
# self.reply('max: %d. len: %d' % (max, len(sorted)))
|
||||
#self.reply('max: %d. len: %d' % (max, len(sorted)))
|
||||
s = 'Top finishers: '
|
||||
if max > 0:
|
||||
recipients = []
|
||||
|
@ -185,16 +196,20 @@ class Trivia(callbacks.Plugin):
|
|||
def hint(self):
|
||||
self.hints += 1
|
||||
ans = self.a[0]
|
||||
divider = int( math.ceil( len(ans) * self.registryValue('hintPercentage', self.channel) * self.hints ) )
|
||||
hintPercentage = self.registryValue('hintPercentage', self.channel)
|
||||
divider = int(math.ceil(len(ans) * hintPercentage * self.hints ))
|
||||
if divider == len(ans):
|
||||
divider -= 1
|
||||
show = ans[ : divider]
|
||||
blank = ans[divider : ]
|
||||
blank = re.sub('\w', self.registryValue('blankChar', self.channel), blank)
|
||||
blankChar = self.registryValue('blankChar', self.channel)
|
||||
blank = re.sub('\w', blankChar, blank)
|
||||
self.reply('HINT: %s%s' % (show, blank))
|
||||
def event():
|
||||
self.timedEvent()
|
||||
eventTime = time.time() + self.registryValue('timeout', self.channel) / (self.registryValue('numHints', self.channel)+1)
|
||||
timeout = self.registryValue('timeout', self.channel)
|
||||
numHints = self.registryValue('numHints', self.channel)
|
||||
eventTime = time.time() + timeout / (numHints + 1)
|
||||
if self.active:
|
||||
schedule.addEvent(event, eventTime, 'next_%s' % self.channel)
|
||||
|
||||
|
@ -203,10 +218,11 @@ class Trivia(callbacks.Plugin):
|
|||
correct = False
|
||||
for ans in self.a:
|
||||
dist = self.DL(str.lower(msg.args[1]), str.lower(ans))
|
||||
if dist <= len(ans)/self.registryValue('flexibility', self.channel):
|
||||
flexibility = self.registryValue('flexibility', self.channel)
|
||||
if dist <= len(ans) / flexibility:
|
||||
correct = True
|
||||
# if self.registryValue('debug'):
|
||||
# self.reply('Distance: %d' % dist)
|
||||
#if self.registryValue('debug'):
|
||||
# self.reply('Distance: %d' % dist)
|
||||
if correct:
|
||||
if not msg.nick in self.scores:
|
||||
self.scores[msg.nick] = 0
|
||||
|
@ -215,7 +231,8 @@ class Trivia(callbacks.Plugin):
|
|||
self.roundscores[msg.nick] = 0
|
||||
self.roundscores[msg.nick] += 1
|
||||
self.unanswered = 0
|
||||
self.reply('%s got it! The full answer was: %s. Points: %d' % (msg.nick, self.a[0], self.scores[msg.nick]))
|
||||
self.reply('%s got it! The full answer was: %s. Points: %d' %
|
||||
(msg.nick, self.a[0], self.scores[msg.nick]))
|
||||
schedule.removeEvent('next_%s' % self.channel)
|
||||
self.writeScores()
|
||||
self.newquestion()
|
||||
|
@ -241,27 +258,30 @@ class Trivia(callbacks.Plugin):
|
|||
# Python lists wrap around for negative indices, so put the
|
||||
# leftmost column at the *end* of the list. This matches with
|
||||
# the zero-indexed strings and saves extra calculation.
|
||||
twoago, oneago, thisrow = oneago, thisrow, [0] * len(seq2) + [x + 1]
|
||||
twoago, oneago, thisrow = oneago, thisrow, [0]*len(seq2)+[x+1]
|
||||
for y in xrange(len(seq2)):
|
||||
delcost = oneago[y] + 1
|
||||
addcost = thisrow[y - 1] + 1
|
||||
subcost = oneago[y - 1] + (seq1[x] != seq2[y])
|
||||
thisrow[y] = min(delcost, addcost, subcost)
|
||||
# This block deals with transpositions
|
||||
if (x > 0 and y > 0 and seq1[x] == seq2[y - 1] and seq1[x-1] == seq2[y] and seq1[x] != seq2[y]):
|
||||
if x > 0 and y > 0 and seq1[x] == seq2[y - 1] and \
|
||||
seq1[x-1] == seq2[y] and seq1[x] != seq2[y]:
|
||||
thisrow[y] = min(thisrow[y], twoago[y - 2] + 1)
|
||||
return thisrow[len(seq2) - 1]
|
||||
|
||||
|
||||
def trivia(self, irc, msg, args, channel, num):
|
||||
def start(self, irc, msg, args, channel, num):
|
||||
"""[<channel>] [<number of questions>]
|
||||
|
||||
Starts a game of trivia. <channel> is only necessary if the message isn't sent in the channel itself."""
|
||||
Starts a game of trivia. <channel> is only necessary if the message
|
||||
isn't sent in the channel itself."""
|
||||
if num == None:
|
||||
num = self.registryValue('defaultRoundLength', channel)
|
||||
# elif num > 100:
|
||||
# irc.reply('sorry, for now, you can\'t start games with more than 100 questions :(')
|
||||
# num = 100
|
||||
#elif num > 100:
|
||||
# irc.reply('sorry, for now, you can\'t start games with more '
|
||||
# 'than 100 questions :(')
|
||||
# num = 100
|
||||
channel = ircutils.toLower(channel)
|
||||
if channel in self.games:
|
||||
if not self.games[channel].active:
|
||||
|
@ -276,20 +296,21 @@ class Trivia(callbacks.Plugin):
|
|||
self.games[channel].total += num
|
||||
irc.reply('%d questions added to active game!' % num)
|
||||
else:
|
||||
self.games[channel] = self.Game(irc, channel, num, self.registryValue, self.games, self.scores, self.scorefile)
|
||||
self.games[channel] = self.Game(irc, channel, num, self)
|
||||
irc.noReply()
|
||||
trivia = wrap(trivia, ['channel', optional('positiveInt')])
|
||||
start = wrap(start, ['channel', optional('positiveInt')])
|
||||
|
||||
|
||||
def strivia(self, irc, msg, args, channel):
|
||||
def stop(self, irc, msg, args, channel):
|
||||
"""[<channel>]
|
||||
|
||||
Stops a running game of trivia. <channel> is only necessary if the message isn't sent in the channel itself."""
|
||||
Stops a running game of trivia. <channel> is only necessary if the
|
||||
message isn't sent in the channel itself."""
|
||||
channel = ircutils.toLower(channel)
|
||||
try:
|
||||
schedule.removeEvent('next_%s' % channel)
|
||||
except KeyError:
|
||||
pass
|
||||
irc.error('No trivia started')
|
||||
if channel in self.games:
|
||||
if self.games[channel].active:
|
||||
self.games[channel].stop()
|
||||
|
@ -298,7 +319,7 @@ class Trivia(callbacks.Plugin):
|
|||
irc.reply('Trivia stopped')
|
||||
else:
|
||||
irc.noReply()
|
||||
strivia = wrap(strivia, ['channel'])
|
||||
stop = wrap(stop, ['channel'])
|
||||
|
||||
|
||||
Class = Trivia
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
###
|
||||
# Copyright (c) 2010, quantumlemur
|
||||
# Copyright (c) 2011, Valentin Lorentz
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
|
@ -30,8 +30,13 @@
|
|||
|
||||
from supybot.test import *
|
||||
|
||||
class TriviaTestCase(PluginTestCase):
|
||||
class TriviaTestCase(ChannelPluginTestCase):
|
||||
plugins = ('Trivia',)
|
||||
|
||||
def testStartStop(self):
|
||||
self.assertRegexp('start', '...#1 of 10:.*')
|
||||
self.assertResponse('stop', 'Trivia stopping.')
|
||||
self.assertError('stop')
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
|
||||
|
|
Loading…
Reference in New Issue