1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
$LETTER = 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 --.. /] $CODE = $LETTER.invert def encode(message) encoded_message = [] words = message.split(" ") words.each do |word| encoded_word = "" word.split(//).each do |letter| if $LETTER.has_key?(letter.upcase) encoded_word << $LETTER[letter.upcase] encoded_word << " " end end encoded_message << encoded_word end puts encoded_message.join("| ") end def decode(message) decoded_message = "" words = message.split("|") words.each do |word| word.split(/\s/).each do |letter| if $CODE.has_key?(letter) decoded_message << $CODE[letter] end end decoded_message << " " end puts decoded_message end def encode_file(f) File.open(f).each do |line| encode(line) end end def decode_file(f) File.open(f).each do |line| decode(line) end end
Refactorings
No refactoring yet !
Adam
September 29, 2008, September 29, 2008 18:51, permalink
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
module Morse CODES = 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 --.. \ | /] def self.file_helper(method) module_eval %{ def self.#{method}_file(filename) File.readlines(filename).map { |line| #{method}(line) }.join("\n") end } end def self.encode(message) message.upcase.split(//).map { |char| CODES[char] }.join(' ') end file_helper :encode def self.decode(message) message.split(' ').map { |code| CODES.invert[code] }.join end file_helper :decode end
Druwerd
September 30, 2008, September 30, 2008 00:36, permalink
Thanks Adam.
This is very helpful. Looks concise and elegant.
Magnus Holm
October 1, 2008, October 01, 2008 12:49, permalink
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
module Morse;A=[19,189,192,63,6,165,66,162,18,175,64,171,22,21,67,174,199,57, 54,7,55,163,58,190,193,198];B=proc{|c|A[c-65].to_s(3)[1..-1].tr('10','-.')} C=proc{|m|(A.index(("2"+m.tr('-.','10')).to_i(3))||return)+65} def self.encode(str);str.upcase.split(//).map{|c|(65.. 90)===(c=c[0])?B[c]:c==32?'|':nil}.compact.join(' ') end def self.decode(str);str.split(' ').map{|m|m[0]==?|?' ':(m=C[m])&&m.chr}.join end self.methods(false).map{|m|class<<self;self;end.send(:define_method,m+"_file" ){|f|File.readlines(f).map{|l|send(m,l)}.join $/}} end # >> Morse.encode("Concise and elegant") # => "-.-. --- -. -.-. .. ... . | .- -. -.. | . .-.. . --. .- -. -" # >> Morse.decode("-.-. --- -. -.-. .. ... . | .- -. -.. | . .-.. . --. .- -. -") # => "CONCISE AND ELEGANT" # >> Morse.encode_file("somefile.txt") # >> Morse.decode_file("somefile.txt")
Druwerd
October 1, 2008, October 01, 2008 18:45, permalink
Magnus,
I don't understand your approach at all, but it sure looks concise!
Could you explain how it works?
lel
October 18, 2008, October 18, 2008 15:25, permalink
Juggling ascii-numbers, base 3 and single letter constant names? Is this "obfuscatemycode.com" :-)
1 2 3 4 5 6 7 8 9
# The idea is that each morse code is encoded as a number: # "a" is mapped to 19, which in base 3 is 201, the 2 works as a dummy to keep leading 0's in place, so the real value is "01" which maps to the morse code ".-" # "b" is mapped to 189, which in base 3 is 21000, remove the 2 and the real value is "1000" which maps to the mores code "-..." # and so on. # # I don't see why not, but the codes could have been encoded in base 2 as well: # "a" would map to 5, which in base 2 is "101", the first digit is always a dummy, so the real value is "01" which maps to ".-" # "b" would map to 24, which in base 2 is "11000", skip the first digit and we get "1000" which maps to "-..." #
Magnus Holm
October 19, 2008, October 19, 2008 18:28, permalink
lel: You're absolutely right. This can be solved in a much simpler way:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
module Morse A,B,C=proc{M.tr(' ','').gsub(/#{$/}+/,$/).split($/).map{|x| x[/(.)(.+)(.).*\1\2\3/,2].to_i(16)}},proc{|c|A[][c-65].to_s(2 )[1..-1].tr('10','-.')},proc{|m|(A[].index(("1"+m.tr( '-.','10')).to_i(2))||return)+65} def self.encode(str) str.upcase.split(//).map{|c|(65..90)=== (c=c[0])?B[c]:c==32?'|':nil}.compact.join(' ') end def self.decode(str) str.split(' ').map{|m|m[0]==?|?' ':(m=C[m])&&m.chr}.join end self.methods(false). map{|m|class<<self;self;end. send(:define_method,m+"_file"){|f| File.readlines(f).map{|l|send(m,l)}.join $/}} M = <<-'LETS GO MORSING!' 3DC5D1BBFBE596573E0EE011500C2959ED1469891C5D9120EA8 D18A6BF9C806A8A15A77A5788575BD18A0233578435B20884FE A1AAAAAA1AA BCD BCD 123 123 412C127 140C127 87EB9557EB757 7103B03517D082301871039DD318B6ABEB04981 2A44EFBD92A0B694FE1ECC094F42E7F7DF37AF7 9781 765A3C96E24326A0F58 1764 2D3C 3399D0D588D492D 3A95 AB74 D14522116D1 45E3 6833 7 A807B37 A F32E BD57 4F C61 EC 613F 07EF 733E F 7DEA 540F E285 04F691 656291 6595 85EC 1D8343A C1D82A1 9F95 F5A3 7F8D02D25A357BEDC75 4958 86C8 61F6679FFEB2DF19CEC 8673 0706 DC3C81C810CBEBA76FC CC3C 32B7 91791ADFE02C7664F6E 7D51 1111 656B15AA24FF66461FD 1111 0BD60F270C533AE418A5A99E65950BD26D003CF 1BC023CDEBA3CE19D0CF7E0B50607C7E19DD396 11B878DCDAEAE1AE136657420A26AF87356FCD6DA11B80CDD4F 22C2201C00354CD948A67CAAA92566A7E4515CAADADC8FA01C0 LETS GO MORSING! end
I'm trying to improve my Ruby skills. I wrote this as an exercise. I would like some suggestions on making this cleaner.