```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(" ")

```