Coded Correspondence Question - Vigenere Cypher (i think i am close)

i am trying to create the vigenere cypher and i think i am close but i know i am missing something. this comes from the coded correspondence jupyter notebook project and although i am 63% of the way through the python course here on codecademy, i found this project to be impossible to do and had to look at the solutions, and i still don’t understand the solution for how they did the vigenere cypher.

here is what i have so far:

alphabet = "abcdefghijklmnopqrstuvwxyz"
v_message = "txm srom vkda gl lzlgzr qpdb? fepb ejac! ubr imn tapludwy mhfbz cza ruxzal wg zztcgcexxch!"
clue = "fri ends frie nd sfrien dsfri ends frie  nds fri endsfrie ndsfr ien dsfrie nd sfriendsfri "

def vigenere_decode(message, keyword):
    vigenere_decoded_message = ""
    for c in message:
        if c in alphabet:
            c_value = alphabet.find(c)
    for l in keyword:
        if l in clue:
            l_value = clue.find(l)
            vigenere_decoded_message += [(c_value % 26) + (l_value % len(keyword))]
    else:
        vigenere_decoded_message += c
    return vigenere_decoded_message

print(vigenere_decode("txm srom vkda gl lzlgzr qpdb? fepb ejac! ubr imn tapludwy mhfbz cza ruxzal wg zztcgcexxch!", "friends"))

i am only 2 months in to learning python, never coded anything before, and using no other resources but codecademy and this project blew my mind.

1 Like

Yep, its a tough project to think through.

In your case, you need what’s happening with the keyword to overlap with what’s happening with the letters in message
so you shouldn’t put
for c in message:
and
for l in keyword:
as separate loops.

Instead of having a loop to go through the message, it may be more useful to have a counter variable [that starts at 0 and increases by 1 each time the letter changes] to then use to find the appropriate thing in the keyword.
And then use something like
l = keyword[counter_variable % len(keyword)]
to get the appropriate letter from the keyword.

Also, you don’t need clue in your function: the clue string is just an aid to check that what your doing with the keyword is correct, but it wouldn’t be part of the decoding function. (You don’t need to loop through clue at all.)

You’re concerned with the position of the keyword letter l in the alphabet, so instead of
l_value = clue.find(l)
you should have
l_value = alphabet.find(l)

You have:

vigenere_decoded_message += [(c_value % 26) + (l_value % len(keyword))]

but you’re adding a letter from alphabet, so instead of
vigenere_decoded_message += [stuff]
it should be
vigenere_decoded_message += alphabet[stuff]
where stuff is a placeholder for the calculation to get the index of the appropriate character.

also, the % 26 should be the last thing done in the calculation (to ensure that you have a valid index of the alphabet string).
So you might end up with something like:

vigenere_decoded_message += [(c_value + l_value) % 26]

The else you have should happen if that letter in the message is not in alphabet
so
the indentation for
if c in alphabet:
and
else:
should be the same.

