# Fwd: Morse Code (#121)

**URL:** <https://www.ruby-forum.com/t/fwd-morse-code-121/229112>\
**Category:** Ruby\
**Created:** [April 22, 2007, 8:04pm UTC](https://www.ruby-forum.com/t/fwd-morse-code-121/229112 "2007-04-22T20:04:30Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![bbazzarrakk](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/47e85d/32.png) [@bbazzarrakk](https://www.ruby-forum.com/u/bbazzarrakk)\
**Post date:** [April 22, 2007, 8:04pm UTC](https://www.ruby-forum.com/t/fwd-morse-code-121/229112/1 "2007-04-22T20:04:30Z")

</div>

Begin forwarded message:

---

<div class="post-metadata">

**Author:** ![bbazzarrakk](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/47e85d/32.png) [@bbazzarrakk](https://www.ruby-forum.com/u/bbazzarrakk)\
**Post date:** [April 22, 2007, 8:12pm UTC](https://www.ruby-forum.com/t/fwd-morse-code-121/229112/2 "2007-04-22T20:12:30Z")

</div>

Below is my first solution to this quiz.

[http://pastie.caboo.se/55736](http://pastie.caboo.se/55736)

- donald

# Ruby Q. 121

# Donald A. Ball Jr.

# Version 1.0

class Morse

CODES = {  
:A =\> ‘.-’,  
:N =\> ‘-.’,  
:B =\> ‘-…’,  
😮 =\> ‘—’,  
:C =\> ‘-.-.’,  
😛 =\> ‘.–.’,  
😃 =\> ‘-…’,  
: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}

---

<div class="post-metadata">

**Author:** ![bbazzarrakk](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/47e85d/32.png) [@bbazzarrakk](https://www.ruby-forum.com/u/bbazzarrakk)\
**Post date:** [April 22, 2007, 9:02pm UTC](https://www.ruby-forum.com/t/fwd-morse-code-121/229112/3 "2007-04-22T21:02:34Z")

</div>

Below is my second solution.

[http://pastie.caboo.se/55742](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 =\> ‘-.-.’,  
😃 =\> ‘-…’,  
:E =\> ‘.’,  
:F =\> ‘…-.’,  
:G =\> ‘–.’,  
:H =\> ‘…’,  
:I =\> ‘…’,  
:J =\> ‘.—’,  
:K =\> ‘-.-’,  
:L =\> ‘.-…’,  
:M =\> ‘–’,  
:N =\> ‘-.’,  
😮 =\> ‘—’,  
😛 =\> ‘.–.’,  
: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}

---

<div class="post-metadata">

**Author:** ![bbazzarrakk](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/47e85d/32.png) [@bbazzarrakk](https://www.ruby-forum.com/u/bbazzarrakk)\
**Post date:** [April 23, 2007, 12:11am UTC](https://www.ruby-forum.com/t/fwd-morse-code-121/229112/4 "2007-04-23T00:11:00Z")

</div>

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](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)” : “” }” }

---

<div class="post-metadata">

**Author:** ![bbazzarrakk](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/47e85d/32.png) [@bbazzarrakk](https://www.ruby-forum.com/u/bbazzarrakk)\
**Post date:** [April 23, 2007, 12:15am UTC](https://www.ruby-forum.com/t/fwd-morse-code-121/229112/5 "2007-04-23T00:15:02Z")

</div>

On 4/22/07, Ball, Donald A Jr (Library) [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
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.

---

<div class="post-metadata">

**Author:** ![bbazzarrakk](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/47e85d/32.png) [@bbazzarrakk](https://www.ruby-forum.com/u/bbazzarrakk)\
**Post date:** [April 23, 2007, 4:36am UTC](https://www.ruby-forum.com/t/fwd-morse-code-121/229112/6 "2007-04-23T04:36:18Z")

</div>

> 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

---

<div class="post-metadata">

**Author:** ![bbazzarrakk](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/47e85d/32.png) [@bbazzarrakk](https://www.ruby-forum.com/u/bbazzarrakk)\
**Post date:** [April 23, 2007, 3:18pm UTC](https://www.ruby-forum.com/t/fwd-morse-code-121/229112/7 "2007-04-23T15:18:06Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![bbazzarrakk](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/47e85d/32.png) [@bbazzarrakk](https://www.ruby-forum.com/u/bbazzarrakk)\
**Post date:** [April 23, 2007, 3:29pm UTC](https://www.ruby-forum.com/t/fwd-morse-code-121/229112/8 "2007-04-23T15:29:08Z")

</div>

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

> Begin forwarded message:
> 
> > From: “Jesús Gabriel y Galán” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
> > Date: April 21, 2007 5:01:15 PM CDT  
> > To: removed\_email\_address@domain.invalid  
> > 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

---

<div class="post-metadata">

**Author:** ![bbazzarrakk](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/47e85d/32.png) [@bbazzarrakk](https://www.ruby-forum.com/u/bbazzarrakk)\
**Post date:** [April 23, 2007, 3:42pm UTC](https://www.ruby-forum.com/t/fwd-morse-code-121/229112/9 "2007-04-23T15:42:12Z")

</div>

On 4/23/07, James Edward G. II [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > > From: “Jesús Gabriel y Galán” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

> 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.
