HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Reddit mirror encryption challenge

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
encryptionmirrorredditchallenge

Problem

While reviewing Encryption using a mirror field, I decided to write my own solution from scratch. The challenge, from Reddit's /r/dailyprogrammer, is to implement a monoalphabetic substitution cipher whose key is derived from a pictorial 13×13 grid. Here's a simplified 5×5 example:

abcde
A \   f
B     g
C   \ h
D     i
E   / j
 FGHIJ




The 5×5 grid above defines 20 mappings, some of which are:



  • A maps to G, because a laser beam heading right from the A would hit the \ mirror and be deflected down to G.



  • Conversely, G maps to A through the reverse path.



  • B maps to g, and vice versa, as the horizontal beam is uninterrupted.



  • C maps to E, and vice versa, as the beam is reflected twice.



  • I maps to j, and vice versa.




The actual input is provided as a 13×13 grid of /, \, and space characters, without the row and column labels. I've implemented the option to accept the key as a filename if one is provided on the command line, else it will be read from the first 13 lines of standard input. Thereafter, the program acts as a filter for text on standard input.

I've also implemented a doctest, which you can run using python -v -m doctest programname. The presence of backslashes has forced me to write it in an ugly way; any suggestion for a better way to write it would be appreciated.

```
"""
Perform the mirror encryption challenge in https://redd.it/4m3ddb
"""

from fileinput import input as fileinput
from string import ascii_lowercase, ascii_uppercase
from sys import argv, stdin

def grid_to_translation(grid):
"""
Given a mirror field, construct a translation table suitable for use with
str.maketrans(). The grid may be any iterable; only the first 13 lines
will be taken from it.

>>> # Using a string replacement as literal backslashes are hard to write.
>>> input = (line.replace('x', chr(92)) for line in [
... ' xx /x ',
... ' x',
...

Solution

The logic is neat and nicely done, there is not much to say. Just a few nitpicks:

  • fileinput() already defaults to stdin if there is no arguments on the command line, no need to manage it yourself.


It has been made clearer in a comment that you expect more than "no filename = stdin" : you should make it more clear in the code too; maybe changing the second line of comment with something like # since fileinput will truncate anything to the 13 lines we need, overide the 'no filename = stdin' rule to be able to pipe in the grid + some text to translate.

-
You can easily use '\' in docstrings by using raw multiline strings: r'''docstring'''.
Thus when defining input you can use '\\' as in a regular Python session, or use raw strings where applicable.

Or use raw strings all along and add padding characters for those that ends with a backslash, as you already ignore them; and document it with something along the lines of # avoid ending raw strings with backslashes, extra characters are ignored anyway.

  • You can extract the building of the various constants out of the function, there is no need to do it each time.



  • You can define the magic number 13 as MID_ALPHABET = len(ascii_lowercase) / 2

Context

StackExchange Code Review Q#131684, answer score: 2

Revisions (0)

No revisions yet.