2025-08-28 21:02:26 -04:00
|
|
|
require "rufus-scheduler"
|
|
|
|
|
2025-08-19 21:07:51 -04:00
|
|
|
class Drill
|
2025-08-29 17:46:40 -04:00
|
|
|
attr_reader :responder, :current_question, :scheduler, :questions
|
2025-08-28 21:02:26 -04:00
|
|
|
attr_accessor :length, :participants, :timer_job_id
|
|
|
|
|
|
|
|
def initialize(responder: nil, scheduler: Rufus::Scheduler.new)
|
|
|
|
@responder = responder
|
|
|
|
@participants = []
|
|
|
|
@length = "10m"
|
|
|
|
@running = false
|
|
|
|
@scheduler = scheduler
|
|
|
|
@time_is_up = false
|
2025-08-29 17:46:40 -04:00
|
|
|
@questions = []
|
2025-08-28 21:02:26 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def respond(response)
|
|
|
|
responder.call response
|
|
|
|
end
|
|
|
|
|
|
|
|
def can_handle_message?(message)
|
|
|
|
true
|
|
|
|
end
|
2025-08-23 14:38:42 -04:00
|
|
|
|
2025-08-28 21:02:26 -04:00
|
|
|
ACTIONS = %w[join leave start stop]
|
|
|
|
CUSTOMIZATIONS = %w[length]
|
2025-08-19 21:07:51 -04:00
|
|
|
|
2025-08-28 21:02:26 -04:00
|
|
|
def handle_message(message)
|
|
|
|
if ACTIONS.include? message.content
|
|
|
|
return send("handle_#{message.content.downcase}", message)
|
|
|
|
elsif customization = CUSTOMIZATIONS.find { |c| message.content.start_with?("#{c} ") }
|
|
|
|
return send("handle_customize_#{customization}", message)
|
|
|
|
end
|
|
|
|
return unless running?
|
|
|
|
return unless message.author == current_question_target
|
|
|
|
|
|
|
|
handle_question_response(message)
|
2025-08-19 21:07:51 -04:00
|
|
|
end
|
|
|
|
|
2025-08-28 21:02:26 -04:00
|
|
|
def handle_join(message)
|
2025-08-29 17:15:49 -04:00
|
|
|
return respond "The drill's already started!" if running?
|
|
|
|
|
2025-08-28 21:02:26 -04:00
|
|
|
if participants.include? message.author
|
|
|
|
respond "You've already joined"
|
|
|
|
else
|
|
|
|
self.participants << message.author
|
|
|
|
respond "#{message.author.display_name} has joined"
|
|
|
|
end
|
2025-08-23 14:38:42 -04:00
|
|
|
end
|
|
|
|
|
2025-08-28 21:02:26 -04:00
|
|
|
def handle_leave(message)
|
2025-08-29 17:15:49 -04:00
|
|
|
return respond "The drill's already started!" if running?
|
|
|
|
|
2025-08-28 21:02:26 -04:00
|
|
|
if participants.include? message.author
|
|
|
|
self.participants -= [message.author]
|
|
|
|
respond "#{message.author.display_name} has left"
|
|
|
|
else
|
|
|
|
respond "You aren't a participant"
|
|
|
|
end
|
2025-08-19 21:07:51 -04:00
|
|
|
end
|
|
|
|
|
2025-08-28 21:02:26 -04:00
|
|
|
def handle_start(message)
|
|
|
|
return respond "The drill's already started!" if running?
|
2025-08-29 17:15:49 -04:00
|
|
|
return respond "Nobody has joined the drill! Type `join` to join it!" if participants.empty?
|
2025-08-28 21:02:26 -04:00
|
|
|
|
|
|
|
@running = true
|
|
|
|
@time_is_up = false
|
|
|
|
self.timer_job_id = scheduler.in(length){ @time_is_up = true }
|
|
|
|
respond "Drill started!"
|
|
|
|
participants.shuffle!
|
2025-08-29 17:46:40 -04:00
|
|
|
@questions = []
|
2025-08-28 21:02:26 -04:00
|
|
|
next_question!
|
2025-08-19 21:07:51 -04:00
|
|
|
end
|
|
|
|
|
2025-08-28 21:02:26 -04:00
|
|
|
def handle_stop(message)
|
|
|
|
return respond "The drill's not running yet" unless running?
|
|
|
|
|
|
|
|
scheduler.unschedule(timer_job_id) if timer_job_id
|
2025-08-29 17:15:49 -04:00
|
|
|
|
|
|
|
end_drill!
|
2025-08-28 21:02:26 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def handle_customize_length(message)
|
|
|
|
return respond "The drill's already started!" if running?
|
|
|
|
|
|
|
|
cmd, desired_length = message.content.split
|
|
|
|
return respond "Please specify a length" unless desired_length
|
|
|
|
|
|
|
|
self.length = desired_length
|
|
|
|
respond "Drill length set to #{desired_length}"
|
2025-08-19 21:07:51 -04:00
|
|
|
end
|
|
|
|
|
2025-08-28 21:02:26 -04:00
|
|
|
def handle_question_response(message)
|
2025-08-29 17:46:40 -04:00
|
|
|
if current_question.answer message.content
|
2025-08-28 21:02:26 -04:00
|
|
|
respond "Correct!"
|
2025-08-23 14:38:42 -04:00
|
|
|
else
|
2025-08-28 21:02:26 -04:00
|
|
|
respond "Incorrect: #{current_question.correct_answer}"
|
2025-08-19 21:07:51 -04:00
|
|
|
end
|
2025-08-28 21:02:26 -04:00
|
|
|
|
|
|
|
next_question!
|
|
|
|
end
|
|
|
|
|
|
|
|
def next_question!
|
|
|
|
return end_drill! if time_is_up?
|
|
|
|
|
|
|
|
self.participants = participants.rotate
|
|
|
|
|
|
|
|
generate_question
|
|
|
|
respond "#{current_question_target.display_name}: #{current_question.question_text}"
|
|
|
|
end
|
|
|
|
|
|
|
|
def end_drill!
|
2025-08-29 17:46:40 -04:00
|
|
|
respond "Lesson's over!"
|
|
|
|
questions.group_by(&:target).each do |target, target_questions|
|
|
|
|
correct_count = target_questions.select(&:correct?).count
|
|
|
|
total_count = target_questions.count
|
|
|
|
percentage = "#{((correct_count.to_f / total_count) * 100).to_i}%"
|
|
|
|
respond "#{target.display_name} got #{correct_count} out of #{total_count} correct (#{percentage})"
|
|
|
|
end
|
|
|
|
|
2025-08-28 21:02:26 -04:00
|
|
|
@running = false
|
2025-08-29 17:15:49 -04:00
|
|
|
@participants = []
|
2025-08-28 21:02:26 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def generate_question
|
2025-08-29 17:46:40 -04:00
|
|
|
q = Question.new current_question_target
|
|
|
|
questions << q
|
|
|
|
@current_question = q
|
2025-08-28 21:02:26 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def current_question_target
|
|
|
|
participants.first
|
2025-08-23 14:38:42 -04:00
|
|
|
end
|
2025-08-19 21:07:51 -04:00
|
|
|
|
2025-08-28 21:02:26 -04:00
|
|
|
def running?
|
|
|
|
@running
|
2025-08-23 14:38:42 -04:00
|
|
|
end
|
2025-08-19 21:07:51 -04:00
|
|
|
|
2025-08-28 21:02:26 -04:00
|
|
|
def time_is_up?
|
|
|
|
@time_is_up
|
2025-08-19 21:07:51 -04:00
|
|
|
end
|
2025-08-29 17:46:40 -04:00
|
|
|
|
|
|
|
class Question
|
|
|
|
attr_reader :question_text, :correct_answer, :target
|
|
|
|
attr_accessor :given_answer
|
|
|
|
|
|
|
|
def initialize(target) # some kind of config here
|
|
|
|
@target = target
|
|
|
|
|
|
|
|
value = (1..100).to_a.sample
|
|
|
|
@question_text = "Type the number #{value}"
|
|
|
|
@correct_answer = value.to_s
|
|
|
|
end
|
|
|
|
|
|
|
|
def answer(response)
|
|
|
|
@given_answer = response
|
|
|
|
correct?
|
|
|
|
end
|
|
|
|
|
|
|
|
def correct?
|
|
|
|
given_answer == correct_answer
|
|
|
|
end
|
|
|
|
end
|
2025-08-19 21:07:51 -04:00
|
|
|
end
|