0

I have a program which I'm using to encrypt and decrypt user inputted text, and then outputting the result onto the GUI for my user to see.

vigernkey = open("vigernkey.txt", "r+")  # opens the text file
finish_message = ""
ciphertext_file = open("cip.txt", "r+")  # opens the text file for the ciphertext
pygame.init()  # initialises the library that allows a GUI to be opened


# Encrypt subroutine:
def vigenere(x):
    ciphertext = []
    vigkey = []  # this declares the list which will store the key for each individual letter
    for letter in x:
        individualletterkey = secrets.choice(string.ascii_letters)  # this generates the key for each letter as a
        # random character in the ASCII set
        newletter = ord(letter) ^ ord(individualletterkey)  # This transforms the letters of the key and the
        # plaintext into numbers  and performs an XOR operation on the two to create the encoding of the ciphertext
        # character
        vigkey.append(individualletterkey)  # this stores the key of each letter in a list, so it can be passed on
        # to the intended recipient for decryption
        ciphertext.append(newletter)  # this adds the newly encrypted letter to the ciphertext
    for element in vigkey:  # this loop ensures that the key for every letter is in a text file that can be passed
        # on to the intended recipient for them to decrypt the ciphertext
        vigernkey.write(str(element))
        vigernkey.write("\n")  # Each character in the key will be stored in an individual line
    for element in ciphertext:
        ciphertext_file.write(str(element))  # Each character in the ciphertext will be stored in a line in a file
        ciphertext_file.write("\n")
    global finish_message
    finish_message = "The key is in the file vigernkey.txt, and the ciphertext is in the file cip.txt"
    return ciphertext, finish_message


# Decrypt subroutine:
def vigenere_decrypt(y):
    y = [int(x) for x in y]
    Plaintext = ""  # this declares the plaintext variable
    vigkey = vigernkey.read().splitlines()
    for i in range(len(y)):
        newletter = chr(y[i] ^ ord(vigkey[i]))
        Plaintext += newletter  # this adds each newly decrypted character to the Plaintext
    return Plaintext


# GUI creation:
WIDTH, HEIGHT = 900, 500  # this declares the size of the window the GUI will open in
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Vigenere cipher")  # this titles the window
FPS = 60  # this declares the  magnitude of the framerate of the window
TRANSPARENT = (0, 0, 0, 0)  # This tuple allows objects on the screen to "disappear" when they are no longer needed
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)


class Button:  # This class will be used as buttons to allow the user to make selections in the program

    def __init__(self, x, y, image):
        self.image = image
        self.rect = self.image.get_rect()
        self.rect.topleft = (x, y)

    def draw(self):  # This method allows the button to draw itself on the screen
        WIN.blit(self.image, (self.rect.x, self.rect.y))

    def isclicked(self, event):
        x, y = pygame.mouse.get_pos()
        if event.type == pygame.MOUSEBUTTONDOWN:
            if self.rect.collidepoint(x, y):
                return 1
            else:
                return 0


class InputBox:

    def __init__(self, x, y, w, h, text=''):
        self.rect = pygame.Rect(x, y, w, h)
        self.colour = WHITE
        self.text = text
        self.txt_surface = FONT.render(text, True, self.colour)
        self.active = False
        self.done = False

    def handle_event(self, event):
        if event.type == pygame.MOUSEBUTTONDOWN:
            # If the user clicked on the input_box rect.
            if self.rect.collidepoint(event.pos):
                # Toggle the active variable.
                self.active = not self.active
            else:
                self.active = False
            self.colour = WHITE if self.active else BLUE
        if event.type == pygame.KEYDOWN:
            if self.active:
                if event.key == pygame.K_RETURN:
                    self.text = ''
                    self.done = True
                elif event.key == pygame.K_BACKSPACE:
                    self.text = self.text[:-1]
                else:
                    self.text += event.unicode
                # Re-render the text.
                self.txt_surface = FONT.render(self.text, True, self.colour)

    def update(self):
        # Resize the box if the text is too long.
        width = max(200, self.txt_surface.get_width() + 10)
        self.rect.w = width

    def draw(self, screen):
        # Blit the text.
        screen.blit(self.txt_surface, (self.rect.x + 5, self.rect.y + 5))
        # Blit the rect.
        pygame.draw.rect(screen, self.colour, self.rect, 2)


FONT = pygame.font.Font(None, 32)

encryptimg = pygame.image.load(os.path.join("Assets", "Encrypt_button.png"))  # This line and the next contain the
# images that will be the program's buttons and allow them to be utilised in the programs
decryptimg = pygame.image.load(os.path.join("Assets", "Decrypt_button.png"))

