Take the 2-minute tour ×
Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

Write a program which reads a string and a key and encodes the string into a rail-fence cipher using that key.

Similarly, write a program for reverse function, ie, deciphering a rail fence using a key.

For those who don't know what rail fence cipher is, it is basically a method of writing plain text in a way it creates linear pattern in a spiral way. Example - when "FOOBARBAZ" rail-fenced using key of 3.

F . . . A . . . Z . . . .
  O . B . R . A . Q . X
    O . . . B . . . U

Reading the above spiral line-by-line, the cipher text becomes "FAZOBRAQXOBU".

Read more at - Rail fence - Wikipedia.

Code in any language is welcomed.

The one with the least characters wins.

share|improve this question
2  
What is the winning criterion ? –  Paul R Jan 25 '13 at 10:37

2 Answers 2

up vote 7 down vote accepted

Python 133 bytes

def cipher(t,r):
 m=r*2-2;o='';j=o.join
 for i in range(r):s=t[i::m];o+=i%~-r and j(map(j,zip(s,list(t[m-i::m])+[''])))or s
 return o

Sample usage:

>>> print cipher('FOOBARBAZQUX', 3)
FAZOBRAQXOBU

>>> print cipher('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 4)
AGMSYBFHLNRTXZCEIKOQUWDJPV

>>> print cipher('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 5)
AIQYBHJPRXZCGKOSWDFLNTVEMU

>>> print cipher('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 6)
AKUBJLTVCIMSWDHNRXEGOQYFPZ

Note: the results from even rail counts are different than for the code you provided, but they seem to be correct. For example, 6 rails:

A         K         U
 B       J L       T V
  C     I   M     S   W
   D   H     N   R     X
    E G       O Q       Y
     F         P         Z

corresponds to AKUBJLTVCIMSWDHNRXEGOQYFPZ, and not AKUTBLVJICMSWXRDNHQYEOGZFP as your code produces.

The basic idea is that each rail can be found directly by taking string slices [i::m], where i is the rail number (0-indexed), and m is (num_rails - 1)*2. The inner rails additionally need to be interwoven with [m-i::m], achieved by zipping and joining the two sets of characters. Because the second of these can potentially be one character shorter, it is padded with a character assumed not to appear anywhere (_), and then that character is stripped off if necessary it is converted to a list, and padded with an empty string.


A slightly more human readable form:

def cipher(text, rails):
  m = (rails - 1) * 2
  out = ''
  for i in range(rails):
    if i % (rails - 1) == 0:
      # outer rail
      out += text[i::m]
    else:
      # inner rail
      char_pairs = zip(text[i::m], list(text[m-i::m]) + [''])
      out += ''.join(map(''.join, char_pairs))
  return out
share|improve this answer
    
A deciphering function is also needed. –  ShuklaSannidhya Jan 17 at 16:47

APL 52 41

i←⍞⋄n←⍎⍞⋄(,((⍴i)⍴(⌽⍳n),1↓¯1↓⍳n)⊖(n,⍴i)⍴(n×⍴i)↑i)~' '

If the input text string i and the key number n are preinitialised the solution can be shortened by 9 characters. Running the solution against the examples given by primo gives identical answers:

FOOBARBAZQUX
3
FAZOBRAQXOBU

ABCDEFGHIJKLMNOPQRSTUVWXYZ
4
AGMSYBFHLNRTXZCEIKOQUWDJPV

ABCDEFGHIJKLMNOPQRSTUVWXYZ
5
AIQYBHJPRXZCGKOSWDFLNTVEMU

ABCDEFGHIJKLMNOPQRSTUVWXYZ
6
AKUBJLTVCIMSWDHNRXEGOQYFPZ

On further reflection there appears to be a shorter index based solution:

i[⍋+\1,(y-1)⍴((n←⍎⍞)-1)/1 ¯1×1 ¯1+y←⍴i←⍞]
share|improve this answer
    
A deciphering function is also needed. –  ShuklaSannidhya Jan 17 at 17:08

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.