This is the CodeEval problem #181, and here is my Python 3 solution.
ALPHA is the vocabulary we have to use.
ALPHA = ' !"#$%&\'()*+,-./0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'I have converted the sample provided to a Python test case, adding an extra test that shows how the decoding works at an extreme of the alphabet:
def test_provided_1(self): self.assertEqual('EXALTATION', solution('31415;HYEMYDUMPS')) def test_provided_2(self): self.assertEqual('I love challenges!', solution('45162;M%muxi%dncpqftiix"')) def test_provided_3(self): self.assertEqual('Test input.', solution('14586214;Uix!&kotvx3')) def test_extra(self): self.assertEqual('xyz', solution('3; !"'))Gronsfeld is a simple extension of the Caesar ciphering method. Instead of using a single number that shifts the plain text to its encrypted version, more numbers could be used. Since the message could be longer than the key, we repeat the key to get the shift we have to apply to a given character in the message.
As you can see, my extra test does not use the Gronsfeld extension capability, falling back to the Caesar schema. It's point is just to show what happens when I encrypt letters that are on the extreme right of the vocabulary.
The core of my solution is a loop that executes a single line converting each character back to its plain counterpart and appending it to the result.
result.append(ALPHA[ALPHA.index(data[i]) - data[i % len(data)]])data is a list of integers, representing the key.
data is a string, the encrypted message.
The index in ALPHA for the plain character is given by the index in ALPHA of the encrypted one minus the key for that position. In this way it could happen that we get a negative index, but this is OK, since python manages them right how we need.
I pushed test case and solution python script to GitHub.