'Ruby: Adding a timer to a simple console quiz app
I'm learning Ruby and as part of the practice, I have implemented a simple quiz app. Its pseudocode is like this
for i in 0..questions.length - 1 do
puts questions[i]
$answer = gets.chomp
if $answer == answers[i]
correct += 1
end
end
timer_thread = Thread.new do
while $answer == nil
(1..5).each do |number|
sleep(1)
number
if number == 5
puts "Timer out"
end
break if ($answer != nil)
end
end
end
What I want is to add a timer of let's say 30 seconds, it should move to the next question and that question should be considered incorrect. I came to know about Time.now but am not sure how I can go about adding it to my program.
Any pointers, please?
Solution 1:[1]
You can use timeout. Set your desired timeout in seconds by changing time_to_answer, in this example it is set to 5.
require 'timeout'
questions = [
"2 + 2 = ?",
"Who is Amazons CEO?",
]
answers = [
"4",
"Jeff Bezos",
]
def ask_question(question, answer, time_to_answer)
puts "\n=== NEW QUESTION ==="
puts question
Timeout::timeout(time_to_answer) do
user_action = gets.chomp
return user_action === answer
end
rescue Timeout::Error
puts "? time is up! solution: #{answer}"
return false
end
time_to_answer = 5 # in seconds
score = 0 # initialize score
questions.each_with_index do |question, indx|
correct = ask_question(question, answers[indx], time_to_answer)
score += 1 if correct
puts correct ? "? correct" : "? wrong! correct solution: #{answers[indx]}"
end
puts "\n? Your score is #{score} out of #{questions.size}"
Solution 2:[2]
I think that using threads is overhead here
You can use Timeout
As I see you use two arrays for questions and answers, you can zip it with Array#zip
In Ruby we don't like for loop. We use Array#each. BTW for uses each under the hood
Using global variables in the code can lead to a shot in the foot. Use them only when you are absolutely sure that they are needed
So I would suggest refactoring the code like this:
require "timeout"
correct_answers_count = 0
TIMEOUT = 30
questions.zip(answers).each do |question, right_answer|
puts question
user_answer = nil
Timeout::timeout(TIMEOUT) { user_answer = gets.strip }
if user_answer&.downcase == right_answer&.downcase
correct_answers_count += 1
puts "Right!"
else
puts "Wrong!"
end
rescue Timeout::Error
puts "Time is out"
end
puts "Right answers: #{correct_answers_count}"
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | mechnicov |
