The three rules of Ruby Q.:
-
Please do not post any solutions or spoiler discussion for this quiz
until
48 hours have passed from the time on this message. -
Support Ruby Q. by submitting ideas as often as you can:
- Enjoy!
Suggestion: A [QUIZ] in the subject of emails about the problem helps
everyone
on Ruby T. follow the discussion. Please reply to the original quiz
message,
if you can.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
by Gavin K.
The Background
---------------------------------------------------------------------
Last night I was having trouble falling asleep, and was staring at my
digital
alarm clock (as I do so often under that circumstance). Something on the
bedside
table was occluding the minutes digit, however, so all I could tell is
that it
was “10 4”. (Oddly, my alarm clock has no “:” between the hours and
minutes.)
“How nice!” I thought. “An imposed vagueness to keep me from obsessing
on
exactly what time it is! Should I really be worried about the exact
time?
Shouldn’t I be more relaxed? Shouldn’t a 10-minute precision in life be
enough
to keep me roughly on time, without obsessing on exacting promptitude?”
I realized that if I kept staring at the clock (as I did), and I were to
observe
it changing from “10 4” to “10 5”, that I would, at that moment, know
exactly
what time it is.
“Bah” I thought, “so much for that idea.”
And then I thought some more. I thought of bad ideas: analog watches
where the
hand erratically swings forward and backward, digital clocks that showed
random
times near the correct time. And then I dreamed of the watch I wanted to
own…
The Challenge
---------------------------------------------------------------------
Requirement #1: Write a Ruby program that shows the current time, but
only the
‘tens’ part of the minutes. For example, if the time is 10:37, then the
program
might output “10:3~”
Requirement #2: The time shown by the clock must randomly vary +/- 5
minutes
from reality. For example, if the time is actually 10:37, the program
might
output “10:3~” or “10:4~” (but not “10:2~” or “10:5~”).
Requirement #3: The time on the clock should continuously increase. If
the time
shows “10:4~” it must continue to show “10:4~” until it shows “10:5~”.
(It can’t
show “10:4~”, then “10:3~” for a bit and then come back to “10:4~”.)
Putting the three requirements together, the left column below shows the
actual
time and the next three columns show the possible outputs from three
different
runs of the same program:
10:35 10:3~ 10:4~ 10:3~
10:36 10:3~ 10:4~ 10:3~
10:37 10:3~ 10:4~ 10:3~
10:38 10:3~ 10:4~ 10:3~
10:39 10:4~ 10:4~ 10:3~
10:40 10:4~ 10:4~ 10:3~
10:41 10:4~ 10:4~ 10:3~
10:42 10:4~ 10:4~ 10:3~
10:43 10:4~ 10:4~ 10:3~
10:44 10:4~ 10:4~ 10:3~
10:45 10:4~ 10:4~ 10:4~
10:46 10:4~ 10:4~ 10:5~
10:47 10:4~ 10:4~ 10:5~
10:48 10:4~ 10:4~ 10:5~
10:49 10:4~ 10:4~ 10:5~
10:50 10:4~ 10:4~ 10:5~
10:51 10:4~ 10:4~ 10:5~
10:52 10:5~ 10:4~ 10:5~
10:53 10:5~ 10:4~ 10:5~
10:54 10:5~ 10:4~ 10:5~
10:55 10:5~ 10:5~ 10:5~
10:56 10:5~ 10:5~ 11:0~
10:57 10:5~ 10:5~ 11:0~
10:58 10:5~ 10:5~ 11:0~
10:59 10:5~ 10:5~ 11:0~
11:00 10:5~ 10:5~ 11:0~
11:01 10:5~ 10:5~ 11:0~
Testing your Output
---------------------------------------------------------------------
You should supply a FuzzyTime class that supports the following:
ft = FuzzyTime.new # Start at the current time
ft = FuzzyTime.new(Time.at(1161104503)) # Start at a specific time
p ft.to_s # to_s format
#=> "10:5~"
p ft.actual, ft.actual.class # Reports real time as Time
#=> Tue Oct 17 11:01:36 -0600 2006
#=> Time
ft.advance( 60 * 10 ) # Manually advance time
puts ft # by a specified number of
#=> 11:0~ # seconds.
sleep( 60 * 10 )
ft.update # Automatically update the time based on the
puts ft # time that has passed since the last call
#=> 11:1~ # to #initialize, #advance or #update
Your class and output will be tested with code like the following:
def test_output
# Initialize with a well-known time
ft = FuzzyTime.new( Time.at( ... ) )
60.times do
@legal = ... # Find the array of legal output strings
@output = ft.to_s
assert_block "#@output not one of #@legal.inspect" do
@legal.include?( @output )
end
sleep( rand( 30 ) )
ft.update
end
60.times do
@legal = ... # Find the array of legal output strings
@output = ft.to_s
assert_block "#@output not one of #@legal.inspect" do
@legal.include?( @output )
end
ft.advance( rand( 30 ) )
end
end
Extra Credit
---------------------------------------------------------------------
* Provide a self-running application that shows the time somehow.
(ASCII in the terminal, some GUI window, etc.)
* Allow your class to be customized to display 12- or 24-hour time.
* Allow your class to be customized to change how close to reality
it must display. (+/- 3 minutes, +/- 12 minutes, etc.)
* Allow your class to be customized to change how roughly it displays
the time (e.g. 1 minute, 10 minute, 1 hour intervals).
* Ensure that the transition from one digit to the next occurs
randomly across the range of -5 to +5. (So, while the digit might
change 5 minutes before or 5 minutes after the real transition, on
average the change should occur around the transition itself.)
You might need to assume that your update/advance method will be
called with a certain regularity (e.g. once per second, once every
7 seconds, once every 30 seconds, etc.)
* Come up with your own technique of displaying time that
(a) is always 'close' to right, but (b) never allows a
watchful person to ever know exactly what time it is.
Things to Keep in Mind
---------------------------------------------------------------------
* You need to be able to handle the transition across hour/day
boundaries. (10:5~ might change to 11:0~ when the real time is still
10:58, or might continue to display 10:5~ when the real time is
11:04. On a 24-hour click, you also need to be able to wrap from
23:5~ to 00:0~)
* For testing purposes of the real-time #update advancing, you might
find it easier to work with minutes and seconds instead of hours and
minutes.
* Requirement #3 is, well, a requirement. Repeated #update/#to_s
calls to a FuzzyTime instance should never show an earlier time
(unless 24 hours occurred between #update calls ;).