Crypt Kicker Solution Design
I participate in ‘the Calgary book club’, several developers come together every couple of weeks to discuss a book we’ve all been reading. Currently we’re working our way through Steven Skiena’s Algorithm Design Manual. It’s a pretty good walk through a lot of computer science fundamentals, particularly for those of us who didn’t study a straight CS course at university.
The other week, we had a stab at the crypt kicker problem from the book. None of us managed to implement a solution that would be deemed acceptable by the online judge, but we did produce some ideas and partial solutions. Here's my idea, which you can find source code for at GitHub.
The general concept is to build up a dictionary, or cipher, of possible letter substitutions based on each word in the input sentence. Progressing through the input from start to finish may cause several equally valid ciphers to be produced, so we keep a list of ciphers. Each word encountered may cause this list to be lengthened or shortened.
We'll work through the example given in the problem description.
Just to recap, the word list contains 6 words:
Note that both ciphers have a substitute for b, but as it is the same in both, there is no conflict.
On the other hand, the second cipher from stage 1 contains b → j, and the cipher from stage 2 contains b → d. Therefore the two cannot be merged, and we drop this possibility:
Finally, the third cipher from stage 1 contains b → s, which also conflicts with the stage 2 cipher.
So after this stage, we have reduced ourselves to just one possibility. We discard all the ciphers we had before from stage 1 and 2.
and dick jane puff spot yertleAnd there is one sentence to decode:
bjvg xsb hxsn xsb qymm xsb rqat xsb pnetfn
Solution Stage 1 : Find ciphers for the first word
The first word from our input is bjvg. We'll try this word against every word in the dictionary. and : Too short, throw that right out dick : That works, we can substitute b → d, j →i, v → c and g → k jane : Also works puff : Appears to work at first, b → p, j → u, v → f, but wait... g can't stand in for f, because f is already taken. So that doesn't work spot : That works yertle : Too long So we end up with three ciphers, one each for dick, jane and spot:Key | Cipher 1 | Cipher 2 | Cipher 3 |
b | d | j | s |
j | i | a | p |
v | c | n | o |
g | k | e | t |
Solution Stage 2 : Find ciphers for the second word
We now go through the same process for the second word, and come out with just one cipher:Key | Cipher 1 |
x | a |
s | n |
b | d |
Solution Stage 3 : Find all the valid combinations
This is where the magic happens. With any implementation of a solution to this problem, eliminating possibilities is as important as finding them. In this stage, we get all the ciphers found so far and merge them with all those found in the last step, so in this case we expect to get 3 x 1 = 3 new ciphers (if two were found in stage 2, we would get 3 x 2 = 6). We discard any combinations that conflict with each other. To start with, we get the first cipher from stage 1, and combine it with the result of stage 2. This yields the following:Key | Stage 1, Ciper 1 | Stage 2 | Combination |
x | a | a | |
s | n | n | |
b | d | d | d |
j | i | i | |
v | c | c | |
g | k | k |
Key | Stage 1, Ciper 1 | Stage 2 | Combination |
x | a | a | |
s | n | n | |
b | j | d | ? |
j | a | a | |
v | n | n | |
g | e | e |