Search code examples
pythonencryptionmethodsreplace

How can I ensure incremental changes in deciphered messages in Python substitution cipher decoding?


I am working on a decipher method. I want to decipher a sentence manually by user input.

import random


class Cryptography:
    def __init__(self, input_file):
        self.input_file = input_file
        with open(self.input_file, 'r+') as file:
            self.content = file.read()
        self.sentence = ''
        self.code = {
            'A': 'A', 'Ą': 'A', 'B': 'A', 'C': 'A',
            'Ć': 'A', 'D': 'A', 'E': 'A', 'Ę': 'A',
            'F': 'A', 'G': 'A', 'H': 'A', 'I': 'A',
            'J': 'A', 'K': 'A', 'L': 'A', 'Ł': 'A',
            'M': 'A', 'N': 'A', 'Ń': 'A', 'O': 'A',
            'Ó': 'A', 'P': 'A', 'R': 'A', 'S': 'A',
            'Ś': 'A', 'T': 'A', 'U': 'A', 'W': 'A',
            'Y': 'A', 'Z': 'A', 'Ż': 'A', 'Ź': 'A',
        }
        self.replaced_sentence = ''
        self.welcome = '\nWITAJ\nMASZ TERAZ OKAZJE ODSZYFROWAĆ POWYŻSZĄ WIADOMOSĆ\nZA KAŻDYM RAZEM JAK ZAMIENISZ ' \
                       'LITERKI WYSWIETLONA ZOSTANIE\nCZĘŚCIOWO ODSZYFROWANA WIADOMOŚĆ.\nPOWODZENIA!\n '

    # repair converts whatever is in self.content to self.sentence, so it is one line of text without large whitespaces.
    def repair(self):
        for char in self.content:
            if char == '\n':
                char = char.replace('\n', ' ')
            char = char.capitalize()
            self.sentence += char
        self.sentence = " ".join(self.sentence.split())
        print(self.sentence)

    def encrypt(self):
        numbers = list(range(32))
        random.shuffle(numbers)
        letters = list(self.code.keys())
        encrypted_code = {}
        for i, letter in enumerate(letters):
            encrypted_code[letter] = letters[numbers[i]]
        self.code = encrypted_code
        print(f"Encrypted successfully!")

    def transform(self):
        special_char = [' ', ',', '!', '.', '(', ')', ';',]
        for char in self.sentence:
            if char in special_char:
                replaced_char = char
            else:
                replaced_char = self.code.get(char)
            self.replaced_sentence += replaced_char

    def decode(self):
        guessed_sentence = self.replaced_sentence
        spec_char = zip([' ', ',', '!', '.', '(', ')', ';'], [' ', ',', '!', '.', '(', ')', ';'])
        self.code.update(spec_char)
        while True:
            print(guessed_sentence)
            guess = input('please type eg. A = S : ')
            guess = guess.strip()
            guess = guess.replace(' ', '')
            letter1 = guess[0].upper()
            letter2 = guess[2].upper()
            char_mapping = self.code
            char_mapping[letter1] = letter2
            old_string = self.replaced_sentence
            guessed_sentence = ''
            for char in old_string:
                guessed_sentence += char_mapping[char]
            if guessed_sentence == self.sentence:
                break


test = Cryptography('message')
test.repair()
test.encrypt()
test.transform()
test.decode()
  1. __init__(self, input_file): Initializes the Cryptography class with an input file. It reads the content of the input file and initializes attributes such as sentence, code, replaced_sentence, and welcome.

  2. repair(self): Processes the content read from the input file, removes extra whitespaces, capitalizes characters, and stores the processed sentence in the self.sentence attribute.

  3. encrypt(self): Generates a random mapping of letters based on the original mapping provided in self.code, effectively encrypting the message.

  4. transform(self): Applies the encryption mapping generated in encrypt method to transform the original sentence into an encrypted one, storing the result in self.replaced_sentence.

  5. decode(self): Initiates the deciphering process. It prompts the user to input letter substitutions, applies those substitutions to the encrypted message, and prints the partially deciphered message until it matches the original sentence.

self.welcome is not used in this version, it is just aestethics, also in polish so it doesn't matter.

