From: Robert Conn [mailto:bob.conn / btinternet.com] > I haven't had time to do any "extra credit" stuff, or > even test this fully, but here goes - For what it's worth, here's the test code I've written to test submissions. I'm not 100% sure that it's correctly testing things yet, but I think it is :) The interesting bit for me has been trying to identify any solution that ignores requirement #2, such as solutions that always show the correct time, or that are always a bit fast or slow. The statistics are my best attempt at that so far. To use, if you have defined your class name as "FuzzyTime", just include this file after your class definition. (Beware long incorrectly wrapped lines ahead.) require 'test/unit' $DEBUG = false class Time def short strftime("%H:%M") end def to_fuzzy s = short s[4] = "~" s end end class FuzzyTimeTester < Test::Unit::TestCase def test_running runs, num_ahead, num_behind = 0, 0, 0 20.times{ t = Time.at( Time.new + rand( 3600 * 300 ) ) advance_seconds = rand( 200 ) + 17 end_time = t + 60 * 60 * 24 ft = FuzzyTime.new( t ) last_value = nil while( t < end_time ) assert_equal t, ft.actual t0 = Time.at( t - 60 * 5 ) t2 = Time.at( t + 60 * 5 ) legal_values = [ t0, t, t2 ].map{ |x| x.to_fuzzy }.uniq if last_value y,mon,day = t.year, t.mon, t.day h,m = last_value.scan(/\d+/).map{ |s| s.to_i } m *= 10 if (m -= 10) < 0 m %= 60 if (h -= 1) < 0 h %= 24 end end illegal_old_value = Time.local( y,mon,day,h,m ).to_fuzzy legal_values -= [ illegal_old_value ] if $DEBUG puts "Now: #{t.short}; legal: #{legal_values.inspect} (was #{last_value}, can't be #{illegal_old_value})" end end s = ft.to_s assert legal_values.include?( s ), "#{s} not in #{legal_values.inspect}" a = t.to_fuzzy if s != a ahour, amin = a.scan( /\d+/ ).map{ |x| x.to_i } fhour, fmin = s.scan( /\d+/ ).map{ |x| x.to_i } if fmin > amin || fhour > ahour || ( fhour == 0 && ahour == 23 ) num_ahead += 1 else num_behind +=1 end end runs += 1 last_value = s ft.advance( advance_seconds ) t += advance_seconds end puts "Variation: %.2f%% ahead, %.2f%% behind" % [ 100.0 * num_ahead / runs, 100.0 * num_behind / runs ] } end end