Fwd: Morse Code (#121)

Begin forwarded message:

Below is my first solution to this quiz.

http://pastie.caboo.se/55736

  • donald

Ruby Q. 121

Donald A. Ball Jr.

Version 1.0

class Morse

CODES = {
:A => ‘.-’,
:N => ‘-.’,
:B => ‘-…’,
:open_mouth: => ‘—’,
:C => ‘-.-.’,
:stuck_out_tongue: => ‘.–.’,
:smiley: => ‘-…’,
:Q => ‘–.-’,
:E => ‘.’,
:R => ‘.-.’,
:F => ‘…-.’,
:S => ‘…’,
:G => ‘–.’,
:T => ‘-’,
:H => ‘…’,
:U => ‘…-’,
:I => ‘…’,
:V => ‘…-’,
:J => ‘.—’,
:W => ‘.–’,
:K => ‘-.-’,
:X => ‘-…-’,
:L => ‘.-…’,
:Y => ‘-.–’,
:M => ‘–’,
:Z => ‘–…’
}

LETTERS = CODES.invert

def self.translate(cipher)
results = []
LETTERS.each_pair do |code, letter|
next unless cipher.slice(0, code.length) == code
if cipher.length == code.length
results << letter.to_s
else
translate(cipher.slice(code.length, cipher.length)).each do
|result|
results << (letter.to_s << result)
end
end
end
results
end

end

Morse.translate(ARGV[0]).each{|word| puts word}

Below is my second solution.

http://pastie.caboo.se/55742

  • donald

Ruby Q. 121

Donald A. Ball Jr.

Version 1.1

class String
def split_at(index)
[slice(0, index), slice(index, length)]
end
end

class Morse

CODES = {
:A => ‘.-’,
:B => ‘-…’,
:C => ‘-.-.’,
:smiley: => ‘-…’,
:E => ‘.’,
:F => ‘…-.’,
:G => ‘–.’,
:H => ‘…’,
:I => ‘…’,
:J => ‘.—’,
:K => ‘-.-’,
:L => ‘.-…’,
:M => ‘–’,
:N => ‘-.’,
:open_mouth: => ‘—’,
:stuck_out_tongue: => ‘.–.’,
:Q => ‘–.-’,
:R => ‘.-.’,
:S => ‘…’,
:T => ‘-’,
:U => ‘…-’,
:V => ‘…-’,
:W => ‘.–’,
:X => ‘-…-’,
:Y => ‘-.–’,
:Z => ‘–…’
}

def self.decipher(cipher)
CODES.each_pair do |letter, code|
prefix, suffix = cipher.split_at(code.length)
next unless prefix == code
if suffix == ‘’
yield letter.to_s
else
decipher(suffix) {|result| yield letter.to_s << result }
end
end
end

end

Morse.decipher(ARGV[0]) {|word| puts word}

Here’s my solution to Ruby Q. #121.

Jim Barnett

#!/usr/bin/env ruby

class MorseCode
attr_accessor :results
attr_reader :words

Alphabet = {
‘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’ => ‘–…’
}

def initialize
@results = []
@words = []
@words << load_dictionary
end

def to_text(input, output = “”, words = @words)
unless input.empty?
m = matches(input)
m.each do |char|
to_text(input[Alphabet[char].length, input.length], output +
char)
end
else
@results << output
end
end

def matches(input)
Alphabet.select { |key, value| input[0, value.length] ==
value }.map { |v| v.first }.sort
end

def load_dictionary
# dictionary.txt from
http://java.sun.com/docs/books/tutorial/collections/interfaces/examples/dictionary.txt
File.open(“dictionary.txt”, “r”) do |file|
file.each_line do |line|
@words << line.chomp.upcase if line
end
end
@words << ‘SOFIA’
@words << ‘EUGENIA’
end

def in_dictionary?(str)
@words.include?(str)
end
end

$mc = MorseCode.new
$mc.to_text(ARGV[0])
$mc.results.each { |r| puts “#{r} #{ $mc.in_dictionary?(r) ? “(in
dictionary)” : “” }” }

On 4/22/07, Ball, Donald A Jr (Library) [email protected]
wrote:

end

end

end

Morse.decipher(ARGV[0]) {|word| puts word}

That’s pretty much what I did (as well as some others) but yours is
much more elegant. I didn’t really think about using a block with the
recursion. Cool.

That’s pretty much what I did (as well as some others) but yours is
much more elegant. I didn’t really think about using a block with the
recursion. Cool.

Thanks. That’s actually the first time I’ve written code that yields.
It’s actually bit unclear to me as to when it’s better to return results
and when it’s better to yield them. I guess the best thing to do would
be to check, what is it, block_given? and either yield or collect the
results as appropriate. Do more advanced rubyists have any guidance to
offer in this regard?

  • donald

On Apr 22, 2007, at 9:35 PM, Ball, Donald A Jr (Library) wrote:

That’s pretty much what I did (as well as some others) but yours is
much more elegant. I didn’t really think about using a block with the
recursion. Cool.

Thanks. That’s actually the first time I’ve written code that
yields. It’s actually bit unclear to me as to when it’s better to
return results and when it’s better to yield them. I guess the best
thing to do would be to check, what is it, block_given? and either
yield or collect the results as appropriate. Do more advanced
rubyists have any guidance to offer in this regard?

I prefer to yield whenever you don’t need a full set of results to do
something useful. This means I don’t have to aggregate results,
which saves memory. It also means the calling code gets answers as
soon as they are available. Plus, if that calling code really wanted
to fill an Array with the results they can certainly do that.
Basically, it gives the caller more choices.

James Edward G. II

On Apr 22, 2007, at 1:03 PM, James Edward G. II wrote:

Begin forwarded message:

From: “Jesús Gabriel y Galán” [email protected]
Date: April 21, 2007 5:01:15 PM CDT
To: [email protected]
Subject: Re: [QUIZ] Morse Code (#121)

Also, I’m fairly new to Ruby, only programming little things to
learn,
but nothing serious. So I’d appreciate any feedback you have on my
Ruby.

Some minor suggestions:

  • Drop the parentheses on if/while statement conditions
  • while !queue.empty? could be until queue.empty?
  • This bit of code:

sorted_keys = letters.keys.sort_by {|x| x.length}
min_length = sorted_keys[0].length
max_length = sorted_keys[-1].length

could be:

min_length = letters.keys.min {|a,b| a.length <=> b.length }
max_length = letters.keys.max {|a,b| a.length <=> b.length }

or:

min_length, max_length = letters.keys.sort_by {|x| x.length}.values_at
(0, -1)

Just some thoughts.

Welcome to Ruby.

James Edward G. II

On 4/23/07, James Edward G. II [email protected] wrote:

From: “Jesús Gabriel y Galán” [email protected]

or:

min_length, max_length = letters.keys.sort_by {|x| x.length}.values_at
(0, -1)

Just some thoughts.

In fact, I have done a modification to my version, to generalize that
thing: instead of assuming we have keys from min to max I actually get
an array with all the possible key lengths with:

key_lengths = letters.keys.map {|x| x.length}.uniq

and then modify the min_length.upto(up_to) with key_lengths.each

which optimizes the loop for arbitrary key lengths… but haven’t been
able to test my code yet.

Welcome to Ruby.

Thanks, I’m in complete love with the language, and the community is
great. Ruby Q. is a great tool to learn.

Jesus.