Mar 22 2010
Morse Code Translator in Ruby
I got a challenge from my friend Kim to solve a programming problem they give new hire candidates. Basically, the problem is to build something that takes a string of Morse code and returns all possible translations for it. I did my solution in Ruby. This is pretty much a first pass, so comments are appreciated. This is, I think, the first time I’ve ever solved a problem with recursion when I wasn’t specifically told “use recursion” for an assignment.
def morse_code()
morse = {'a' => '.-',
'b' => '-...',
'c' => '-.-.',
'd' =>'-..',
'e' => '.',
'f' => '..-.',
'g' => '--.',
'h' => '....',
'i' => '..',
'j' => '.---',
'k' => '-.-',
'l' => '.-..',
'm' => '--',
'n' => '-.',
'o' => '---',
'p' => '.--.',
'q' => '--.-',
'r' => '.-.',
's' => '...',
't' => '-',
'u' => '..-',
'v' => '...-',
'w' => '.--',
'x' => '-..-',
'y' => '-.--',
'z' => '--..'}
# This is a hack; I reversed the hash when I typed it and didn't want to retype
# just for a proof of concept
morse.invert
end
def read_morse_code(input, morse)
# Initialize some arrays
code_matches = Array.new
matches = Array.new
translation_list = Array.new
# If we've been passed a nil input, it's at the end of the search.
# Return an empty array
if input.nil?
return translation_list << ''
end
# Collect any matches with the morse code at the start of the string
# and delete the nils; the collect block returns nil values when there's no match
code_matches = morse.collect {|code, letter| input.match('^' + Regexp.escape(code))}
code_matches.delete(nil)
code_matches.each do |code_match|
temp_input = String.new(input)
if temp_input == code_match.to_s
translation_list << morse[code_match.to_s]
else
matches = read_morse_code(temp_input.gsub!(Regexp.new('^' + Regexp.escape(code_match.to_s)), ''), morse)
# Stick each match into the translation_list
matches.each do |match|
translation_list << morse[code_match.to_s] + match
end
end
end
# Remove any nil matches and return what we've got
translation_list.delete(nil)
return translation_list
end
# Grab the morse_code hash
morse = morse_code
translations = read_morse_code(String.new(ARGV[0]), morse)
translations.each do |translation|
puts translation
end