# Quiz Engine class
# This class takes care of handling quiz questions
require './IrcSocket'
require 'csv'
require 'thread'
require 'yaml'
require './Language'
include PLanguageSupport
module PTriviaBot
class QuizEngine
def initialize(questionsFile, scoreFile, delegate, secsbetweenquestions, secstoanswer)
puts t(:initializing_quiz_engine)
@questionsFile = questionsFile
@scoreFile = scoreFile
@delegate = delegate
@quizrunning = false
@questionCount = 0
@secsbetweenquestions = secsbetweenquestions.to_i
@secstoanswer = secstoanswer.to_i
@answers = {}
@singlequestionrunning = false
loadquestions
puts t(:loaded_questions, @questions.length.to_s)
loadscores
puts t(:loaded_scores_database)
end
def loadscores
begin
@scores = YAML::load(File.open(@scoreFile,'r')) || Hash.new
rescue
puts t(:exception_no_score_file_exists, @scoreFile)
@scores = Hash.new
end
end
def savescores
File.open(@scoreFile, 'w') do |out|
YAML.dump(@scores, out)
end
end
def loadquestions
@questions = []
CSV.parse(File.open(@questionsFile,'rb')) do |row|
@questions.push(row)
end
end
def startquiz
if !@quizrunning
puts t(:starting_a_new_quiz)
@questionCount = 0
@delegate.sendmessagetoall('<font color="darkgreen">' + t(:a_new_quiz_is_about_to_begin) + '</font>')
@quizrunning = true
Thread.new {quizloop()}
end
end
def stopquiz
@quizrunning = false
@delegate.sendmessagetoall('<font color="darkred">' + t(:the_quiz_has_been_stopped) + '</font>')
end
def quizloop
while @quizrunning
# Skip wait time if this is a single question
if !@singlequestionrunning
@delegate.sendmessagetoall(t(:new_question_in_seconds,@secsbetweenquestions))
sleep @secsbetweenquestions
end
@answers.clear #Reset answers
# Double check for stop command
break unless @quizrunning
# Increase question count
@questionCount += 1
# Fetch question ID
@currentQuestionID = getrandomquestionid
# Retrieve actual question
@question = getquestion(@currentQuestionID)
# Send question text
@delegate.sendmessagetoall("<b>#{@questionCount}. #{@question[0]}</b>")
# Send answers
choice = 'A'
for i in 1..@question.length-2 do
@delegate.sendmessagetoall(" (#{choice}) #{@question[i]}")
choice = choice.succ # A-->B-->C-->...
end
@delegate.sendmessagetoall(" ")
# Wait for answers
sleep @secstoanswer/3*2
# Double check for stop command
break unless @quizrunning
secsremaining = @secstoanswer/3
@delegate.sendmessagetoall(t(:seconds_left_to_answer,secsremaining))
sleep secsremaining
# Double check for stop command
break unless @quizrunning
# That's it!
@delegate.sendmessagetoall(t(:time_is_over))
# Reveal answer
rightanswer = @question.last
rightanswerchar = indextoanswer(rightanswer.to_i)
@delegate.sendmessagetoall('<b>' + t(:correct_answer) + ': <font color="darkgreen">' + rightanswerchar + '</font></b>')
# Evaluate results...
@answers.each_pair do |nick, answerID|
@scores[nick] = 1500 unless @scores.has_key?(nick) #First time somebody answered?
previousscore = @scores[nick]
puts t(:comparing_with, answerID, rightanswer)
if answerID.to_s == rightanswer.to_s
@scores[nick] += 10
netchange = '+ 10'
else
@scores[nick] -= 10
netchange = '- 10'
end
answergiven = indextoanswer(answerID)
@delegate.sendmessagetoall(t(:user_answered,nick,previousscore,netchange,answergiven))
end
# Save results
savescores
# If this was a single question, exit
if @singlequestionrunning
@quizrunning = false
@singlequestionrunning = false
end
end
end
def askquestion
if !@singlequestionrunning and !@quizrunning
@singlequestionrunning = true
@quizrunning = true
Thread.new {quizloop()}
end
end
def indextoanswer(index)
('A'[0].ord + index).chr
end
def getrandomquestionid
rand(@questions.length)
end
def getquestion(id)
@questions[id]
end
def giveanswer(nickname, answer)
@answers[nickname] = answer.upcase[0].ord - 'A'[0].ord unless @answers.has_key?(nickname)
puts t(:answers_to_question,nickname,answer)
end
attr_accessor :quizrunning, :scores
end
end