]>
jfr.im git - irc/rizon/acid.git/blob - pyva/pyva/src/main/python/trivia/trivia_engine.py
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
35 'geography' : 'Geography' ,
37 'lotr-books' : 'LOTR-Books' ,
38 'lotr-movies' : 'LOTR-Movies' ,
41 'sciandnature' : 'ScienceAndNature' ,
42 'simpsons' : 'Simpsons' ,
46 def __init__ ( self
, cname
, mod
, theme
, qnum
):
50 self
. question_number
= qnum
53 # Not repeating so people don't have to wait until forever
54 # between answered questions
55 self
. question_timer
= task
. LoopingCall ( self
. ask
)
56 self
. question_timer
. start ( 3 , False )
58 self
. module
. msg ( self
. cname
, "Starting round of trivia. Questions: unlimited" )
60 self
. module
. msg ( self
. cname
, "Starting round of trivia. Questions: %d " % qnum
)
63 '''Asks a question to the channel.'''
64 if self
. question_number
> 0 :
65 if self
. asked_questions
>= self
. question_number
:
66 # call parent to remove reference from dict so GC cleans us up
67 self
. module
. stop_trivia ( self
. cname
, False )
71 query
= "SELECT tq.question, tq.answer FROM `trivia_questions` AS tq JOIN (SELECT tq2.id FROM `trivia_questions` AS tq2 JOIN `trivia_themes` AS tt ON tq2.theme_id=tt.theme_id AND tt.theme_name=' %s ' ORDER BY rand() LIMIT 1) AS x WHERE tq.id = x.id"
72 self
. dbp
. execute ( query
% self
. themes
[ self
. theme
])
74 self
. module
. elog
. error ( 'Unable to look up trivia question: %s ' % ex
)
76 resultset
= self
. dbp
. fetchone ()
77 # If there is a *, multiple answers may be possible. Silly Trivia DB doing
79 self
. answer
= unicode ( resultset
[ 1 ]). split ( '*' )
81 self
. asked_questions
+= 1
84 self
. hint_timer
= task
. LoopingCall ( self
. give_hint
)
85 self
. hint_timer
. start ( 10 , False )
87 # SOME questions have a question mark already appended, some don't.
88 # We're gonna keep compatibility here and append a question mark.
89 self
. module
. msg ( self
. cname
, " %d . %s ?" % ( self
. asked_questions
, resultset
[ 0 ]))
90 self
. started
= datetime
. now ()
93 '''Gives a hint, increases the hints_given variable and sets timer for
94 the next hint being given.'''
98 if self
. hints_given
== 0 :
100 self
. hint_timer
= task
. LoopingCall ( self
. give_hint
)
101 self
. hint_timer
. start ( 10 , False )
102 elif self
. hints_given
== 1 :
103 if len ( self
. answer
[ 0 ]) < 20 :
107 self
. hint_timer
= task
. LoopingCall ( self
. give_hint
)
108 self
. hint_timer
. start ( 20 , False )
109 # Also show some parts of the ending if last hint
110 elif self
. hints_given
== 2 :
111 if len ( self
. answer
[ 0 ]) < 20 :
115 if len ( self
. answer
[ 0 ]) >= 32 :
117 elif len ( self
. answer
[ 0 ]) >= 24 :
119 elif len ( self
. answer
[ 0 ]) >= 16 :
121 elif len ( self
. answer
[ 0 ]) >= 8 :
123 elif len ( self
. answer
[ 0 ]) >= 4 :
125 self
. hint_timer
= task
. LoopingCall ( self
. give_hint
)
126 self
. hint_timer
. start ( 20 , False )
127 elif self
. hints_given
== 3 :
129 self
. module
. msg ( self
. cname
, "Time's up! The answer was: " + self
. answer
[ 0 ])
132 self
. hint_timer
= task
. LoopingCall ( self
. ask
)
133 self
. hint_timer
. start ( 5 , False )
137 # Length from the beginning of the string to be shown
138 length
= ( int )( len ( self
. answer
[ 0 ]) * factor
)
139 # substring from the beginning to length to be shown
140 showstr
= self
. answer
[ 0 ][ 0 : length
]
141 # substring from the middle of the string to be hidden
143 # if "end", the number of characters to show at the end is not 0 only go until there
145 hidestr
= self
. answer
[ 0 ][ length
: len ( self
. answer
[ 0 ])- end
]
147 hidestr
= self
. answer
[ 0 ][ length
:]
148 tltable
= dict ( zip ( map ( ord , u
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' ), map ( ord , u
'**************************************************************' )))
149 hidestr
= hidestr
. translate ( tltable
)
150 # substring to be shown if there's an end
153 endstr
= self
. answer
[ 0 ][ len ( self
. answer
[ 0 ])- end
:]
155 hint
= showstr
+ hidestr
+ endstr
156 self
. module
. msg ( self
. cname
, "Hint: " + hint
)
158 self
. hints_given
+= 1
160 def check_answer ( self
, nick
, answer
):
161 '''checks if a given answer is the one we're looking for. self.module
162 will need to call this; we'll only check for validity and they must
163 check if they even want to run this.
164 We'll also apply points/streak, though.'''
165 # Hey, smartass, don't answer before you know the question!
166 if self
. started
== None :
170 tdiff
= now
- self
. started
171 tdelta
= tdiff
. seconds
+ tdiff
. microseconds
/ 1000000 .
172 # No human can answer in one second or less (compat with orig Trivia)
177 for a
in self
. answer
:
179 # Issue #10: do not accept '200' when the correct answer is '20'
186 if a
. lower () in answer
. lower ():
195 if self
. winner
== nick
:
201 if self
. hints_given
== 0 :
204 points
= 4 - self
. hints_given
206 points
*= self
. streak
208 # XXX: We're COMPLETELY ignoring RFC1459 casemapping here
209 cid
= self
. module
. get_cid ( self
. cname
)
211 self
. dbp
. execute ( 'SELECT points, fastest_time, highest_streak FROM trivia_scores WHERE nick = %s AND channel = %s ' ,
213 except Exception , ex
:
214 self
. module
. elog
. error ( 'Unable to look up trivia scores: %s ' % ex
)
216 res
= self
. dbp
. fetchone ()
218 fastest_time
= 61 # greater than all of the timers added
221 ( totalpoints
, fastest_time
, highest_streak
) = res
223 totalpoints
+= points
225 self
. module
. msg ( self
. cname
, "Winner: %s ; Answer: %s ; Time: %.3fs; Streak: %d ; Points: %d ; Total: %d "
226 % ( nick
, self
. answer
[ 0 ], tdelta
, self
. streak
, points
, totalpoints
))
228 if fastest_time
> tdelta
:
229 fastest_time
= tdelta
230 if self
. streak
> highest_streak
:
231 highest_streak
= self
. streak
234 self
. dbp
. execute ( 'UPDATE trivia_scores SET points = %s , fastest_time = %s , highest_streak = %s WHERE nick = %s AND channel = %s ' ,
235 ( totalpoints
, fastest_time
, highest_streak
, nick
. lower (), cid
))
237 self
. dbp
. execute ( 'INSERT INTO trivia_scores(points, fastest_time, highest_streak, nick, channel) VALUES ( %s , %s , %s , %s , %s )' ,
238 ( totalpoints
, fastest_time
, highest_streak
, nick
. lower (), cid
))
240 self
. question_timer
. stop ()
241 self
. hint_timer
. stop ()
244 self
. hint_timer
= task
. LoopingCall ( self
. ask
)
245 self
. hint_timer
. start ( 5 , False )
247 def stop ( self
, forced
):
248 '''Stops a round of trivia. This stops all timers associated with this
249 instance and sends a message to the channel that the round is done.
250 If forced is True, the message "Trivia stopped." will be shown,
251 otherwise the message will be "Round of trivia complete."
252 The calling instance is responsible of removing any references to us,
253 this includes the dict entry.'''
257 self
. question_timer
. stop ()
258 self
. hint_timer
. stop ()
259 except AttributeError :
260 pass # We might be called before hint_timer's set up
263 msg
= "Trivia stopped."
265 msg
= "Round of trivia complete."
266 self
. module
. msg ( self
. cname
,
267 msg
+ " '.trivia [number]' to start playing again." )
270 '''Stops the current question and asks the next question'''
272 self
. question_timer
. stop ()
273 self
. hint_timer
. stop ()
274 except AttributeError :
279 self
. hint_timer
= task
. LoopingCall ( self
. ask
)
280 self
. hint_timer
. start ( 5 , False )
282 self
. module
. msg ( self
. cname
, "Skipping question" )