possible solution (try not to look at it until you're done)

Here’s one possible way to do it using much of your code.
The commented out code would print the stuff identical to hint.

alphabet = "abcdefghijklmnopqrstuvwxyz"
v_message = "txm srom vkda gl lzlgzr qpdb? fepb ejac! ubr imn tapludwy mhfbz cza ruxzal wg zztcgcexxch!"
clue = "fri ends frie nd sfrien dsfri ends frie  nds fri endsfrie ndsfr ien dsfrie nd sfriendsfri "

def vigenere_decode(message, keyword):
    vigenere_decoded_message = ""
    i = 0 #counter (counts iterations)
    for c in message:
      if c in alphabet:
        c_value = alphabet.find(c)
        l = keyword[i % len(keyword)]
        #print(l, end="");
        l_value = alphabet.find(l)
        vigenere_decoded_message += alphabet[(c_value + l_value) % 26]
        i += 1
      else:
        #print(" ", end="")
        vigenere_decoded_message += c
    #print()
    return vigenere_decoded_message

print(vigenere_decode("txm srom vkda gl lzlgzr qpdb? fepb ejac! ubr imn tapludwy mhfbz cza ruxzal wg zztcgcexxch!", "friends"))

Think about the order of the steps for the letters from keyword for each letter in the message

  1. setup (like a counter variable) may be needed
  2. get the appropriate letter from keyword
  3. find the position of that letter in the alphabet
  4. use that result to get the position of the shifted letter (multiple steps)
1 Like

[quote=“core4207147728, post:1, topic:778129”]

l don’t understand the solution for how they did the vigenere cypher.

Hi, the solution provided works but it is very short and the steps are tough to follow.

Here I have one solution in details. It can be long, but I can read it step-by-step. I’ll walk you through the :point_right:decoder. :point_left: :call_me_hand: Then, I’ll shorten it so that you have another short solution which seems brief.
In the end, I’ll guild you to do the encoder.

Take a look at what we are going to do

alphabet = 'abcdefghijklmnopqrstuvwxyz'

message_to_decode = "txm srom vkda gl lzlgzr qpdb? fepb ejac! ubr imn tapludwy mhfbz cza ruxzal wg zztcgcexxch!"
keyword = "friends"

def VigenereC_decoder(message, keyword):
  print(message)
  # Apply keyword
  applied_keyword_phrase = ''
  count = 0
  for char in message:
    if char in alphabet:
      applied_keyword_phrase += keyword[count % len(keyword)]
      count += 1 
      #print(count % len(keyword)): 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, ... (repeats)
    else:
      applied_keyword_phrase += char
    
  print(applied_keyword_phrase)

  # List of alphabet_index from Message
  print(message)
  list_index_message = []

  for char in message:
    if char in alphabet:
      list_index_message += [alphabet.find(char)]
    else:
      list_index_message += [char]

  print (list_index_message)

  # List of alphabet_index from Keyword
  print(applied_keyword_phrase)
  list_index_keyword_phrase = []

  for char in applied_keyword_phrase:
    if char in alphabet:
      list_index_keyword_phrase += [alphabet.find(char)]
    else:
      list_index_keyword_phrase += [char]

  print (list_index_keyword_phrase)

  # Result List of alphabet_index += list_index_message[i] + list_index_keyword_phrase[i]
  list_index_result = []

  for i in range(0, len(list_index_message)):
    if type(list_index_message[i]) == int and type(list_index_keyword_phrase[i]) == int:
      list_index_result += [list_index_message[i] + list_index_keyword_phrase[i]]
    else:
      list_index_result += list_index_message[i]
  
  print('result in alphabet_index', '\n', list_index_result)

  # convert List_result from alphabet_index to alphabet 
  list_result = []
  for answer in list_index_result:
    if type(answer) == int:
      # print(answer)
      list_result += alphabet[answer % len(alphabet)]
    else:
      list_result += answer

  print(list_result)

  # final result: join list
  result = ''.join(list_result)
  return result

print(VigenereC_decoder(message_to_decode, keyword))


See my photo for the math of alphabet_index encoding and decoding?

  • To decode: alphabet_index_encoded + alphabet_index_keyword
  • To encode: alphabet_index_message - alphabet_index_keyword

If step 1 is not clear to follow, let me know. :vulcan_salute:

Oh, and here is the very short solution for the :point_right:decoder :point_left::

alphabet = 'abcdefghijklmnopqrstuvwxyz'

message_to_decode = "txm srom vkda gl lzlgzr qpdb? fepb ejac! ubr imn tapludwy mhfbz cza ruxzal wg zztcgcexxch!"
keyword = "friends"

def VigenereC_decoder(message, keyword):
  print(message)

  # Apply keyword
  applied_keyword_phrase = ''
  count = 0
  for char in message:
    if char in alphabet:
      applied_keyword_phrase += keyword[count % len(keyword)]
      count += 1
    else:
      applied_keyword_phrase += char

  print(applied_keyword_phrase)

  # Result
  result = ''

  for i in range(0, len(applied_keyword_phrase)):
    if applied_keyword_phrase[i] in alphabet:
      result_index = alphabet.find(message[i]) + alphabet.find(applied_keyword_phrase[i])
      result += alphabet[result_index % len(alphabet)]
    else:
      result += applied_keyword_phrase[i]

  return result

print(VigenereC_decoder(message_to_decode, keyword))
1 Like