Skip to content

Instantly share code, notes, and snippets.

@tom-galvin
Created May 5, 2015 12:57
Show Gist options
  • Save tom-galvin/e8503e28bafcb67c6535 to your computer and use it in GitHub Desktop.
Save tom-galvin/e8503e28bafcb67c6535 to your computer and use it in GitHub Desktop.
DailyProgrammer Challenge #213i Solution (The Lazy Typist)
class Keyboard
def initialize(rows)
@keys, @spaces, @shifts = {}, [], []
rows.each.with_index do |row, j|
row.each_char.with_index do |c, i|
unless c == '.'
@keys[c] = [] unless @keys[c]
@keys[c] << [i, j]
end
end
end
end
def closest(key, px, py)
@keys[key].sort_by {|(sx, sy)| (sx - px).abs + (sy - py).abs }.first
end
end
class Hand
attr_reader :effort, :keyboard, :name, :key
def initialize(keyboard, name, key)
@keyboard, @name = keyboard, name
@effort = 0
@key, @px, @py = key, *@keyboard.closest(key, 0, 0)
end
def effort_for(key)
kx, ky = @keyboard.closest(key, @px, @py)
(kx - @px).abs + (ky - @py).abs
end
def move_to(key)
kx, ky = @keyboard.closest(key, @px, @py)
de = (kx - @px).abs + (ky - @py).abs
@effort += de
@px, @py = kx, ky
@key = key
de
end
end
$kb = Keyboard.new(['qwertyuiop', 'asdfghjkl', '^zxcvbnm.^', '... '])
input = gets.chomp
hands, $available_hands = [], ['left', 'right']
def key_to_s(key)
{' ' => 'Space', '^' => 'Shift'}[key] || key.upcase
end
def move_to(hands, key, but_not=nil)
if $available_hands.empty?
possible_hands = but_not ? hands.reject {|hand| hand == but_not } : hands
possible_hands = hands if possible_hands.empty?
best_hand = possible_hands.min_by {|hand| hand.effort_for(key.downcase) }
if best_hand.key == key.downcase
puts "#{key_to_s(key)}: Use #{best_hand.name} hand again"
else
msg = "#{key_to_s(key)}: Move #{best_hand.name} hand from #{key_to_s(best_hand.key)}"
de = best_hand.move_to(key.downcase)
msg += " (effort: #{de})"
puts msg
best_hand
end
else
name = $available_hands.shift
puts "#{key_to_s(key)}: Use #{name} hand"
hands << Hand.new($kb, name, key.downcase)
end
end
input.each_char do |char|
(puts "Invalid character in input."; exit) unless char =~ /[A-Za-z ]/
end
while c = input.slice!(0)
if c =~ /[A-Z]/
used_hand = move_to(hands, '^')
else
used_hand = nil
end
used_hand = move_to(hands, c, used_hand)
end
puts "Total effort: #{hands.map {|hand| hand.effort }.reduce(0, :+)}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment