Here is my script. This is my first entry to Ruby Quiz.

I wanted this FuzzyTime to support random access so you can do this:

ft = FuzzyTime.new; puts ft
=> 17:5~
ft = FuzzyTime.set(Time.now+4.hours); puts ft
=> 22:0~
ft = FuzzyTime.set(Time.now+10.minutes); puts ft
=> 18:1~
ft = FuzzyTime.set(Time.now); puts ft
=> 17:5~

Also, I added a 'rewind' method for symmetry with 'advance' (although 
you cannot rewind to before the time FuzzyTime was initialized with). 
Now 'update' adds to the internal time based on how long since you last 
called one of 'initialize', 'advance', 'rewind', 'update' or 'set'.

Other than ensuring that the transition occurs randomly for each ten 
minute block, I didn't implement any of the extra credit options.

-Dan Lucraft
___________________________________________________

# handy stuff...
require 
'/home/dan/gems/activesupport-1.3.1/lib/active_support/core_ext/numeric'
require 
'/home/dan/gems/activesupport-1.3.1/lib/active_support/core_ext/time'

class FuzzyTime
  def initialize(time=Time.now)
    # we record the start time as it's used to reset the random number 
generator
    # every time we fuzzify a time
    @start_time = time

    time_mins = (time - time.beginning_of_day).to_i/60
    hours = time_mins/60
    mins = time_mins-(hours*60)
    tens = mins/10
    @time_of_nearest_ten_before_start = time_mins - mins + (tens*10) -5

    @internal_time = time
    @last_called = time
  end

  def actual
    @internal_time
  end

  def advance(secs)
    @internal_time += secs
    @last_called = Time.now
  end

  def rewind(secs)
    @internal_time -= secs
    check_valid
    @last_called = Time.now
  end

  def update
    @internal_time += Time.now - @last_called
    check_valid
    @last_called = Time.now
  end


  def set(time=Time.now)
    @internal_time = time
    check_valid
    @last_called = Time.now
  end

  # this fuzzifies the current internal time.
  def to_s
    # run through random numbers for the number of 10 minute blocks 
since the
    # start time, and keep the last one (switch_val)
    time_mins = ((@internal_time - 
@start_time.beginning_of_day).to_i)/60
    distance = time_mins - @time_of_nearest_ten_before_start
    Kernel.srand(@start_time.to_i)
    switch_val = nil
    ((distance/10)+1).to_i.times do
      switch_val = rand(10)
    end

    # the kept random number is where in the 10 minute interval around
    # the current time that the fuzzy time switches from low to high
    # E.g.
    # current time 9:12
    # interval around current time: [9:05, 9:15]
    # a switch_val of 3 means that we go from 9:0~ to 9:1~ at 9:08
    # NB we always get the same switch_val for this ten-minute block,
    # since we are resetting the generator and counting the correct 
number
    # of random numbers in. This is what allows random access.
    # marginal_mins is 7 in this case. (9:12-9:05)
    marginal_mins = distance - (10*(distance/10))
    if marginal_mins >= switch_val and marginal_mins >= 5
      near_time(@internal_time, :below)
    elsif marginal_mins >= switch_val and marginal_mins < 5
      near_time(@internal_time, :above)
    elsif marginal_mins < switch_val and marginal_mins >= 5
      near_time(@internal_time-10.minutes, :below)
    elsif marginal_mins < switch_val and marginal_mins < 5
      near_time(@internal_time, :below)
    end
  end

  def near_time(time, type)
    time = (time - time.beginning_of_day).to_i
    hour = time/3600
    fuzzy_min = ((time - (hour*3600))/60)/10
    fuzzy_min += 1 if type == :above
    (fuzzy_min = 0 and hour += 1) if fuzzy_min == 6
    hour = 0 if hour == 24
    if hour >= 10
      "#{hour}:#{fuzzy_min}~"
    else
      "0#{hour}:#{fuzzy_min}~"
    end
  end

  def check_valid
    if @internal_time < @start_time
      raise Exception, "Rewound past start of FuzzyTime."
    end
  end
end

if __FILE__ == $0
  ft = FuzzyTime.new
  puts ft
  step = ARGV[0].to_i || 60
  while(true)
    sleep step
    ft.advance 60
    puts ft
  end
end

-- 
Posted via http://www.ruby-forum.com/.