Re: Fuzzy Time (#99)

Following is my (very late, but short) submission.

I first attempted to be really tricky about the time distribution in a
variety of ways (which I’ll mention in the Summary), but found that the
following code gave pretty good results (which you’ll see in the
upcoming results email).

class Time
def round_to( seconds )
seconds = seconds.round
Time.at( self.to_i / seconds * seconds )
end
end

class FuzzyTime
FIVE_MINS = 5 * 60
TEN_MINS = 10 * 60
attr_reader :actual
def initialize( start_time=Time.new )
@last_fuzzy = @actual = @fuzzy = start_time
end

def update
now = Time.new
elapsed = now - ( @last_update || now )
advance( elapsed )
@last_update = now
end

def advance( seconds_forward )
@actual += seconds_forward

# Randomly move forward, centered around the desired seconds
@fuzzy += seconds_forward * 2 if rand < 0.5

# Ensure the fuzzy time is within legal bounds
overshoot = @fuzzy - @actual
if overshoot > FIVE_MINS
  @fuzzy = @actual + FIVE_MINS
elsif overshoot < -FIVE_MINS
  @fuzzy = @actual - FIVE_MINS
end

# Ensure that the fuzzy time is not less than the last *displayed*
if @fuzzy.round_to( TEN_MINS ) < @last_fuzzy.round_to( TEN_MINS )
  if $DEBUG
    puts "It is #{@actual.short}; " +
       "I wanted to show #{@fuzzy.short} (#{@fuzzy.to_fuzzy})," +
       " but I last showed " +
       "#{@last_fuzzy.short} (#{@last_fuzzy.to_fuzzy})"
  end
  @fuzzy = @last_fuzzy
end

end

def to_s
# only record the last displayed time, to allow backtracking
# as often as possible
@last_fuzzy = @fuzzy
s = @fuzzy.strftime("%H:%M")
s[4] = “~”
s
end

end