So, I had 2 scripts, a Vigenere cipher and a Caesar cipher, however, when I decided to merge them into a "mainproject" file by using "import" to import the script after the wanted answer from the user is sent on the Terminal page, when I've done the code and decided to execute the mainproject, I've got the question whether to choose to use Vigenere or Caesar, once I typed caesar (1) it played the first 2-4 lines and stopped the code once I've encountered the "def" line on both of scripts, if thats the problem, I can't use imports with "def", how can I merge them both into one file that asks which script I would like to use?
Caesar:
import time
import sys
print("Welcome to Caesar Cipher")
time.sleep(3)
print("Choose the corresponding number to Encrypt or Decrypt in Caesar Cipher")
def encryption():
print("Encryption")
print("You have chose ENCRYPTION")
msg = input("Enter message: ")
key = int(input("Enter key(0-25): "))
encrypted_text = ""
for i in range(len(msg)):
if ord(msg[i]) == 32:
encrypted_text += chr(ord(msg[i]))
elif ord(msg[i]) + key > 122:
temp = (ord(msg[i]) + key) - 122
encrypted_text += chr(96+temp)
elif (ord(msg[i]) + key > 90) and (ord(msg[i]) <= 96):
temp = (ord(msg[i]) + key) - 90
encrypted_text += chr(64+temp)
else:
encrypted_text += chr(ord(msg[i]) + key)
print("Your Encrypted Message: " + encrypted_text)
def decryption():
print("Decryption")
print("You have chose DECRYPTION")
encrp_msg = input("Enter encrypted Text: ")
decrp_key = int(input("Enter key(0-25): "))
decrypted_text = ""
for i in range(len(encrp_msg)):
if ord(encrp_msg[i]) == 32:
decrypted_text += chr(ord(encrp_msg[i]))
elif ((ord(encrp_msg[i]) - decrp_key) < 97) and ((ord(encrp_msg[i]) - decrp_key) > 90):
temp = (ord(encrp_msg[i]) - decrp_key) + 26
decrypted_text += chr(temp)
elif (ord(encrp_msg[i]) - decrp_key) < 65:
temp = (ord(encrp_msg[i]) - decrp_key) + 26
decrypted_text += chr(temp)
else:
decrypted_text += chr(ord(encrp_msg[i]) - decrp_key)
print("Text has been Decrypted: " + decrypted_text)
choice = int(input("1. Encryption\n2. Decryption\nChoose(1,2): "))
if choice == 1:
encryption()
elif choice == 2:
decryption()
else:
print("Wrong Choice")
Vigenere:
import time
print("Welcome to Vigenere Cipher")
time.sleep(2)
print("Choose the corresponding number to Encrypt or Decrypt in Vigenere Cipher")
time.sleep(2.5)
def msg_and_key():
msg = input("Enter message: ").upper()
key = input("Enter key: ").upper()
key_map = ""
j=0
for i in range(len(msg)):
if ord(msg[i]) == 32:
key_map += " "
else:
if j < len(key):
key_map += key[j]
j += 1
else:
j = 0
key_map += key[j]
j += 1
return msg, key_map
def create_vigenere_table():
table = []
for i in range(26):
table.append([])
for row in range(26):
for column in range(26):
if (row + 65) + column > 90:
table[row].append(chr((row+65) + column - 26))
else:
table[row].append(chr((row+65)+column))
return table
def cipher_encryption(message, mapped_key):
table = create_vigenere_table()
encrypted_text = ""
for i in range(len(message)):
if message[i] == chr(32):
encrypted_text += " "
else:
row = ord(message[i])-65
column = ord(mapped_key[i]) - 65
encrypted_text += table[row][column]
print("Encrypted Message: {}".format(encrypted_text))
def itr_count(mapped_key, message):
counter = 0
result = ""
for i in range(26):
if mapped_key + i > 90:
result += chr(mapped_key+(i-26))
else:
result += chr(mapped_key+i)
for i in range(len(result)):
if result[i] == chr(message):
break
else:
counter += 1
return counter
def cipher_decryption(message, mapped_key):
table = create_vigenere_table()
decrypted_text = ""
for i in range(len(message)):
if message[i] == chr(32):
decrypted_text += " "
else:
decrypted_text += chr(65 + itr_count(ord(mapped_key[i]), ord(message[i])))
print("Decrypted Message: {}".format(decrypted_text))
print("Key and Message can only be alphabetic")
time.sleep(1.5)
choice = int(input("1. Encryption\n2. Decryption\nChoose(1,2): "))
if choice == 1:
print("You have chose ENCRYPTION")
message, mapped_key = msg_and_key()
cipher_encryption(message, mapped_key)
elif choice == 2:
print("You have chose DECRYPTION")
message, mapped_key = msg_and_key()
cipher_decryption(message, mapped_key)
else:
print("Wrong choice")
Any help would be appreciated!
def only defines a function. To actually execute it you need to call it.
It seems the following part should be outside of decryption function body i.e. indented to the left. It:
call be executed directly on the module level
can be a separate function e.g. main that you can call
As main:
def main():
choice = int(input("1. Encryption\n2. Decryption\nChoose(1,2): "))
if choice == 1:
encryption()
elif choice == 2:
decryption()
else:
print("Wrong Choice")
And now you can call the main function:
main()
Welcome to Stackoverflow. This answer ended up more as general advice than a specific point solution to your problem, but I hope it's helpful.
One obvious remark is that it would be nice not to have to import the code for the cypher you don't intend to use.
Imports are executable statements, so this is quite practical.
Your code is far from optimally organised. Much of the code on the two files is the same or very similar. This is not unusual for new programmers, as it takes a while to learn how to break problems down and extract the common elements. The real problem is that while it defines lots of functions, none of them actually get called (unless there's more code you haven't included).
I would recommend that you modify your code so that there's a top-level program that collects the key and data and performs the required operations, along with your two
encryption/decryption modules. The encryption and decryption routines shouldn't do any input or output at all, just deal with the data.
Let's assume you have a variable mtype that holds the type of encryption you want to use. The top-level logic could look something like this:
if mtype == "caesar":
from caesar import encrypt, decrypt
elif mtype == "vigniere":
from vigniere import encrypt, decrypt
else:
sys.exit("Unrecognised message type")
If this code succeeds you would then have an encrypt and a decrypt function from the correct module. This means that they have to have the same interface, since your logic must now be written to accommodate either.
The remainder of your logic would look something like this (untested):
operation = input("E(ncrypt) or D(ecrypt)? ")
if operation.upper().startswith("E"):
function = encrypt
elif operation.upper().startswith("D"):
function = decrypt
else:
sys.exit("Unknown operation")
message = input(...)
key = input(...)
output = function(message, key)
This will hopefully make your code clearer by separating out the I/O responsibility
from the encryption and decryption tasks.
Related
My code for now works as desired where the user can input a level 1-3 depending on how hard they would like it to be (1-3 being the amount of digits the numbers will have in the math equation), and then must solve math equations. Those math equations will output EEE if the answer is incorrect and everything works as planned if you correctly answer the question as it exits the function and adds one total_correct_answers variable at the bottom, then will prompt you with another equation. However, if you input an incorrect answer and then a correct answer, you will just be prompted with the same question over and over again without the try loop being truly broken out of and total_correct_answers not being incremented positively by 1. The incrementation block of code is at lines 61-65, and the equation code is lines 30-49.
import random
def main():
ten_questions()
def get_level():
while True:
try:
level_input = int(input("Level: "))
if level_input in [1,2,3]:
return level_input
except:
pass
def integer_generator(level):
if level == 1:
x = random.randint(0,9)
y = random.randint(0,9)
elif level == 2:
x = random.randint(10, 99)
y = random.randint(10, 99)
else:
x = random.randint(100, 999)
y = random.randint(100, 999)
return x, y
def question_generator(x, y):
real_answer = x + y
wrong_counter = 0
while True:
try:
answer_given = input(str(x) + " + " + str(y) + " = ")
if int(answer_given) == real_answer:
if wrong_counter == 0:
return True
elif int(answer_given) == real_answer and wrong_counter != 0:
break
else:
while wrong_counter < 2:
print("EEE")
wrong_counter +=1
break
else:
print(str(x) + " + " + str(y) + " = " + str(real_answer))
print("False, that was last attempt")
break
except:
print("EEE")
pass
def ten_questions():
num_of_questions = 0
total_correct_answers = 1
my_level = get_level()
correct_answers = question_generator(*integer_generator(my_level))
while num_of_questions <= 8:
question_generator(*integer_generator(my_level))
num_of_questions +=1
if correct_answers == True:
total_correct_answers +=1
print("Score: " + str(total_correct_answers))
if __name__ == "__main__":
main()
Because of your line 36:
if int(answer_given) == real_answer: happens when someone answers correctly, wether they are right or wrong. So it enters the if, and then faces if wrong_counter == 0: which discards wrong answers. So just replace those two lines with if int(answer_given) == real_answer and wrong_counter == 0: and you are good to go.
I am trying to make a encrypter, in a similar fashion to the enigma machine but no what I try, the variable "final_message" won't print anything but blank space
message = input("Please input a message. ").upper()
final_message = ""
shift = 0
rotor1 = ['D','M','T','W','S','I','L','R','U','Y','O',
'N','K','F','E','J','C','A','Z','B','P','G','X','O','H','V']
for i in range(len(message)):
if ord(message[i]) == 32:
final_message += "n"
else:
num = ord(message[i]) - 65 + shift
if num > 25:
num -= 26
final_message += rotor1[num]
shift+=1
print(final_message)
I pretty new to coding so I am wondering whether anyone can spot my mistake. I don't get any errors, my code just finishes without printing any letters
It seems the indentation of final_message += rotor1[num] should be at the same level as that of if num > 25. Like this -
if num > 25:
num -= 26
final_message += rotor1[num]
I would greatly appreciate your feedback on my first ever Python project! :D
Basically I am coding a Caesar Cipher and I think its pretty terribly 'optimised / efficient' if you know what I mean, this is because I copied and pasted the encrypt() method for the decrypt() method and the only thing I changes was instead of rotating the numbers more, I rotated them less. This is what I'm talking about:
newPosition = (abc.find(letter) - key) % 26
^^ Instead of having a + (plus) I made it a - (minus) ^^
Is there a way I can sort of call the encrypt() method at just the newPosition line? Or what I did was correct and it doesn't need fixing (which I highly doubt)
** Please do take in mind that I do not have much knowledge in Python (if any at all) since I just started today so don't blow my brain up with some super complex code. THANK YOU!!! **
abc = 'abcdefghijklmnopqrstuvwxyz'
def main():
message = input("Would you like to encrypt or decrypt a word?")
if message.lower() == "encrypt":
encrypt()
elif message.lower() == "decrypt":
decrypt()
else:
print("You must enter either 'encrypt' or 'decrypt'.")
main()
def encrypt():
message = input("Enter a message to encrypt: ")
message = message.lower()
key = int(input("What number would you like for your key value?"))
cipherText = ""
for letter in message:
if letter in abc:
newPosition = (abc.find(letter) + key) % 26
cipherText += abc[newPosition]
else:
cipherText += letter
print(cipherText)
return cipherText
def decrypt():
message = input("Enter a message to decrypt: ")
message = message.lower()
key = int(input("What number would you like for your key value?"))
cipherText = ""
for letter in message:
if letter in abc:
newPosition = (abc.find(letter) - key) % 26
cipherText += abc[newPosition]
else:
cipherText += letter
print(cipherText)
return cipherText
main()
In general, str.find is bad performance-wise. It's O(n) complexity, which isn't awful, but you rarely actually need it. In this case you can use ord to convert each letter to its ordinal, then subtract ord('a') to get 0-25 instead of 97-122.
This is particularly useful, because you can then use chr to convert back without needing a lookup.
for letter in message:
if letter in string.ascii_lowercase: # same as "abcdef..z"
new_position = ((ord(letter) - ord('a') + key) % 26) + ord('a')
new_ch = chr(new_position)
ciphertext += new_ch
Note also that concatenating strings with += isn't as fast as something like str.join.
new_letters = [chr(((ord(letter) - ord('a') + key) % 26) + ord('a')) if letter in ascii_lowercase else letter for letter in message]
ciphertext = "".join(new_letters)
And since that chr(((ord(letter) - ord('a') + key) % 26) + ord('a')) is so ugly, I'd refactor that into a function.
def rotate(letter, key=0):
c_pos = ord(letter) - ord('a')
rotated = c_pos + key
modded = rotated % 26
final_pos = modded + ord('a')
return chr(final_pos)
new_letters = [rotate(c, key) if c in string.ascii_lowercase else c for c in letters]
ciphertext = "".join(new_letters)
A point of maintainability: it's easier to write testably good code if you separate your inputs from your results. Right now you'd have to do some monkey patching of stdin to write unit tests for any of your functions, but if you move your requests for user input into main and out of their respective function, that gets much easier.
def main():
message = input("What's the message to encrypt/decrypt? ")
key = int(input("What number would you like for your key value? "))
choice = input("Choose: encrypt or decrypt. ")
if choice == "encrypt":
result = encrypt(message, key)
elif choice == "decrypt":
result = decrypt(message, key)
else:
# something here about a bad user input.
In fact, when you consider the Caesar Cipher is reversible by flipping the sign of the key, you can simply do:
if choice == "encrypt":
result = encrypt(message, key)
elif choice == "decrypt":
result = encrypt(message, key * (-1))
and not write a decrypt function at all!
I am learning to code through the introduction to computer science book written by John Zelle. I am stuck on exercise 5.8. I need to somehow modify this solution where the next character after "z" is "a" in order to make it circular. Any help would be great :)
def main():
print("This program can encode and decode Caesar Ciphers") #e.g. if key value is 2 --> word shifted 2 up e.g. a would be c
#input from user
inputText = input("Please enter a string of plaintext:").lower()
inputValue = eval(input("Please enter the value of the key:"))
inputEorD = input("Please enter e (to encrypt) or d (to decrypt) ")
#initate empty list
codedMessage = ""
#for character in the string
if inputEorD == "e":
for ch in inputText:
codedMessage += chr(ord(ch) + inputValue) #encode hence plus
elif inputEorD =="d":
codedMessage += chr(ord(ch) - inputValue) #decode hence minus
else:
print("You did not enter E/D! Try again!!")
print("The text inputed:", inputText, ".Is:", inputEorD, ".By the key of",inputValue, ".To make the message", codedMessage)
main()
Since you're dealing with .lower()-case letters, it's fair to know that their ASCII range is [97-122].
A good way to make the shifting circular would be to represent each letter with the range [0-25], which is done by ord(ch) - 97, and then add the key, then modulo the result with 26 so it becomes (ord(ch) - 97 + key)%26, we'll then have a result in range [0-25], adding 97 will then get it's ASCII code:
def main():
print("This program can encode and decode Caesar Ciphers")
inputText = input("Please enter a string of plaintext:").lower()
inputValue = int(input("Please enter the value of the key:")) # use int(), don't eval unless you read more about it
inputEorD = input("Please enter e (to encrypt) or d (to decrypt) ")
codedMessage = ""
if inputEorD == "e":
for ch in inputText:
codedMessage += chr((ord(ch) - 97 + inputValue)%26 + 97)
elif inputEorD =="d":
codedMessage += chr((ord(ch) - 97 - inputValue)%26 + 97)
else:
print("You did not enter E/D! Try again!!")
print("The text inputed:", inputText, ".Is:", inputEorD, ".By the key of",inputValue, ".To make the message", codedMessage)
main()
I'm Making a sort of cipher that requires a string to be read backwards and i get an indexing error even though the index I reference is well within range:
M = str(input("Input Message: "))
M = M.upper()
L = len(M)
A = ["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"]
def DECRYPT():
global L
global M
global A
if L%2 != 0:
POS = False
else:
POS = True
i = L-1
NM = ""
while 1:
if M[i] != " ":
INDEX = A.index(M[i])
if POS == True:
INDEX += (i + 1)
else:
INDEX -= (i)
INDEX %= 26
NM = NM+A[INDEX]
i += 1
if POS == True:
POS = False
else:
POS = True
print("\n"+NM)
def ENCRYPT():
global L
global A
global M
POS = True
M = M[::-1]
i = 0
NM = ""
while 1:
if i == L:
break
if M[i] != " ":
INDEX = A.index(M[i])
if POS == True:
INDEX += (i + 1)
else:
INDEX -= (i + 1)
INDEX %= 26
NM = NM+A[INDEX]
i += 1
if POS == True:
POS = False
else:
POS = True
print("\n"+NM)
while 1:
C = int(input("\nWhat do you want to do:\n1) Encrypt Something\n2)Decrypt Something\n\n"))
if C == 1:
ENCRYPT()
if C == 2:
DECRYPT()
where i is a placeholder value. I run it and get this:
Input Message: ABC
What do you want to do:
1) Encrypt Something
2)Decrypt Something
2
Traceback (most recent call last):
File "C:\Users\Danny\Google Drive\SHIFT.py", line 67, in <module>
DECRYPT()
File "C:\Users\Danny\Google Drive\SHIFT.py", line 19, in DECRYPT
if M[i] != " ":
IndexError: string index out of range
I have tried changing value of i to no avail.
There are multiple problems with your code: as fernand0 noted, your index runs the wrong way; your inversion of POS happens at different levels in the code, the encryptor does it on every character, the decryptor does it on every letter -- they should work the same; five of your six global declarations aren't needed; you don't deal with word breaks correctly so the decryption won't match the original; once you encrypt, there's no way to decrypt in the same session as the local NM doesn't feedback into the global M.
Below is my rework of your code addressing the above problems and some style issues. The key phrase here is 'simplify'. I've kept your odd uppercase variable names but expanded them from single characters to what they represent:
MESSAGE = input("Input Message: ").upper()
ALPHABET = list("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
ALPHABET_LENGTH = len(ALPHABET)
def DECRYPT(MESSAGE):
LENGTH = len(MESSAGE)
IS_NEGATIVE = True
NEW_MESSAGE = ""
for I in range(LENGTH):
if MESSAGE[I] in ALPHABET:
INDEX = ALPHABET.index(MESSAGE[I])
if IS_NEGATIVE:
INDEX -= (I + 1)
else:
INDEX += (I + 1)
INDEX %= ALPHABET_LENGTH
NEW_MESSAGE += ALPHABET[INDEX]
IS_NEGATIVE = not IS_NEGATIVE
else:
NEW_MESSAGE += MESSAGE[I]
return NEW_MESSAGE[::-1]
def ENCRYPT(MESSAGE):
MESSAGE = MESSAGE[::-1]
LENGTH = len(MESSAGE)
IS_POSITIVE = True
NEW_MESSAGE = ""
for I in range(LENGTH):
if MESSAGE[I] in ALPHABET:
INDEX = ALPHABET.index(MESSAGE[I])
if IS_POSITIVE:
INDEX += (I + 1)
else:
INDEX -= (I + 1)
INDEX %= ALPHABET_LENGTH
NEW_MESSAGE += ALPHABET[INDEX]
IS_POSITIVE = not IS_POSITIVE
else:
NEW_MESSAGE += MESSAGE[I]
return NEW_MESSAGE
while True:
print("\nWhat do you want to do:")
print("1) Encrypt Message")
print("2) Decrypt Message")
CHOICE = int(input("\n"))
if CHOICE == 1:
MESSAGE = ENCRYPT(MESSAGE)
if CHOICE == 2:
MESSAGE = DECRYPT(MESSAGE)
print("\n" + MESSAGE)
TEST
> python3 file.py
Input Message: An opportunity to teach is an opportunity to learn
What do you want to do:
1) Encrypt Message
2) Decrypt Message
1
OPDAQ HB OEWAGIBFXIU JD RI JZEZZ GC NFVBFJAGWJT KC
What do you want to do:
1) Encrypt Message
2) Decrypt Message
2
AN OPPORTUNITY TO TEACH IS AN OPPORTUNITY TO LEARN
What do you want to do:
1) Encrypt Message
2) Decrypt Message
You are starting i at the end of the string and then, you are increasing it. I think the line i += 1 should be i -= 1