Add 'Jeopardy/' from commit '0fc85014d136671257180831029710c82b778307'

git-subtree-dir: Jeopardy
git-subtree-mainline: d26ffc2e84
git-subtree-split: 0fc85014d1
This commit is contained in:
oddluck 2019-03-01 01:43:27 -05:00
commit d75fec8cce
9 changed files with 1028 additions and 0 deletions

1
Jeopardy/README.md Normal file
View File

@ -0,0 +1 @@
Insert a description of your plugin here, with any notes, etc. about using it.

71
Jeopardy/__init__.py Normal file
View File

@ -0,0 +1,71 @@
###
# Copyright (c) 2010, quantumlemur
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions, and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions, and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the author of this software nor the name of
# contributors to this software may be used to endorse or promote products
# derived from this software without specific prior written consent.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
###
"""
Add a description of the plugin (to be presented to the user inside the wizard)
here. This should describe *what* the plugin does.
"""
import supybot
import supybot.world as world
# Use this for the version of this plugin. You may wish to put a CVS keyword
# in here if you're keeping the plugin in CVS or some similar system.
__version__ = "1.0"
# XXX Replace this with an appropriate author or supybot.Author instance.
__author__ = supybot.Author('quantumlemur', 'quantumlemur',
'quantumlemur@users.sourceforge.net')
# This is a dictionary mapping supybot.Author instances to lists of
# contributions.
if not hasattr(supybot.authors, 'progval'):
supybot.authors.progval = supybot.Author('Valentin Lorentz', 'ProgVal',
'progval@gmail.com')
__contributors__ = {supybot.authors.progval: ['code enhancement']}
# This is a url where the most recent plugin package can be downloaded.
__url__ = '' # 'http://supybot.com/Members/yourname/Trivia/download'
from . import config
from . import plugin
from imp import reload
reload(plugin) # In case we're being reloaded.
# Add more reloads here if you add third-party modules and want them to be
# reloaded when this plugin is reloaded. Don't forget to import them as well!
if world.testing:
from . import test
Class = plugin.Class
configure = config.configure
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:

98
Jeopardy/config.py Normal file
View File