I want an output that shows encrypted message but with changes only where implemented.

To clarify, here is the output of the whole function (sentence is in polish but I don't think it will disturb understanting of the case):

LITWO! OJCZYZNO MOJA! TY JESTEŚ JAK ZDROWIE.
Encrypted successfully!
UDŹHĘ! ĘJZMŻMEĘ TĘJŃ! ŹŻ JAGŹAI JŃŁ MBĆĘHDA.
please type eg. A = S : U=L
LBCRL! LJMTWTAL ŹLJÓ! CW JŃOCŃD JÓF TĄSLRBŃ.
please type eg. A = S : D=I
LICRL! LJMTWTAL ŹLJÓ! CW JŃOCŃD JÓF TĄSLRIŃ.
please type eg. A = S : Ź=T
LITRL! LJMTWTAL ŹLJÓ! TW JŃOTŃD JÓF TĄSLRIŃ.
please type eg. A = S : 

As you can see the encrypted message changes everytime I make changes. This is the outcome that I pursue:

LITWO! OJCZYZNO MOJA! TY JESTEŚ JAK ZDROWIE.
Encrypted successfully!
UDŹHĘ! ĘJZMŻMEĘ TĘJŃ! ŹŻ JAGŹAI JŃŁ MBĆĘHDA.
please type eg. A = S : U=L
LDŹHĘ! ĘJZMŻMEĘ TĘJŃ! ŹŻ JAGŹAI JŃŁ MBĆĘHDA.
please type eg. A = S : D=I
LIŹHĘ! ĘJZMŻMEĘ TĘJŃ! ŹŻ JAGŹAI JŃŁ MBĆĘHIA.
please type eg. A = S : Ź=T
LITHĘ! ĘJZMŻMEĘ TĘJŃ! TŻ JAGTAI JŃŁ MBĆĘHIA.
please type eg. A = S : 

How can I change the code so it produces desired outcome?


Solution

  • Heavily refactored solution. The key is to use str.translate along with a current list of replacements to generate the partially decoded message from the encrypted message each time. Because translating one letter to say 'A' might be confusing with an untranslated 'A', I print the current translation and original sentence each time to make it easier to use (for me, anyway):

    import random
    
    class Cryptography:
        def __init__(self, message):
            self.sentence = message.upper()
            self.alphabet = 'AĄBCĆDEĘFGHIJKLŁMNŃOÓPRSŚTUWYZŻŹ'
            keys = [ord(a) for a in self.alphabet] # keys must be ordinals
            values = list(keys)  # need mutable list for shuffle
            random.shuffle(values)
            self.code = dict(zip(keys, values))  # build translation table
            self.replaced_sentence = self.sentence.translate(self.code)  # translate
            print(f'Encrypted successfully!')
    
        def decode(self):
            guessed_sentence = self.replaced_sentence
            # build up a translation table.  Start with hyphens for unknowns.
            guessed_code = dict(zip([ord(a) for a in self.alphabet], '-' * len(self.alphabet)))
            while True:
                print(self.replaced_sentence)
                guess = input('please type eg. A = S : ')
                guess = guess.strip()
                guess = guess.replace(' ', '')
                letter1 = guess[0].upper()
                letter2 = guess[2].upper()
                guessed_code[ord(letter1)] = ord(letter2)  # update translation table
                guessed_sentence = self.replaced_sentence.translate(guessed_code)  # translate
                print(guessed_sentence)
                if guessed_sentence == self.sentence:
                    print('Success!')
                    break
    
    test = Cryptography('Litwo! Ojczyzno moja! Ty jesteś jak zdrowie.')
    test.decode()
    

    Output:

    Encrypted successfully!
    SWŹJI! IOZBMBFI KIOŁ! ŹM OARŹAY OŁH BĆĘIJWA.
    please type eg. A = S : s=l
    L----! -------- ----! -- ------ --- -------.
    SWŹJI! IOZBMBFI KIOŁ! ŹM OARŹAY OŁH BĆĘIJWA.
    please type eg. A = S : w=i
    LI---! -------- ----! -- ------ --- -----I-.
    SWŹJI! IOZBMBFI KIOŁ! ŹM OARŹAY OŁH BĆĘIJWA.
    please type eg. A = S : Ź=i
    LII--! -------- ----! I- ---I-- --- -----I-.
    SWŹJI! IOZBMBFI KIOŁ! ŹM OARŹAY OŁH BĆĘIJWA.
    please type eg. A = S : Ź=t
    LIT--! -------- ----! T- ---T-- --- -----I-.
    SWŹJI! IOZBMBFI KIOŁ! ŹM OARŹAY OŁH BĆĘIJWA.
    please type eg. A = S : j=w
    LITW-! -------- ----! T- ---T-- --- ----WI-.
    SWŹJI! IOZBMBFI KIOŁ! ŹM OARŹAY OŁH BĆĘIJWA.
    please type eg. A = S : i=o
    LITWO! O------O -O--! T- ---T-- --- ---OWI-.
    SWŹJI! IOZBMBFI KIOŁ! ŹM OARŹAY OŁH BĆĘIJWA.
    please type eg. A = S : o=j
    LITWO! OJ-----O -OJ-! T- J--T-- J-- ---OWI-.
    SWŹJI! IOZBMBFI KIOŁ! ŹM OARŹAY OŁH BĆĘIJWA.
    please type eg. A = S : z=c
    LITWO! OJC----O -OJ-! T- J--T-- J-- ---OWI-.
    SWŹJI! IOZBMBFI KIOŁ! ŹM OARŹAY OŁH BĆĘIJWA.
    please type eg. A = S : b=z
    LITWO! OJCZ-Z-O -OJ-! T- J--T-- J-- Z--OWI-.
    SWŹJI! IOZBMBFI KIOŁ! ŹM OARŹAY OŁH BĆĘIJWA.
    please type eg. A = S : m=y
    LITWO! OJCZYZ-O -OJ-! TY J--T-- J-- Z--OWI-.
    SWŹJI! IOZBMBFI KIOŁ! ŹM OARŹAY OŁH BĆĘIJWA.
    please type eg. A = S : f=n
    LITWO! OJCZYZNO -OJ-! TY J--T-- J-- Z--OWI-.
    SWŹJI! IOZBMBFI KIOŁ! ŹM OARŹAY OŁH BĆĘIJWA.
    please type eg. A = S : k=m
    LITWO! OJCZYZNO MOJ-! TY J--T-- J-- Z--OWI-.
    SWŹJI! IOZBMBFI KIOŁ! ŹM OARŹAY OŁH BĆĘIJWA.
    please type eg. A = S : Ł=a
    LITWO! OJCZYZNO MOJA! TY J--T-- JA- Z--OWI-.
    SWŹJI! IOZBMBFI KIOŁ! ŹM OARŹAY OŁH BĆĘIJWA.
    please type eg. A = S : a=e
    LITWO! OJCZYZNO MOJA! TY JE-TE- JA- Z--OWIE.
    SWŹJI! IOZBMBFI KIOŁ! ŹM OARŹAY OŁH BĆĘIJWA.
    please type eg. A = S : r=s
    LITWO! OJCZYZNO MOJA! TY JESTE- JA- Z--OWIE.
    SWŹJI! IOZBMBFI KIOŁ! ŹM OARŹAY OŁH BĆĘIJWA.
    please type eg. A = S : y=ś
    LITWO! OJCZYZNO MOJA! TY JESTEŚ JA- Z--OWIE.
    SWŹJI! IOZBMBFI KIOŁ! ŹM OARŹAY OŁH BĆĘIJWA.
    please type eg. A = S : h=k
    LITWO! OJCZYZNO MOJA! TY JESTEŚ JAK Z--OWIE.
    SWŹJI! IOZBMBFI KIOŁ! ŹM OARŹAY OŁH BĆĘIJWA.
    please type eg. A = S : Ć=d
    LITWO! OJCZYZNO MOJA! TY JESTEŚ JAK ZD-OWIE.
    SWŹJI! IOZBMBFI KIOŁ! ŹM OARŹAY OŁH BĆĘIJWA.
    please type eg. A = S : Ę=r
    LITWO! OJCZYZNO MOJA! TY JESTEŚ JAK ZDROWIE.
    Success!