]>
jfr.im git - irc/rizon/acid.git/blob - pyva/pyva/src/main/python/trivia/trivia_engine.py
901ddba4137f539e25979ca44f2560a242049424
2 # provides the Trivia class for channels
3 # Also I hate trivia bots.
6 from datetime
import datetime
, timedelta
12 ## string cname: channel name
13 ## PSModule mod: the module calling us
14 ## string theme: the name of the theme table
15 ## int question_number: the number of questions to ask (if 0, unlimited)
17 # initialized elsewhere:
18 # string[] answer: the answer to the question being asked
19 # int asked_questions: the amount of questions already asked
20 # int hints_given: the number of hints already given; reset to 0 by ask and
22 # string winner: winner of the last round
23 # int streak: number of times the winner responded to a question
24 # datetime started: time when we asked the question
31 def __init__(self
, cname
, mod
, theme
, qnum
):
35 self
.question_number
= qnum
38 # Not repeating so people don't have to wait until forever
39 # between answered questions
40 self
.question_timer
= task
.LoopingCall(self
.ask
)
41 self
.question_timer
.start(3, False)
43 self
.module
.msg(self
.cname
, "Starting round of trivia. Questions: unlimited")
45 self
.module
.msg(self
.cname
, "Starting round of trivia. Questions: %d" % qnum
)
48 '''Asks a question to the channel.'''
49 if self
.question_number
> 0:
50 if self
.asked_questions
>= self
.question_number
:
51 # call parent to remove reference from dict so GC cleans us up
52 self
.module
.stop_trivia(self
.cname
, False)
55 # Silly db design is silly
57 self
.dbp
.execute("SELECT question, answer FROM `trivia_questions_%s` ORDER BY rand() LIMIT 1"
60 self
.module
.elog
.error('Unable to look up trivia question: %s' % ex
)
62 resultset
= self
.dbp
.fetchone()
63 # If there is a *, multiple answers may be possible. Silly Trivia DB doing
65 self
.answer
= unicode(resultset
[1]).split('*')
67 self
.asked_questions
+= 1
70 self
.hint_timer
= task
.LoopingCall(self
.give_hint
)
71 self
.hint_timer
.start(10, False)
73 # SOME questions have a question mark already appended, some don't.
74 # We're gonna keep compatibility here and append a question mark.
75 self
.module
.msg(self
.cname
, "%d. %s?" % (self
.asked_questions
, resultset
[0]))
76 self
.started
= datetime
.now()
79 '''Gives a hint, increases the hints_given variable and sets timer for
80 the next hint being given.'''
84 if self
.hints_given
== 0:
86 self
.hint_timer
= task
.LoopingCall(self
.give_hint
)
87 self
.hint_timer
.start(10, False)
88 elif self
.hints_given
== 1:
89 if len(self
.answer
[0]) < 20:
93 self
.hint_timer
= task
.LoopingCall(self
.give_hint
)
94 self
.hint_timer
.start(20, False)
95 # Also show some parts of the ending if last hint
96 elif self
.hints_given
== 2:
97 if len(self
.answer
[0]) < 20:
101 if len(self
.answer
[0]) >= 32:
103 elif len(self
.answer
[0]) >= 24:
105 elif len(self
.answer
[0]) >= 16:
107 elif len(self
.answer
[0]) >= 8:
109 elif len(self
.answer
[0]) >= 4:
111 self
.hint_timer
= task
.LoopingCall(self
.give_hint
)
112 self
.hint_timer
.start(20, False)
113 elif self
.hints_given
== 3:
115 self
.module
.msg(self
.cname
, "Time's up! The answer was: " + self
.answer
[0])
118 self
.hint_timer
= task
.LoopingCall(self
.ask
)
119 self
.hint_timer
.start(5, False)
123 # Length from the beginning of the string to be shown
124 length
= (int)(len(self
.answer
[0]) * factor
)
125 # substring from the beginning to length to be shown
126 showstr
= self
.answer
[0][0:length
]
127 # substring from the middle of the string to be hidden
129 # if "end", the number of characters to show at the end is not 0 only go until there
131 hidestr
= self
.answer
[0][length
:len(self
.answer
[0])-end
]
133 hidestr
= self
.answer
[0][length
:]
134 tltable
= dict(zip(map(ord, u
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'), map(ord, u
'**************************************************************')))
135 hidestr
= hidestr
.translate(tltable
)
136 # substring to be shown if there's an end
139 endstr
= self
.answer
[0][len(self
.answer
[0])-end
:]
141 hint
= showstr
+ hidestr
+ endstr
142 self
.module
.msg(self
.cname
, "Hint: " + hint
)
144 self
.hints_given
+= 1
146 def check_answer(self
, nick
, answer
):
147 '''checks if a given answer is the one we're looking for. self.module
148 will need to call this; we'll only check for validity and they must
149 check if they even want to run this.
150 We'll also apply points/streak, though.'''
151 # Hey, smartass, don't answer before you know the question!
152 if self
.started
== None:
156 tdiff
= now
- self
.started
157 tdelta
= tdiff
.seconds
+ tdiff
.microseconds
/1000000.
158 # No human can answer in one second or less (compat with orig Trivia)
163 for a
in self
.answer
:
164 if a
.lower() in answer
.lower():
171 if self
.winner
== nick
:
177 if self
.hints_given
== 0:
180 points
= 4 - self
.hints_given
182 points
*= self
.streak
184 # XXX: We're COMPLETELY ignoring RFC1459 casemapping here
185 cid
= self
.module
.get_cid(self
.cname
)
187 self
.dbp
.execute('SELECT points, fastest_time, highest_streak FROM trivia_scores WHERE nick = %s AND channel = %s',
189 except Exception, ex
:
190 self
.module
.elog
.error('Unable to look up trivia scores: %s' % ex
)
192 res
= self
.dbp
.fetchone()
194 fastest_time
= 61 # greater than all of the timers added
197 (totalpoints
, fastest_time
, highest_streak
) = res
199 totalpoints
+= points
201 self
.module
.msg(self
.cname
, "Winner: %s; Answer: %s; Time: %.3fs; Streak: %d; Points: %d; Total: %d"
202 % (nick
, self
.answer
[0], tdelta
, self
.streak
, points
, totalpoints
))
204 if fastest_time
> tdelta
:
205 fastest_time
= tdelta
206 if self
.streak
> highest_streak
:
207 highest_streak
= self
.streak
210 self
.dbp
.execute('UPDATE trivia_scores SET points = %s, fastest_time = %s, highest_streak = %s WHERE nick = %s AND channel = %s',
211 (totalpoints
, fastest_time
, highest_streak
, nick
.lower(), cid
))
213 self
.dbp
.execute('INSERT INTO trivia_scores(points, fastest_time, highest_streak, nick, channel) VALUES (%s, %s, %s, %s, %s)',
214 (totalpoints
, fastest_time
, highest_streak
, nick
.lower(), cid
))
216 self
.question_timer
.stop()
217 self
.hint_timer
.stop()
220 self
.hint_timer
= task
.LoopingCall(self
.ask
)
221 self
.hint_timer
.start(5, False)
223 def stop(self
, forced
):
224 '''Stops a round of trivia. This stops all timers associated with this
225 instance and sends a message to the channel that the round is done.
226 If forced is True, the message "Trivia stopped." will be shown,
227 otherwise the message will be "Round of trivia complete."
228 The calling instance is responsible of removing any references to us,
229 this includes the dict entry.'''
233 self
.question_timer
.stop()
234 self
.hint_timer
.stop()
235 except AttributeError:
236 pass # We might be called before hint_timer's set up
239 msg
= "Trivia stopped."
241 msg
= "Round of trivia complete."
242 self
.module
.msg(self
.cname
,
243 msg
+ " '.trivia [number]' to start playing again.")