2016-01-31 19:28:22 +01:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
import os
|
|
|
|
|
import random
|
|
|
|
|
from functools import lru_cache
|
|
|
|
|
|
|
|
|
|
import re
|
|
|
|
|
|
|
|
|
|
import time
|
2016-04-05 14:18:22 +02:00
|
|
|
import config
|
|
|
|
|
from plugin_system import pluginfunction, ptypes
|
|
|
|
|
|
|
|
|
|
@pluginfunction('quiz', 'play quiz', ptypes.COMMAND)
|
|
|
|
|
def quiz_control(argv, **args):
|
|
|
|
|
usage = """quiz mode usage: "quiz start [secs interval:default 30]", "quiz stop", "quiz rules;
|
|
|
|
|
Not yet implemented: "quiz answer", "quiz skip".
|
|
|
|
|
If the quiz mode is active, all messages are parsed and compared against the answer.
|
|
|
|
|
"""
|
|
|
|
|
if not argv:
|
|
|
|
|
return {'msg': usage}
|
|
|
|
|
|
|
|
|
|
rules = """
|
|
|
|
|
The answers will be matched by characters/words. Answers will be
|
|
|
|
|
granted points according to the match percentage with a minimum
|
|
|
|
|
percentage depending on word count. After a configurable timeout per
|
|
|
|
|
quiz game, a single winner will be declared, if any. The timeout can
|
|
|
|
|
be cancelled with "quiz answer" or "quiz skip", which results in
|
|
|
|
|
a lost round.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
with config.plugin_config('quiz') as quizcfg:
|
|
|
|
|
if quizcfg is None:
|
|
|
|
|
quizcfg = dict()
|
|
|
|
|
|
|
|
|
|
if argv[0] == 'start':
|
|
|
|
|
quizcfg['stop_bit'] = False
|
|
|
|
|
interval = int(argv[1]) if len(argv) > 1 else 30
|
|
|
|
|
quizcfg['interval'] = interval
|
|
|
|
|
return start_random_question()
|
|
|
|
|
elif argv[0] == 'stop':
|
|
|
|
|
return end(quizcfg)
|
|
|
|
|
elif argv[0] == 'answer':
|
|
|
|
|
return answer(quizcfg)
|
|
|
|
|
elif argv[0] == 'skip':
|
|
|
|
|
return skip(quizcfg)
|
|
|
|
|
elif argv[0] == 'rules':
|
|
|
|
|
return {
|
|
|
|
|
'msg': rules
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pluginfunction('quizparser', 'react on chat during quiz games', ptypes.PARSE)
|
|
|
|
|
def quizparser(**args):
|
|
|
|
|
with config.plugin_config('quiz') as quizcfg:
|
|
|
|
|
current_quiz_question = get_current_question(quizcfg)
|
|
|
|
|
if current_quiz_question is None:
|
|
|
|
|
return
|
|
|
|
|
else:
|
|
|
|
|
return rate(quizcfg, args['data'], args['reply_user'])
|
2016-01-31 19:28:22 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@lru_cache(10)
|
|
|
|
|
def get_questions(directory=None):
|
|
|
|
|
if not directory:
|
|
|
|
|
directory = 'plugins/quiz_resources/'
|
|
|
|
|
all_files = sorted(filter(lambda x: x.endswith('.txt'), os.listdir(directory)))
|
|
|
|
|
all_questions = []
|
2016-01-31 22:29:28 +01:00
|
|
|
for q_file in all_files:
|
2016-01-31 19:28:22 +01:00
|
|
|
with open(directory + q_file) as f:
|
|
|
|
|
all_questions += f.readlines()[1:]
|
|
|
|
|
return all_questions
|
|
|
|
|
|
|
|
|
|
|
2016-01-31 22:22:41 +01:00
|
|
|
def get_random_question():
|
2016-04-05 14:18:22 +02:00
|
|
|
with config.plugin_config('quiz') as quizcfg:
|
2016-01-31 22:22:41 +01:00
|
|
|
questions = get_questions()
|
|
|
|
|
# select a random question
|
|
|
|
|
used_ids = quizcfg.get('used_ids', [])
|
|
|
|
|
q_index = None
|
2016-01-31 22:29:28 +01:00
|
|
|
while q_index is None or len(questions[q_index+1].split()) > 8:
|
|
|
|
|
rand = random.choice(range(1956, len(questions)-2, 2))
|
2016-01-31 22:22:41 +01:00
|
|
|
if rand not in used_ids:
|
|
|
|
|
q_index = rand
|
|
|
|
|
|
|
|
|
|
quizcfg['active_id'] = q_index
|
|
|
|
|
quizcfg['used_ids'] = used_ids + [q_index]
|
2016-01-31 19:28:22 +01:00
|
|
|
return questions[q_index], questions[q_index+1]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_current_question(quizcfg):
|
2016-01-31 21:20:27 +01:00
|
|
|
if quizcfg.get('active_id') and quizcfg.get('active_id') != 'None':
|
2016-01-31 19:28:22 +01:00
|
|
|
return int(quizcfg['active_id'])
|
|
|
|
|
|
|
|
|
|
|
2016-01-31 21:18:09 +01:00
|
|
|
def end_question():
|
2016-04-05 14:18:22 +02:00
|
|
|
with config.plugin_config('quiz') as quizcfg:
|
2016-01-31 21:18:09 +01:00
|
|
|
lines = ['Question time over!']
|
2016-01-31 19:28:22 +01:00
|
|
|
|
2016-01-31 21:18:09 +01:00
|
|
|
score = float(quizcfg.get('current_max_score', 0))
|
|
|
|
|
winner = quizcfg.get('current_max_user', 'nobody')
|
2016-01-31 19:28:22 +01:00
|
|
|
|
2016-01-31 21:18:09 +01:00
|
|
|
print(winner, score)
|
|
|
|
|
win_msg = '{} scores with {:.2f}%'.format(winner, score)
|
|
|
|
|
lose_msg = 'nobody scores.'
|
2016-01-31 19:28:22 +01:00
|
|
|
|
2016-01-31 21:42:22 +01:00
|
|
|
the_answer = get_questions()[get_current_question(quizcfg)+1]
|
|
|
|
|
lines.append('Answer to the question: {}'.format(the_answer))
|
|
|
|
|
|
2016-01-31 21:33:05 +01:00
|
|
|
if score >= 50.0:
|
2016-01-31 21:18:09 +01:00
|
|
|
lines.append(win_msg)
|
|
|
|
|
else:
|
|
|
|
|
lines.append(lose_msg)
|
2016-01-31 19:28:22 +01:00
|
|
|
|
2016-01-31 21:18:09 +01:00
|
|
|
quizcfg["locked"] = False
|
|
|
|
|
quizcfg['current_max_user'] = 'nobody'
|
|
|
|
|
quizcfg['current_max_score'] = 0
|
2016-01-31 19:28:22 +01:00
|
|
|
|
2016-01-31 21:18:09 +01:00
|
|
|
quizcfg['active_id'] = None
|
2016-01-31 19:28:22 +01:00
|
|
|
|
2016-01-31 21:18:09 +01:00
|
|
|
action = {
|
|
|
|
|
'msg': lines
|
2016-01-31 19:28:22 +01:00
|
|
|
}
|
2016-01-31 21:18:09 +01:00
|
|
|
if quizcfg.get('stop_bit', False):
|
|
|
|
|
quizcfg['stop_bit'] = False
|
|
|
|
|
lines.append('stopping the quiz now.')
|
|
|
|
|
else:
|
|
|
|
|
action['event'] = {
|
|
|
|
|
'time': time.time() + 10,
|
|
|
|
|
'command': (start_random_question, ([],))
|
|
|
|
|
}
|
|
|
|
|
lines.append('continuing.')
|
2016-01-31 19:28:22 +01:00
|
|
|
|
2016-01-31 21:18:09 +01:00
|
|
|
return action
|
2016-01-31 19:28:22 +01:00
|
|
|
|
2016-01-31 21:18:09 +01:00
|
|
|
|
|
|
|
|
def end(quizcfg):
|
|
|
|
|
# TODO: cleanup the switches
|
2016-01-31 19:28:22 +01:00
|
|
|
quizcfg['stop_bit'] = True
|
2016-01-31 21:18:09 +01:00
|
|
|
quizcfg['locked'] = False
|
2016-01-31 21:35:11 +01:00
|
|
|
return {'msg': 'stopping.'}
|
2016-01-31 19:28:22 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def rate(quizcfg, response, user):
|
|
|
|
|
"""
|
|
|
|
|
rate answer, check threshold, note user score
|
|
|
|
|
:param quizcfg: configsection plugins/quiz
|
|
|
|
|
:param response: text given by users
|
|
|
|
|
:param user: nick to the response
|
|
|
|
|
:return: actiondict
|
|
|
|
|
"""
|
|
|
|
|
questions = get_questions()
|
|
|
|
|
current_quiz_question = get_current_question(quizcfg)
|
2016-01-31 21:18:09 +01:00
|
|
|
the_answer = questions[current_quiz_question+1].lower()
|
2016-01-31 19:28:22 +01:00
|
|
|
|
2016-01-31 21:18:09 +01:00
|
|
|
anwer_words = set(re.findall('[a-zA-ZäöüÄÖÜß0-9]+', the_answer))
|
2016-01-31 19:28:22 +01:00
|
|
|
words = set(response.lower().split())
|
|
|
|
|
|
|
|
|
|
# stripping all fill words seems like a tedious task...
|
|
|
|
|
|
|
|
|
|
same_words = words.intersection(anwer_words)
|
|
|
|
|
percentage = len(same_words)/len(anwer_words)*100
|
|
|
|
|
|
|
|
|
|
threshold = 50
|
|
|
|
|
if (
|
2016-01-31 21:33:05 +01:00
|
|
|
percentage >= threshold and
|
2016-01-31 19:28:22 +01:00
|
|
|
float(quizcfg.get('current_max_score', 0)) < percentage
|
|
|
|
|
):
|
|
|
|
|
quizcfg['current_max_user'] = user
|
|
|
|
|
quizcfg['current_max_score'] = percentage
|
|
|
|
|
return {
|
|
|
|
|
'msg': 'Good answer.'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# verbose_response = {
|
|
|
|
|
# 'msg': 'matching {} words (answer {}), percentage {}'.format(
|
|
|
|
|
# same_words, anwer_words, percentage
|
|
|
|
|
# )
|
|
|
|
|
# }
|
|
|
|
|
|
|
|
|
|
|
2016-01-31 21:18:09 +01:00
|
|
|
def start_random_question():
|
2016-04-05 14:18:22 +02:00
|
|
|
with config.plugin_config('quiz') as quizcfg:
|
2016-01-31 21:18:09 +01:00
|
|
|
if quizcfg.get("locked", False):
|
|
|
|
|
return {'msg': 'already running!'}
|
2016-01-31 19:28:22 +01:00
|
|
|
|
2016-01-31 21:18:09 +01:00
|
|
|
else:
|
|
|
|
|
quizcfg["locked"] = True
|
2016-01-31 22:22:41 +01:00
|
|
|
qa = get_random_question()
|
2016-01-31 21:18:09 +01:00
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
'msg': ['Q: {}'.format(qa[0])],
|
|
|
|
|
'event': {
|
|
|
|
|
'command': (end_question, ([],)),
|
|
|
|
|
'time': time.time() + int(quizcfg['interval'])
|
|
|
|
|
}
|
2016-01-31 19:28:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-01-31 21:18:09 +01:00
|
|
|
# TODO: fix those
|
2016-01-31 19:28:22 +01:00
|
|
|
def skip(quizcfg):
|
|
|
|
|
""" skip the current question, omitting the
|
|
|
|
|
answer and removing it from the used ones """
|
2016-01-31 21:18:09 +01:00
|
|
|
raise NotImplementedError()
|
2016-01-31 19:28:22 +01:00
|
|
|
quizcfg['used_ids'].remove(get_current_question(quizcfg))
|
2016-01-31 21:18:09 +01:00
|
|
|
return end_question()
|
2016-01-31 19:28:22 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def answer(quizcfg):
|
2016-01-31 21:18:09 +01:00
|
|
|
raise NotImplementedError()
|
2016-01-31 19:28:22 +01:00
|
|
|
the_answer = get_questions()[get_current_question(quizcfg)+1]
|
|
|
|
|
return {
|
|
|
|
|
'msg': 'Answer to the question: {}'.format(the_answer),
|
|
|
|
|
'event': {
|
2016-01-31 21:18:09 +01:00
|
|
|
'command': (end_question, ([], )),
|
2016-01-31 19:28:22 +01:00
|
|
|
'time': time.time() + 3
|
|
|
|
|
}
|
|
|
|
|
}
|