patternpythonMinor
Reddit mirror encryption challenge
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:
The 5×5 grid above defines 20 mappings, some of which are:
The actual input is provided as a 13×13 grid of
I've also implemented a doctest, which you can run using
```
"""
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',
...
abcde
A \ f
B g
C \ h
D i
E / j
FGHIJThe 5×5 grid above defines 20 mappings, some of which are:
Amaps toG, because a laser beam heading right from theAwould hit the\mirror and be deflected down toG.
- Conversely,
Gmaps toAthrough the reverse path.
Bmaps tog, and vice versa, as the horizontal beam is uninterrupted.
Cmaps toE, and vice versa, as the beam is reflected twice.
Imaps toj, 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:
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
-
You can easily use
Thus when defining
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
fileinput()already defaults tostdinif 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.