r/dailyprogrammer • u/rya11111 3 1 • May 14 '12
[5/14/2012] Challenge #52 [difficult]
Your task is to write functions that encrypt and decrypt using the solitaire cipher.
18
Upvotes
2
0
May 14 '12
2
1
u/rya11111 May 14 '12
not again ... :( ... will try not to let this happen .. somehow i must have missed it ..
3
u/TweenageDream May 16 '12
Its not really optimized, so it could probably be shortened, i finished this pretty late last night. But it will key the deck with a pass phrase when you instantiate a new deck. Made some helper functions to put the strings in the right format, which i think it is still to picky about, but oh well.
Usage at the bottom, in Ruby:
class String def to_num arr = [] self.split(//).each do |c| if c == " " arr << c else arr << c.ord-64 end end arr.join(" ") end def to_let arr = [] self.split(" ").each do |c| if c == " " arr << c else arr << (c.to_i+64).chr end end arr.join("").split_5 end def split_5 message = self message = message.upcase.gsub(/[\s,*!.?]/,"") filler = "X"*(5 - (message.length % 5)) unless message.length % 5 == 0 message << filler.to_s # puts message (5..message.length-1).step(6).each{|i| message = message.insert(i," ")} message.strip end end class Deck def initialize(key=nil) @deck = Array.new(54){|i| i+1 } @output_card = nil @JOKER_A = 53 @JOKER_B = 54 key_deck(key) unless key.nil? end def key_deck(key) key.length.times do |idx| all(key[idx].upcase.ord-64) end end def move_a i1 = @deck.index(@JOKER_A) @deck.delete_at(i1) @deck.insert((i1+1)%(@deck.length+1),@JOKER_A) end def move_b i1 = @deck.index(@JOKER_B) @deck.delete_at(i1) loc = (i1+2)%(@deck.length) if loc != 0 @deck.insert(loc,@JOKER_B) else @deck << @JOKER_B end end def triple_cut i1 = @deck.index(@JOKER_A) i2 = @deck.index(@JOKER_B) i1, i2 = i2, i1 if i2 < i1 above = @deck.slice(0..i1-1) unless i1 == 0 below = @deck.slice(i2+1,@deck.length-(i2+1)) @deck = (@deck - above.to_a) - below.to_a @deck = below + @deck unless below.nil? @deck = @deck + above unless above.nil? end def count_cut(offset=nil) count = @deck[-1] count = offset unless offset.nil? count -= 1 if count == 54 above = @deck.slice!(0,count.to_i) bottom = @deck.slice!(-1) @deck = @deck + above << bottom count = @deck[0] count -= 1 if count == 54 @output_card = @deck[count] @output_card = all() if @output_card == 53 or @output_card == 54 @output_card end def all(offset=nil) move_a() move_b() triple_cut() ret = count_cut() ret = count_cut(offset) unless offset.nil? return ret end def print puts "#{@deck}" end def out_let ret = @output_card ret = @output_card - 26 if ret > 26 return (ret+64).chr end def out @output_card end end def encrypt(m,key) m = m.split_5.to_num.split(" ") key = key.split_5.to_num.split(" ") encrypted = [] m.each_with_index do |c,idx| ret = (c.to_i+key[idx].to_i) ret -= 26 if ret > 26 encrypted << ret end encrypted.join(" ").to_let.split_5 end def decrypt(c,key) c = c.split_5.to_num.split(" ") key = key.split_5.to_num.split(" ") decrypted = [] c.each_with_index do |l,idx| ret = (l.to_i-key[idx].to_i) ret += 26 if ret < 1 decrypted << ret end decrypted.join(" ").to_let.split_5 end def get_key(message,d) key = [] message.split_5.gsub(/\s/,"").length.times do d.all key << d.out_let end key.join("").split_5 end d = Deck::new("CRYPTONOMICON") m = "BEWARETHEREAREZOMBIESAFOOT" k = get_key(m,d) e = encrypt(m,k) d = decrypt(e,k) puts e puts doutput:
Key: CRYPTONOMICON
Message BEWARETHEREAREZOMBIESAFOOT
Encrypted: TYCSI WQZAH VMOSG WBCNT PAWME CIDDH
Decrypted: BEWAR ETHER EAREZ OMBIE SAFOO TXXXX