encrypt_button = Button(100, 150, encryptimg)  # These following two lines create the buttons to select the two main
# subroutines
decrypt_button = Button(550, 150, decryptimg)

textbox = InputBox(100, 100, 140, 32)
GREY = (54, 45, 45)


def draw_window():  # this function colours the window
    WIN.fill(GREY)  # this colours the window grey
    encrypt_button.draw()
    decrypt_button.draw()
    pygame.display.update()  # this updates the colouring of the window the next time the frame cycles


def reset_window():  # this functions draws a version of the window with a textbox instead of buttons
    WIN.fill(GREY)
    textbox.draw(WIN)
    pygame.display.update()


def Coursework():  # the application loop that all pygame programs require to function
    clock = pygame.time.Clock()  # this creates a variable, that, when a value is assigned to it, it will be the
    # refresh rate of the application
    run = True
    encrypt = False
    decrypt = False
    finished = False
    draw_window()
    while run:  # everything in this loop will only happen when the window is open
        clock.tick(FPS)  # this refreshes the frame every 1/FPS seconds, setting a framerate for the program
        for event in pygame.event.get():  # the event loop that ensures that any events are properly managed
            if event.type == pygame.QUIT:
                run = False  # this closes the window if the user quits the program
            textbox.handle_event(event)
            if encrypt_button.isclicked(event) == 1:  # The two following loops create a text box on the screen
                # when one of the options is chosen
                reset_window()
                encrypt = True
            if decrypt_button.isclicked(event):
                reset_window()
                decrypt = True

        if encrypt:  # the following code encrypts the user input and outputs a message onto the screen
            ciphertext_file.truncate(0)
            vigernkey.truncate(0)
            vigernkey.seek(0)
            ciphertext_file.seek(0)
            reset_window()
            textbox.update()
            if textbox.done:
                encr_text = vigenere(textbox.text)
                print(finish_message)
                textbox.text = finish_message

        elif decrypt:  # the following code decrypts the contents of cip.txt and outputs the result onto the screen
            reset_window()
            textbox.update()
            if textbox.done:
                ciphtext = ciphertext_file.read().splitlines()
                decr_text = vigenere_decrypt(ciphtext)
                print(decr_text)
                textbox.text = decr_text

    pygame.quit()


if __name__ == "__main__":  # this ensures that the GUI will open when this specific program is running
    Coursework()

However, when the encrypt and decrypt subroutines have finished and I want to output their text, the program doesn't stop when the text has been outputted. What happens is that the code repeats the function; in the encrypt case, for example, the program would encrypt the inputted text, output the variable "finish_message" onto the screen, and then repeate the function on the text currently in the text box - in this case the variable finish_message.

I've tried to stop it by setting self.active and self.done to false at the end of the if loops, but what this does is it stops the text from being encrypted/decrypted at all. How can I effectively stop this function but still allow it to decrypt/encrypt the initial input?

EDIT: I tried to use the finished variable in this manner:

        if not finished:
            if encrypt:  # the following code encrypts the user input and outputs a message onto the screen
                ciphertext_file.truncate(0)
                vigernkey.truncate(0)
                vigernkey.seek(0)
                ciphertext_file.seek(0)
                reset_window()
                textbox.update()
                if textbox.done:
                    encr_text = vigenere(textbox.text)
                    print(finish_message)
                    textbox.text = finish_message
                    finished = True

            elif decrypt:  # the following code decrypts the contents of cip.txt and outputs the result onto the screen
                reset_window()
                textbox.update()
                if textbox.done:
                    ciphtext = ciphertext_file.read().splitlines()
                    decr_text = vigenere_decrypt(ciphtext)
                    print(decr_text)
                    textbox.text = decr_text
                    finished = True

but then the text I was trying to output didn't output.

  • don't stop/freeze` `mainloop` but use variable ie. `paused = True` to control if some code has to be executed in `mainloop` – furas Oct 13 '22 at 15:45
  • you defined `finished = False` but you never use it - and this can be your problem. Maybe in some moment you should set it `finished = True` and all code run in `if not finished:` – furas Oct 13 '22 at 15:47
  • @furas when I use finished The text doesn't appear on the screen, sorry I should have mentioned that in the main text of the question – Hackerman4356 Oct 14 '22 at 10:21
  • Maybe first use `print()` (and `print(type(...))`, `print(len(...))`, etc.) to see which part of code is executed and what you really have in variables. It is called `"print debuging"` and it helps to see what code is really doing. – furas Oct 14 '22 at 12:22

0 Answers0