开发者

multilevel caesar cipher

Hey, I'm trying to decode a multilevel Caesar cipher. By that I mean a string of letters could have been shifted several times, so if I say apply_shifts[(2,3),(4,5)], that means I shift everything from the 2nd letter by 3 followed by everything from the 4th letter by 5. Here's my code so far.

def find_best_shifts_rec(wordlist, text, start):
    """
    Given a scrambled string and a starting position from which
    to decode, returns a shift key that will decode the text to
    words in wordlist, or None if there is no such key.

    Hint: You will find this function much easier to implement
    if you use recursion.

    wordlist: list of words
    text: scambled text to try to find the words for
    start: where to start looking at 开发者_高级运维shifts
    returns: list of tuples.  each tuple is (position in text, amount of shift)
    """

    for shift in range(27):
        text=apply_shifts(text, [(start,-shift)])
        #first word is text.split()[0]
        #test if first word is valid.  if not, go to next shift

        if is_word(wordlist,text.split()[0])==False:
            continue

        #enter the while loop if word is valid, otherwise never enter and go to the next shift
        i=0
        next_index=0
        shifts={}
        while is_word(wordlist,text.split()[i])==True:
            next_index+= len(text.split()[i])
            i=i+1
            #once a word isn't valid, then try again, starting from the new index.
            if is_word(wordlist,text.split()[i])==False:
                shifts[next_index]=i
                find_best_shifts_rec(wordlist, text, next_index)

    return shifts

My problems are

1) my code isn't running properly and I don't understand why it is messing up (it's not entering my while loop) and 2) I don't know how to test whether none of my "final shifts" (e.g. the last part of my string) are valid words and I also don't know how to go from there to the very beginning of my loop again.

Help would be much appreciated.


I think the problem is that you always work on the whole text, but apply the (new) shifting at some start inside of the text. So your check is_word(wordlist,text.split()[0]) will always check the first word, which is - of course - a word after your first shift.

What you need to do instead is to get the first word after your new starting point, so check the actually unhandled parts of the text.

edit

Another problem I noticed is the way you are trying out to find the correct shift:

for shift in range(27):
    text=apply_shifts(text, [(start,-shift)])

So you basically want to try all shifts from 0 to 26 until the first word is accepted. It is okay to do it like that, but note that after the first tried shifting, the text has changed. As such you are not shifting it by 1, 2, 3, ... but by 1, 3, 6, 10, ... which is of course not what you want, and you will of course miss some shifts while doing some identical ones multiple times.

So you need to temporarily shift your text and check the status of that temporary text, before you continue to work with the text. Or alternatively, you always shift by 1 instead.

edit²

And another problem I noticed is with the way you are trying to use recursion to get your final result. Usually recursion (with a result) works the way that you keep calling the function itself and pass the return values along, or collect the results. In your case, as you want to have multiple values, and not just a single value from somewhere inside, you need to collect each of the shifting results.

But right now, you are throwing away the return values of the recursive calls and just return the last value. So store all the values and make sure you don't lose them.


Pseudo-code for recursive function:

coded_text = text from start-index to end of string
if length of coded_text is 0, return "valid solution (no shifts)"

for shift in possible_shifts:
    decoded_text = apply shift of (-shift) to coded_text
    first_word = split decoded_text and take first piece
    if first_word is a valid word:
        rest_of_solution = recurse on (text preceding start-index)+decoded_text, starting at start+(length of first_word)+1
        if rest_of_solution is a valid solution
            if shift is 0
                return rest_of_solution
            else
                return (start, -shift mod alphabet_size) + rest_of_solution

# no valid solution found
return "not a valid solution"

Note that this is guaranteed to give an answer composed of valid words - not necessarily the original string. One specific example: 'a add hat' can be decoded in place of 'a look at'.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