Hi,

Here's my solution, finally.
Takes wanted time as argument 0 and variation as argument 1

Any suggestion on improving this welcome.

Cheers,
Dave

------------------------
KEY_WIDTH= 10
KEY_HEIGHT= 10

def get_pos (key)
   case key.to_s
     when '1'..'9': row, col= (key-1)/3, (key-1)%3
     when '0': row, col= 3,0
     when '*': row, col= 3,1
   end
   return row, col
end

def calc_dist (from_key, to_key)
   from_row, from_col= get_pos(from_key)
   to_row, to_col= get_pos(to_key)
   Math.sqrt((KEY_HEIGHT* (to_row- from_row))**2 +
     (KEY_WIDTH* (to_col- from_col))**2)
end

def total_dist (keys)
   return 0 if keys.size==0
   dist= 0
   keys.each_with_index do |key, i|
     dist+= calc_dist(keys[i-1], key) if i>0
   end
   dist
end

def mins_secs_to_keys(mins, secs)
   keys= []
   keys<< mins unless mins.zero?
   keys<< secs/ 10 unless mins.zero? and (secs/ 10).zero?
   keys<< secs% 10
   keys<< '*'
   keys
end

def time_to_candidates(seconds_wanted)
   mins= seconds_wanted/ 60
   secs= seconds_wanted% 60
   candidates= []
   candidates<< mins_secs_to_keys(mins, secs)
   candidates<< mins_secs_to_keys(mins- 1, secs+ 60) if mins.nonzero?  
and secs<40
   candidates
end

seconds= ARGV[0].to_i || 60
variation= ARGV[1].to_i || 0

combos=[]
(seconds- variation).upto(seconds+ variation) do |time|
   combos+= (time_to_candidates(time).map do|keys|
     {:keys => keys, :dist => total_dist(keys)}
   end)
end

print "Best keypad combination for #{seconds}+/-#{variation} seconds  
is "
puts combos.sort{|a, b| a[:dist] <=> b[:dist]}.first[:keys].join(" ")