- n_secs = len(message) // ((height - 1) * 2)
- downrows = [message[:n_secs]]
- uprows = []
- for r in range(height-2):
- midrow = message[(2 * r + 1) * n_secs:(2 * r + 1) * n_secs + n_secs * 2]
- downrows += [''.join([midrow[i] for i in range(0, len(midrow), 2)])]
- uprows = [''.join([midrow[i] for i in range(1, len(midrow), 2)])] + uprows
- downrows += [message[-n_secs:]]
- rows = downrows + uprows
- return ''.join(letter for section in zip(*rows) for letter in section)
+ # find the number and size of the sections, including how many characters
+ # are missing for a full grid
+ n_sections = math.ceil(len(message) / ((height - 1) * 2))
+ padding_to_add = n_sections * (height - 1) * 2 - len(message)
+ # row_lengths are for the both up rows and down rows
+ row_lengths = [n_sections] * (height - 1) * 2
+ for i in range((height - 1) * 2 - 1, (height - 1) * 2 - (padding_to_add + 1), -1):
+ row_lengths[i] -= 1
+ # folded_rows are the combined row lengths in the middle of the railfence
+ folded_row_lengths = [row_lengths[0]]
+ for i in range(1, height-1):
+ folded_row_lengths += [row_lengths[i] + row_lengths[-i]]
+ folded_row_lengths += [row_lengths[height - 1]]
+ # find the rows that form the railfence grid
+ rows = []
+ row_start = 0
+ for i in folded_row_lengths:
+ rows += [message[row_start:row_start + i]]
+ row_start += i
+ # split the rows into the 'down_rows' (those that form the first column of
+ # a section) and the 'up_rows' (those that ofrm the second column of a
+ # section).
+ down_rows = [rows[0]]
+ up_rows = []
+ for i in range(1, height-1):
+ down_rows += [''.join([c for n, c in enumerate(rows[i]) if n % 2 == 0])]
+ up_rows += [''.join([c for n, c in enumerate(rows[i]) if n % 2 == 1])]
+ down_rows += [rows[-1]]
+ up_rows.reverse()
+ return ''.join(c for r in zip_longest(*(down_rows + up_rows), fillvalue='') for c in r)