[QUIZ] Morse Code (#121)

J

James Edward Gray II

I'd welcome any suggestion for making it more ruby-like.

Two simple things I noticed:

dotsanddashes.size == 0 # => dotsanddashes.empty?

try.gsub(/\./,'\.') # => Regexp.escape(try)

Just some thoughts.

Welcome to Ruby Quiz.

James Edward Gray II
 
P

Paul Novak

Thanks for another fun rubyquiz!

I don't think my solution has any unusual features, but I love it that
I could directly paste the mappings in from the problem description!

Regards,

Paul

#!/usr/bin/ruby
# a lazy way to convert pasted-on text from problem into a Hash

$morse = Hash[*%w{
A .- N -.
B -... O ---
C -.-. P .--.
D -.. Q --.-
E . R .-.
F ..-. S ...
G --. T -
H .... U ..-
I .. V ...-
J .--- W .--
K -.- X -..-
L .-.. Y -.--
M -- Z --.. }]

# convert dashes and dots to regexen to match each code at beginning
of line
# gotta love it when Ruby let's you convert documentation to code!
$morse.each_pair { |k,v| $morse[k] = Regexp.new("^(%s)(.*)" %
Regexp.escape(v))}

def parse(code, parsed_so_far)
if code==""
p parsed_so_far
else
$morse.each_pair do |k,v|
m = v.match( code).to_a
if m.length>0
parse(m[2], parsed_so_far + k)
end
end
end
end

parse(ARGV[0],"")
 
B

Bob Lisbonne

Here is a second, cleaned up version of my posting which benefits
from James Edward Gray's fine suggestions.
thanks,
/Bob

#!/usr/bin/env ruby -w
CW =
{'.-'=>'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 morse(dotsanddashes,letters)
if dotsanddashes.empty? then
puts letters
else
CW.keys.each do |try|
if /^#{Regexp.escape(try)}/.match(dotsanddashes) then
morse(dotsanddashes[$&.size,dotsanddashes.size],letters+ CW[$&])
end
end
end
end #morse
morse(STDIN.read.chomp,'')
 
J

Jesse Merriman

Here's a slight optimization to the each_translation method in my original
submission:

class String
# Yield once for each translation of this (Morse code) string.
def each_translation
split(//).each_grouping(MinCodeLength, MaxCodeLength) do |group|
valid = true
group.map! do |char_arr|
# Convert arrays of individual dots & dashes to strings, then translate.
letter = Decode[char_arr.join]
letter.nil? ? (valid = false; break) : letter
end
# Join all the translated letters into one string.
yield group.join if valid
end
end
end

Originally, I would translate every letter in a word, and then throw it out if
any failed to translate. This version breaks out of the map! as soon as any
letter fails, at the expense of two more variables and a few more LOC. I
expected this to speed it up quite a bit, but this test data shows only a
minor improvement for short code strings:

# (All times in seconds)
# Length, Original Time, New Time
0 0.112 0.113
1 0.110 0.109
2 0.106 0.108
3 0.106 0.106
4 0.106 0.106
5 0.108 0.107
6 0.121 0.119
7 0.123 0.121
8 0.125 0.124
9 0.132 0.130
10 0.146 0.145
11 0.188 0.187
12 0.259 0.253
13 0.403 0.390
14 0.713 0.668
15 1.313 1.221
16 2.513 2.342
17 4.959 4.597
18 9.885 9.146
19 19.671 18.208
20 38.729 35.972
21 78.767 71.431
22 159.931 145.794
23 319.763 294.711
24 636.660 590.360
25 1273.474 1169.021

These were all run with prefixes of '...---..-....--.--.-...-.'
The percentage improvement increases as the length of the code to translate
increases, as can be seen in this (noisy) plot:

http://www.jessemerriman.com/images/ruby_quiz/121_morse_code/new_vs_old.png

How far it goes down after that, I don't know, but my guess would be that
eventually it'd approach zero.
 
J

John W. Kennedy

Ken said:
Ruby Quiz said:
The three rules of Ruby Quiz:

1. Please do not post any solutions or spoiler discussion for this quiz until
48 hours have passed from the time on this message.

2. Support Ruby Quiz by submitting ideas as often as you can:

http://www.rubyquiz.com/

3. Enjoy!

Technically, I'm not breaking any rules in suggesting that the most
natural language for this problem is Prolog:

m('.-', a). m('-...', b). m('-.-.', c).
m('-..', d). m('.', e). m('..-.', f).
m('--.', g). m('....', h). m('..', i).
m('.---', j). m('-.-', k). m('.-..', l).
m('--', m). m('-.', n). m('---', o).
m('.--.', p). m('--.-', q). m('.-.', r).
m('...', s). m('-', t). m('..-', u).
m('...-', v). m('.--', w). m('-..-', x).
m('-.--', y). m('--..', z).


morse_decode(Text,Translation):-atom_chars(Text,List),
morse_i(List,TranslationList),
atom_chars(Translation,TranslationList).
morse_encode(Text,Translation):-
atom_chars(Translation,TranslationList),
morse_i(List,TranslationList),
atom_chars(Text,List).
morse_i([],[]).
morse_i(List,Translation):-m(First,Letter),atom_chars(First,FirstList),
append(FirstList,RestList,List),Translation=[Letter|RestTrans],
morse_i(RestList,RestTrans).

Examples of use:
morse_decode('...---...',X).
morse_decode('...---...',sos).
morse_encode(X,'sos').
morse_encode('...---...',sos).

I don't even know Prolog, and I can see that your code is horribly broken.
--
John W. Kennedy
"Only an idiot fights a war on two fronts. Only the heir to the throne
of the kingdom of idiots would fight a war on twelve fronts"
-- J. Michael Straczynski. "Babylon 5", "Ceremonies of Light and Dark"
* TagZilla 0.066 * http://tagzilla.mozdev.org
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top