Thanks for the test and the quiz. Writing a solution wasn't very hard, but coming up with a good way to keep the time from drifting ahead and had good 'fuzziness', quantifying what made a good fuzzy time and then testing different approaches was the interesting part. An approach I took to test the fuzziness of my FuzzyTime class was track the number of minutes the fuzzy time remained the same, advancing one minute at a time, and then calculate the mean and variance of that set of numbers, with the idea that a good fuzzy time would have a mean change interval close to 10 minutes but with a large variance. That would also snag solutions that always displayed the correct time plus solutions that were always ahead or behind by a fixed amount: there would be no variance to the intervals. (It would also be good to see different results each time it's run) A unit test for that is after my solution. In my approach, when a time is asked for, it computes a time that is +/- 5 minutes from the actual time, keeping a low water mark that is the last displayed time or 5 mintes from the actual time, whatever is greater. There is a strong bias not to advance the time, correcting for the tendancy for the time to drift ahead. This is what my solution got running your test: Variation: 10.37% ahead, 20.75% behind Variation: 13.73% ahead, 8.39% behind Variation: 13.46% ahead, 10.64% behind Variation: 13.16% ahead, 10.72% behind Variation: 13.27% ahead, 11.64% behind Variation: 13.96% ahead, 9.06% behind Variation: 13.76% ahead, 9.87% behind Variation: 13.43% ahead, 10.57% behind Variation: 13.69% ahead, 8.77% behind Variation: 13.54% ahead, 9.18% behind Variation: 13.18% ahead, 9.73% behind Variation: 13.11% ahead, 10.15% behind Variation: 13.00% ahead, 10.67% behind Variation: 13.00% ahead, 10.30% behind Variation: 12.92% ahead, 10.57% behind Variation: 12.64% ahead, 10.80% behind Variation: 12.64% ahead, 11.07% behind Variation: 12.52% ahead, 10.94% behind Variation: 12.39% ahead, 11.28% behind Variation: 12.33% ahead, 11.49% behind And means and variances: Mean interval: 9.02446115288221 Variance: 3.07336219244858 As for the solution: ---- FuzzyTime.rb # Fuzzy Time class that reports a time that is always within a given # slop factor to the real time. The user specifies the amount of # fuzzyiness to the time and the display obscures the minutes field. # # This class works by maintaining the actual time it represents, and # calculating a new fuzzy time whenever it is asked to display the # fuzzy time. It keeps a low water mark so an earlier time is never # displayed. # class FuzzyTime # Initialize this object with a known time and a number of minutes # to randomly vary # # time -> initial time # fuzzy_minutes -> number of minutes to randomly vary time def initialize(time=Time.now, fuzzy_minutes=5) @fuzzy_factor = fuzzy_minutes @current_time = time set_low_water_mark set_updated end # Print the fuzzy time in a format obscuring the last number of the # time. def to_s ft = fuzzy_time s = ft.strftime("%H:%M") s[4] = '~' s end # Manually advance time by a certain number of seconds. Seconds # cannot be negative # # seconds -> number of seconds to advance. Will throw exception # if negative def advance(seconds) raise "advance: seconds cannot be negative" if seconds < 0 @current_time = @current_time + seconds set_updated end # Update the current time with the number of seconds that has # elapsed since the last time this method was called def update @current_time = @current_time + update_interval set_updated end # Reports real time as Time def actual @current_time end private # sets the current low water mark. This is so the fuzzy time never # goes backwards def set_low_water_mark @low_water_mark = @current_time - (@fuzzy_factor*60) end # Updates the last time initialize, advance or update was called def set_updated @last_updated = Time.now end # Gets the number of seconds since the last update def update_interval Time.now - @last_updated end # Sets fuzzy time to be +/- the fuzzy factor from the current time, # while ensuring that we never return an earlier time than the one # returned last time we were called. def fuzzy_time fuzzy_seconds = @fuzzy_factor * 60 # Raise the low watermark if it is lower than allowed, if we # advanced by a huge degree, etc. @low_water_mark = [@low_water_mark, @current_time - fuzzy_seconds].max # Compute a new random time, and set it to be the fuzzy time if # it is higher than the low water mark. The algorithm is biased # to return a negative time. This is to compensate for the low # water mark. We want the time to be behind as much as it is # ahead. At least 60 percent of the time the time will not # advance here. random_time = @current_time + (rand(fuzzy_seconds*5) - fuzzy_seconds*4) fuzzy_time = [@low_water_mark, random_time].max # Update the low water mark if necessary @low_water_mark = [@low_water_mark, fuzzy_time].max fuzzy_time end end ----- The unit test to calculate means and variances: ----- FuzzyTimeTest.rb require 'FuzzyTime' class FuzzyTimeTest < Test::Unit::TestCase # Advances the fuzzy time by one minute repeatedly, keeping track # of how many minutes it took to go to the next time on the clock. # Calculates mean and variance to see if the intervals center # around 10 minutes and how much they vary from the mean. We want # the average to hover close to 10 minutes and the variance to be # as large as possible. def test_intervals ft = FuzzyTime.new last_time = nil fuzzy_interval = 0 intervals = Array.new 100000.times do ft.advance 60 fuzzy_time = ft.to_s if last_time.nil? || last_time == fuzzy_time fuzzy_interval += 1 else intervals.push fuzzy_interval fuzzy_interval = 0 end last_time = fuzzy_time end average = intervals.inject {|sum,val| sum + val }.to_f / intervals.length puts "Mean interval: #{average}" variance = intervals.inject {|sum, val| sum+(val-average).abs}.to_f / intervals.length puts "Variance: #{variance}" end end