tags:

views:

337

answers:

1

Hello, ancient cryptography being one of my hobbies thanks to David Kahn's book The Codebreakers, I'm trying implement in Ruby classes to handle old ciphers such as the Nihilist cipher and ADFGVX. For these, one useful item is the Straddling checkboard. I have the following implementation in Ruby and would welcome any improvement.

class Key is the base class (a virtual class if you want). Key#condensed is a method that remove duplicated letters from a given word.

class SKey < Key
  attr_reader :full_key
  attr_reader :alpha, :ralpha

  def initialize(key)
    super(key)
    @alpha = Hash.new
    @ralpha = Hash.new
    @full_key = checkboard()
    gen_rings()
  end

  # === checkboard
  #
  # Shuffle the alphabet a bit to avoid sequential allocation of the
  # code numbers
  #
  # Regular rectangle
  # -----------------
  # Key is ARABESQUE condensed into ARBESQU (len = 7) (height = 4)
  # Let word be ARBESQUCDFGHIJKLMNOPTVWXYZ/-
  #
  # First passes will generate
  #
  # A  RBESQUCDFGHIJKLMNOPTVWXYZ/-   c=0  0 x 6
  # AC  RBESQUDFGHIJKLMNOPTVWXYZ/-   c=6  1 x 6
  # ACK  RBESQUDFGHIJLMNOPTVWXYZ/-   c=12 2 x 6
  # ACKV  RBESQUDFGHIJLMNOPTWXYZ/-   c=18 3 x 6
  # ACKVR  BESQUDFGHIJLMNOPTWXYZ/-   c=0  0 x 5
  # ACKVRD  BESQUFGHIJLMNOPTWXYZ/-   c=5  1 x 5
  # ...
  # ACKVRDLWBFMXEGNYSHOZQIP/UJT-
  #
  # Irregular rectangle
  # -------------------
  # Key is SUBWAY condensed info SUBWAY (len = 6) (height = 5)
  #
  # S  UBWAYCDEFGHIJKLMNOPQRTVXZ/-   c=0  0 x 5
  # SC  UBWAYDEFGHIJKLMNOPQRTVXZ/-   c=5  1 x 5
  # SCI  UBWAYDEFGHJKLMNOPQRTVXZ/-   c=10 2 x 5
  # SCIO  UBWAYDEFGHJKLMNPQRTVXZ/-   c=15 3 x 5
  # SCIOX  UBWAYDEFGHJKLMNPQRTVZ/-   c=20 4 x 5
  # SCIOXU  BWAYDEFGHJKLMNPQRTVZ/-   c=0  0 x 4
  # ...
  # SCIOXUDJPZBEKQ/WFLR-AG  YHMNTV   c=1  1 x 1
  # SCIOXUDJPZBEKQ/WFLR-AGM  YHNTV   c=2  2 x 1
  # SCIOXUDJPZBEKQ/WFLR-AGMT  YHNV   c=3  3 x 1
  # SCIOXUDJPZBEKQ/WFLR-AGMTYHNV
  #
  def checkboard
    word = (@key + BASE).condensed.dup
    len = @key.condensed.length
    height = BASE.length / len


    # Odd rectangle
    #
    if (BASE.length % len) != 0
      height = height + 1
    end

    print "\ncheckboard size is #{len} x #{height}\n"
    res = ""
    (len - 1).downto(0) do |i|
      0.upto(height - 1) do |j|
        if word.length <= (height - 1) then
          return res + word
        else
          c = word.slice!(i * j)
          if not c.nil? then
            res = res + c.chr
          end
        end
      end
    end
    return res
  end 

  # == gen_rings
  #
  # Assign a code number for each letter. Each code number is
  # sequentially allocated from two pools, one with 0..7 and
  # the other with 80..99.
  #
  # Allocation is made on the following criterias
  # - if letter is one of ESANTIRU assign a single code number
  # - else assign of of the two letters ones
  #
  # Generate both the encoding and decoding rings.
  #
  # XXX FIXME Use of 80-99 is hardcoded
  #
  def gen_rings
    ind_u = 0
    ind_d = 80

    word = @full_key.dup
    word.scan(/./) do |c|
      if c =~ /[ESANTIRU]/
        @alpha[c] = ind_u
        @ralpha[ind_u] = c
        ind_u = ind_u + 1
      else
        @alpha[c] = ind_d
        @ralpha[ind_d] = c
        ind_d = ind_d + 1
      end
    end
  end # -- gen_rings

Ruby/Python/Perl or pseudo-code is fine for me. Thanks for any idea.

+1  A: 

Perhaps you should try Refactor :my => code instead? There are a lot of helpful people on there.

Rob Elsner