@ -0,0 +1,98 @@
###
# Copyright (c) 2010, quantumlemur
# Copyright (c) 2011, Valentin Lorentz
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions, and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions, and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the author of this software nor the name of
# contributors to this software may be used to endorse or promote products
# derived from this software without specific prior written consent.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
###
import supybot.conf as conf
import supybot.registry as registry
from supybot.i18n import PluginInternationalization, internationalizeDocstring
_ = PluginInternationalization('Trivia')
def configure(advanced):
# This will be called by supybot to configure this module. advanced is
# a bool that specifies whether the user identified himself as an advanced
# user or not. You should effect your configuration by manipulating the
# registry as appropriate.
from supybot.questions import expect, anything, something, yn
conf.registerPlugin('Trivia', True)
Trivia = conf.registerPlugin('Trivia')
# This is where your configuration variables (if any) should go. For example:
# conf.registerGlobalValue(Trivia, 'someConfigVariableName',
# registry.Boolean(False, """Help for someConfigVariableName."""))
conf.registerChannelValue(Trivia, 'blankChar',
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""")))
conf.registerChannelValue(Trivia, 'timeout',
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""")))
conf.registerChannelValue(Trivia, 'flexibility',
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""")))
conf.registerChannelValue(Trivia, 'inactiveShutoff',
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.""")))
conf.registerGlobalValue(Trivia, 'questionFile',
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.""")))
conf.registerGlobalValue(Trivia, 'questionFileSeparator',
registry.String('*', _("""The separator used between the questions
and answers in your trivia file.""")))
conf.registerChannelValue(Trivia, 'randomize',
registry.Boolean('True', _("""This will determine whether or not the
bot will randomize the trivia questions.""")))
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:

View File

@ -0,0 +1 @@
# Stub so local is a module, used for third-party modules

162
Jeopardy/locales/de.po Normal file
View File

@ -0,0 +1,162 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: Supybot\n"
"POT-Creation-Date: 2011-11-01 19:21+CET\n"
"PO-Revision-Date: 2011-11-01 19:37+0100\n"
"Last-Translator: Florian Besser <fbesser@gmail.com>\n"
"Language-Team: German <fbesser@gmail.com>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
#: config.py:51
msgid ""
"The character used for a blank when\n"
" displaying hints"
msgstr "Das Zeichen das als blankes Zeichen bei Tipps benutzt wird."
#: config.py:55
msgid ""
"The number of hints to be given for\n"
" each question"
msgstr "Die Nummer der Tipps die pro Frage gegeben werden."
#: config.py:59
msgid ""
"The number of seconds to allow for\n"
" each question"
msgstr "Die Anzahl der Sekunden für jede Frage."
#: config.py:63
msgid ""
"The fraction of the answer that\n"
" should be revealed with each hint"
msgstr "Der Anteil der Frage die mit jedem Tipp preisgegeben wird."
#: config.py:67
msgid ""
"The flexibility of the trivia answer\n"
" checker. One typo will be allowed for every __ characters."
msgstr "Die Flexibilität des Fragencheckers. Ein Fehler wird alle __ Zeichen erlaubt."
#: config.py:71
msgid ""
"The mIRC color to use for trivia\n"
" questions"
msgstr "Die mIRC Frage für Quizfragen."
#: config.py:75
msgid ""
"The number of questions that can go\n"
" unanswered before the trivia stops automatically."
msgstr "Die Anzahl der Fragen die unbeantwortet bleiben können, bevor das Quiz automatisch stoppt."
#: config.py:79
msgid ""
"The path to the scores file.\n"
" If it doesn't exist, it will be created."
msgstr "Der Pfad zur Punktedatei. Falls diese nicht existiert wird sie erstellt."
#: config.py:83
msgid ""
"The path to the questions file.\n"
" If it doesn't exist, it will be created."
msgstr "Der Pfad zur Fragendatei. Falls diese nicht existiert wird sie erstellt."
#: config.py:87
msgid ""
"The default number of questions to\n"
" be asked in a round of trivia."
msgstr "Die Standardanzahl an Fragen die in einer Quizrunde gestellt werden."
#: config.py:91
msgid ""
"The separator used between the questions\n"
" and answers in your trivia file."
msgstr "Der Seperator zwischen Fragen und Antworten in deiner Triviadatei."
#: plugin.py:50
msgid ""
"Add the help for \"@plugin help Trivia\" here\n"
" This should describe *how* to use this plugin."
msgstr ""
#: plugin.py:130
msgid "Seems like no one's playing any more."
msgstr "Ich glaube es spielt niemand mehr."
#: plugin.py:133
msgid "Oops! I ran out of questions!"
msgstr "Ups! Ich habe keine Fragen mehr!"
#: plugin.py:147
msgid "%s#%d of %d: %s"
msgstr "%s#%d aus %d: %s"
#: plugin.py:159
msgid "Trivia stopping."
msgstr "Quiz wird gestoppt."
#: plugin.py:177
msgid "Top finishers: "
msgstr "Top Spieler: "
#: plugin.py:183
msgid "%s %s %s."
msgstr "%s %s %s."
#: plugin.py:190
msgid "No one got the answer! It was: %s"
msgstr "Niemand hatte die Antwort! Die Antwort war: %s"
#: plugin.py:208
msgid "HINT: %s%s"
msgstr "Tipp: %s%s"
#: plugin.py:235
msgid "%s got it! The full answer was: %s. Points: %d"
msgstr "%s hat es richtig! Die volle Antwort war: %s. Punkte: %d"
#: plugin.py:276
msgid ""
"[<channel>] [<number of questions>]\n"
"\n"
" Starts a game of trivia. <channel> is only necessary if the message\n"
" isn't sent in the channel itself."
msgstr ""
"[<Kanal>] [<Anzahl der Fragen>]\n"
"\n"
"Startet ein neues Quiz. <Kanal> wird nur benötigt falls der Befehl nicht im Kanal gegeben wird."
#: plugin.py:294
msgid "Orphaned trivia game found and removed."
msgstr "Verwaistes Quiz gefunden und entfernt."
#: plugin.py:298
msgid "%d questions added to active game!"
msgstr "%d Fragen zum aktiven Spiel hinzugefügt!"
#: plugin.py:306
msgid ""
"[<channel>]\n"
"\n"
" Stops a running game of trivia. <channel> is only necessary if the\n"
" message isn't sent in the channel itself."
msgstr ""
"[<Kanal>]\n"
"\n"
"Stoppt das laufende Quiz. <Kanal> wird nur benötigt falls der Befehl nicht im Kanal gegeben wird."
#: plugin.py:314
msgid "No trivia started"
msgstr "Es läuft kein Quiz."
#: plugin.py:320
msgid "Trivia stopped"
msgstr "Quiz gestoppt"

164
Jeopardy/locales/it.po Normal file
View File

@ -0,0 +1,164 @@
msgid ""
msgstr ""
"Project-Id-Version: Supybot-fr\n"
"POT-Creation-Date: 2011-11-01 19:21+CET\n"
"PO-Revision-Date: 2011-11-07 14:45+0100\n"
"Last-Translator: skizzhg <skizzhg@gmx.com>\n"
"Language-Team: Italian <skizzhg@gmx.com>\n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: config.py:51
msgid ""
"The character used for a blank when\n"
" displaying hints"
msgstr "Il carattere usato per lo spazio vuoto quando vengono visualizzati i suggerimenti."
#: config.py:55
msgid ""
"The number of hints to be given for\n"
" each question"
msgstr "Il numero di suggerimenti da fornire per ogni domanda."
#: config.py:59
msgid ""
"The number of seconds to allow for\n"
" each question"
msgstr "Il numero di secondi permessi per ogni domanda."
#: config.py:63
msgid ""
"The fraction of the answer that\n"
" should be revealed with each hint"
msgstr "La porzione della risposta rivelata da ogni suggerimento."
#: config.py:67
msgid ""
"The flexibility of the trivia answer\n"
" checker. One typo will be allowed for every __ characters."
msgstr "La flessibilità del controllore delle risposte, sarà consentito un errore di battitura ogni __ caratteri."
#: config.py:71
msgid ""
"The mIRC color to use for trivia\n"
" questions"
msgstr "Il colore mIRC da utilizzare per le domande del trivia."
#: config.py:75
msgid ""
"The number of questions that can go\n"
" unanswered before the trivia stops automatically."
msgstr "Il numero di domande che possono rimanere senza risposta prima che il trivia si fermi automaticamente."
#: config.py:79
msgid ""
"The path to the scores file.\n"
" If it doesn't exist, it will be created."
msgstr "Il percorso del file dei punteggi, se non esiste verrà creato."
#: config.py:83
msgid ""
"The path to the questions file.\n"
" If it doesn't exist, it will be created."
msgstr "Il percorso del file delle domande, se non esiste verrà creato."
#: config.py:87
msgid ""
"The default number of questions to\n"
" be asked in a round of trivia."
msgstr "Il numero predefinito di domande da porre in una partita di trivia."
#: config.py:91
msgid ""
"The separator used between the questions\n"
" and answers in your trivia file."
msgstr "Il separatore usato tra le domande e le risposte nel file del trivia."
#: plugin.py:50
#, docstring
msgid ""
"Add the help for \"@plugin help Trivia\" here\n"
" This should describe *how* to use this plugin."
msgstr ""
#: plugin.py:130
msgid "Seems like no one's playing any more."
msgstr "Sembra che nessuno stia più giocando."
#: plugin.py:133
msgid "Oops! I ran out of questions!"
msgstr "Oops! Ho finito le domande!"
#: plugin.py:147
msgid "\003%s#%d of %d: %s"
msgstr "\003%s#%d di %d: %s"
#: plugin.py:159
msgid "Trivia stopping."
msgstr "Trivia fermato."
#: plugin.py:177
msgid "Top finishers: "
msgstr "Primi classificati: "
#: plugin.py:183
msgid "%s %s %s."
msgstr "%s %s %s."
#: plugin.py:190
msgid "No one got the answer! It was: %s"
msgstr "Nessuno ha la risposta! Era: %s"
#: plugin.py:208
msgid "HINT: %s%s"
msgstr "Suggerimento: %s%s"
#: plugin.py:235
msgid "%s got it! The full answer was: %s. Points: %d"
msgstr "%s ha indovinato! La risposta intera era: %s. Punti: %d"
#: plugin.py:276
#, docstring
msgid ""
"[<channel>] [<number of questions>]\n"
"\n"
" Starts a game of trivia. <channel> is only necessary if the message\n"
" isn't sent in the channel itself."
msgstr ""
"[<canale>] [<numero di domande>]\n"
"\n"
" Inizia una partita di trivia. <canale> è necessario solo se il messaggio\n"
" non viene inviato nel canale stesso."
#: plugin.py:294
msgid "Orphaned trivia game found and removed."
msgstr "Trovata e rimossa una partita di trivia abbandonata."
#: plugin.py:298
msgid "%d questions added to active game!"
msgstr "%d domande aggiunte al gioco in corso!"
#: plugin.py:306
#, docstring
msgid ""
"[<channel>]\n"
"\n"
" Stops a running game of trivia. <channel> is only necessary if the\n"
" message isn't sent in the channel itself."
msgstr ""
"[<canale>]\n"
"\n"
" Interrompe una partita di trivia in corso. <canale> è necessario solo se\n"
" il messaggio non viene inviato nel canale stesso."
#: plugin.py:314
msgid "No trivia started"
msgstr "Nessun trivia avviato."
#: plugin.py:320
msgid "Trivia stopped"
msgstr "Trivia fermato."

160
Jeopardy/messages.pot Normal file
View File

@ -0,0 +1,160 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2011-11-01 19:21+CET\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: ENCODING\n"
"Generated-By: pygettext.py 1.5\n"
#: config.py:51
msgid ""
"The character used for a blank when\n"
" displaying hints"
msgstr ""
#: config.py:55
msgid ""
"The number of hints to be given for\n"
" each question"
msgstr ""
#: config.py:59
msgid ""
"The number of seconds to allow for\n"
" each question"
msgstr ""
#: config.py:63
msgid ""
"The fraction of the answer that\n"
" should be revealed with each hint"
msgstr ""
#: config.py:67
msgid ""
"The flexibility of the trivia answer\n"
" checker. One typo will be allowed for every __ characters."
msgstr ""
#: config.py:71
msgid ""
"The mIRC color to use for trivia\n"
" questions"
msgstr ""
#: config.py:75
msgid ""
"The number of questions that can go\n"
" unanswered before the trivia stops automatically."
msgstr ""
#: config.py:79
msgid ""
"The path to the scores file.\n"
" If it doesn't exist, it will be created."
msgstr ""
#: config.py:83
msgid ""
"The path to the questions file.\n"
" If it doesn't exist, it will be created."
msgstr ""
#: config.py:87
msgid ""
"The default number of questions to\n"
" be asked in a round of trivia."
msgstr ""
#: config.py:91
msgid ""
"The separator used between the questions\n"
" and answers in your trivia file."
msgstr ""
#: plugin.py:50
#, docstring
msgid ""
"Add the help for \"@plugin help Trivia\" here\n"
" This should describe *how* to use this plugin."
msgstr ""
#: plugin.py:130
msgid "Seems like no one's playing any more."
msgstr ""
#: plugin.py:133
msgid "Oops! I ran out of questions!"
msgstr ""
#: plugin.py:147
msgid "\003%s#%d of %d: %s"
msgstr ""
#: plugin.py:159
msgid "Trivia stopping."
msgstr ""
#: plugin.py:177
msgid "Top finishers: "
msgstr ""
#: plugin.py:183
msgid "%s %s %s."
msgstr ""
#: plugin.py:190
msgid "No one got the answer! It was: %s"
msgstr ""
#: plugin.py:208
msgid "HINT: %s%s"
msgstr ""
#: plugin.py:235
msgid "%s got it! The full answer was: %s. Points: %d"
msgstr ""
#: plugin.py:276
#, docstring
msgid ""
"[<channel>] [<number of questions>]\n"
"\n"
" Starts a game of trivia. <channel> is only necessary if the message\n"
" isn't sent in the channel itself."
msgstr ""
#: plugin.py:294
msgid "Orphaned trivia game found and removed."
msgstr ""
#: plugin.py:298
msgid "%d questions added to active game!"
msgstr ""
#: plugin.py:306
#, docstring
msgid ""
"[<channel>]\n"
"\n"
" Stops a running game of trivia. <channel> is only necessary if the\n"
" message isn't sent in the channel itself."
msgstr ""
#: plugin.py:314
msgid "No trivia started"
msgstr ""
#: plugin.py:320
msgid "Trivia stopped"
msgstr ""

329
Jeopardy/plugin.py Normal file
View File

@ -0,0 +1,329 @@
###
# Copyright (c) 2010, quantumlemur
# Copyright (c) 2011, Valentin Lorentz
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions, and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions, and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the author of this software nor the name of
# contributors to this software may be used to endorse or promote products
# derived from this software without specific prior written consent.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
###
import re
import os
import time
import math
import string
import random
import supybot.utils as utils
import supybot.ircdb as ircdb
from supybot.commands import *
import supybot.plugins as plugins
import supybot.ircmsgs as ircmsgs
import supybot.ircutils as ircutils
import supybot.schedule as schedule
import supybot.callbacks as callbacks
from supybot.i18n import PluginInternationalization, internationalizeDocstring
_ = PluginInternationalization('Trivia')
class Trivia(callbacks.Plugin):
"""Add the help for "@plugin help Trivia" here
This should describe *how* to use this plugin."""
threaded = True
def __init__(self, irc):
self.__parent = super(Trivia, self)
self.__parent.__init__(irc)
self.games = {}
self.scores = {}
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!%s'
'No questions found') %
self.registryValue('questionFileSeparator'))
f.close()
self.scorefile = self.registryValue('scoreFile')
if not os.path.exists(self.scorefile):
f = open(self.scorefile, 'w')
f.close()
f = open(self.scorefile, 'r')
line = f.readline()
while line:
(name, score) = line.split(' ')
self.scores[name] = int(score.strip('\r\n'))
line = f.readline()
f.close()
def doPrivmsg(self, irc, msg):
channel = ircutils.toLower(msg.args[0])
if not irc.isChannel(channel):
return
if callbacks.addressed(irc.nick, msg):
return
if channel in self.games:
self.games[channel].answer(msg)
class Game:
def __init__(self, irc, channel, num, plugin):
self.rng = random.Random()
self.rng.seed()
self.registryValue = plugin.registryValue
self.irc = irc
self.channel = channel
self.num = num
self.numAsked = 0
self.hints = 0
self.games = plugin.games
self.scores = plugin.scores
self.scorefile = plugin.scorefile
self.questionfile = self.registryValue('questionFile')
self.total = num
self.active = True
self.questions = []
self.roundscores = {}
self.unanswered = 0
f = open(self.questionfile, 'r')
line = f.readline()
while line:
self.questions.append(line.strip('\n\r'))
line = f.readline()
f.close()
if self.registryValue('randomize', channel): random.shuffle(self.questions)
try:
schedule.removeEvent('next_%s' % self.channel)
except KeyError:
pass
self.newquestion()
def newquestion(self):
inactiveShutoff = self.registryValue('inactiveShutoff',
self.channel)
if self.num == 0:
self.active = False
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:
self.reply(_('Oops! I ran out of questions!'))
self.active = False
if not self.active:
self.stop()
return
self.hints = 0
self.num -= 1
self.numAsked += 1
q = self.questions.pop(len(self.questions)-1)
sep = self.registryValue('questionFileSeparator')
self.q = q[:q.find(sep)]
self.a = q[q.find(sep)+len(sep):].split(sep)
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()
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)
def stop(self):
self.reply(_('Trivia stopping.'))
self.active = False
try:
schedule.removeEvent('next_%s' % self.channel)
except KeyError:
pass
scores = iter(self.roundscores.items())
sorted = []
for i in range(0, len(self.roundscores)):
item = next(scores)
sorted.append(item)
def cmp(a, b):
return b[1] - a[1]
sorted.sort(key=lambda item: item[1], reverse=True)
max = 3
if len(sorted) < max:
max = len(sorted)
#self.reply('max: %d. len: %d' % (max, len(sorted)))
s = _('Top finishers: ')
if max > 0:
recipients = []
maxp = sorted[0][1]
for i in range(0, max):
item = sorted[i]
s = _('%s %s %s.') % (s, item[0], item[1])
self.reply(s)
del self.games[self.channel]
def timedEvent(self):
if self.hints >= self.registryValue('numHints', self.channel):
self.reply(_('No one got the answer! It was: %s') % self.a[0])
self.unanswered += 1
self.newquestion()
else:
self.hint()
def hint(self):
self.hints += 1
ans = self.a[0]
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 : ]
blankChar = self.registryValue('blankChar', self.channel)
blank = re.sub('\w', blankChar, blank)
self.reply(_('HINT: %s%s') % (show, blank))
def event():
self.timedEvent()
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)
def answer(self, msg):
correct = False
for ans in self.a:
dist = self.DL(str.lower(msg.args[1]), str.lower(ans))
flexibility = self.registryValue('flexibility', self.channel)
if dist <= len(ans) / flexibility:
correct = True
#if self.registryValue('debug'):
# self.reply('Distance: %d' % dist)
if correct:
if not msg.nick in self.scores:
self.scores[msg.nick] = 0
self.scores[msg.nick] += 1
if not msg.nick in self.roundscores:
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]))
schedule.removeEvent('next_%s' % self.channel)
self.writeScores()
self.newquestion()
def reply(self, s):
self.irc.queueMsg(ircmsgs.privmsg(self.channel, s))
def writeScores(self):
f = open(self.scorefile, 'w')
scores = iter(self.scores.items())
for i in range(0, len(self.scores)):
score = next(scores)
f.write('%s %s\n' % (score[0], score[1]))
f.close()
def DL(self, seq1, seq2):
oneago = None
thisrow = list(range(1, len(seq2) + 1)) + [0]
for x in range(len(seq1)):
# 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]
for y in range(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]:
thisrow[y] = min(thisrow[y], twoago[y - 2] + 1)
return thisrow[len(seq2) - 1]
@internationalizeDocstring
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."""
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
channel = ircutils.toLower(channel)
if channel in self.games:
if not self.games[channel].active:
del self.games[channel]
try:
schedule.removeEvent('next_%s' % channel)
except KeyError:
pass
irc.reply(_('Orphaned trivia game found and removed.'))
else:
self.games[channel].num += num
self.games[channel].total += num
irc.reply(_('%d questions added to active game!') % num)
else:
self.games[channel] = self.Game(irc, channel, num, self)
irc.noReply()
start = wrap(start, ['channel', optional('positiveInt')])
@internationalizeDocstring
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."""
channel = ircutils.toLower(channel)
try:
schedule.removeEvent('next_%s' % channel)
except KeyError:
irc.error(_('No trivia started'))
if channel in self.games:
if self.games[channel].active:
self.games[channel].stop()
else:
del self.games[channel]
irc.reply(_('Trivia stopped'))
else:
irc.noReply()
stop = wrap(stop, ['channel'])
Class = Trivia
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:

42
Jeopardy/test.py Normal file
View File

@ -0,0 +1,42 @@
###
# Copyright (c) 2011, Valentin Lorentz
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions, and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions, and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the author of this software nor the name of
# contributors to this software may be used to endorse or promote products
# derived from this software without specific prior written consent.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
###
from supybot.test import *
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: