Search code examples
pythonloopsfor-loopif-statement

Position of in for-loop gives different results


I am trying to build a simple cipher in Python with encoding and encoding functionality.

It takes a word from a user, applies the specified shift number and shifts each letter forward by that index value in the alphabet list.

So:

Text = "hello"  
  
Shift = "5"

Will give: "mjqqt"

Decoding will turn "mjqqt" back into "hello"

Depending on where my if statement is, I either get "holvo" or "hello" and I'm concerned I'm not correctly understanding the order of operations.

The first code below with if-statement inside the for-loop will give me the answer "holvo" when it tries to decode "mjjqt"

#Provide alphabet list and starting input variables

alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']

direction = input("Type 'encode' to encrypt, type 'decode' to decrypt:\n")
text = input("Type your message:\n").lower()
shift = int(input("Type the shift number:\n"))

#Combine the encrypt and decrypt functions into a single function called caesar(). 

def caesar(start_text, shift_amount, cipher_direction):
  end_text = ""
  for letter in start_text:
    position = alphabet.index(letter)
    if cipher_direction == "decode":
          shift_amount *= -1
    new_position = position + shift_amount
    end_text += alphabet[new_position]
    
  print(f"Here's the {direction}d result: {end_text}")

caesar(start_text=text, shift_amount=shift, cipher_direction=direction)

The below with the if-statement outside of the for-loop will give me the correct answer "hello" when it tries to decode "mjjqt".

#Provide alphabet list and starting input variables

alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']

direction = input("Type 'encode' to encrypt, type 'decode' to decrypt:\n")
text = input("Type your message:\n").lower()
shift = int(input("Type the shift number:\n"))

#Combine the encrypt and decrypt functions into a single function called caesar().

def caesar(start_text, shift_amount, cipher_direction):
  end_text = ""
  if cipher_direction == "decode":
      shift_amount *= -1
  for letter in start_text:
    position = alphabet.index(letter)
    new_position = position + shift_amount
    end_text += alphabet[new_position]
  print(f"Here's the {direction}d result: {end_text}")

caesar(start_text=text, shift_amount=shift, cipher_direction=direction)

Solution

  • The reason that the first example isn't working is because in each iteration of the loop, the shift amount is flipped.

    When it is before the loop, it is only flipped once, so you get the expected result.

    # Iteration 1
    shift_amount = -5
    
    # Iteration 2
    shift_amount =  5
    
    # Iteration 3
    shift_amount = -5
    ...