|
@@ -0,0 +1,230 @@
|
|
|
+import sqlite3
|
|
|
+import tkinter as tk
|
|
|
+from tkinter import ttk
|
|
|
+import time
|
|
|
+
|
|
|
+# Создание таблицы для заполнения
|
|
|
+conn = sqlite3.connect("vigenere.db")
|
|
|
+cursor = conn.cursor()
|
|
|
+cursor.execute("""
|
|
|
+CREATE TABLE IF NOT EXISTS alphabets (
|
|
|
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
|
+ name TEXT UNIQUE,
|
|
|
+ alphabet TEXT
|
|
|
+)
|
|
|
+""")
|
|
|
+conn.commit()
|
|
|
+
|
|
|
+# Запись алфавита
|
|
|
+cursor.execute("SELECT COUNT(*) FROM alphabets")
|
|
|
+if cursor.fetchone()[0] == 0:
|
|
|
+ cursor.execute("INSERT INTO alphabets (name, alphabet) VALUES (?, ?)",
|
|
|
+ ("Русский (с Ё)", "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ"))
|
|
|
+ cursor.execute("INSERT INTO alphabets (name, alphabet) VALUES (?, ?)",
|
|
|
+ ("Русский (без Ё)", "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ"))
|
|
|
+ cursor.execute("INSERT INTO alphabets (name, alphabet) VALUES (?, ?)",
|
|
|
+ ("Русский (с подчеркиванием)", "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ"))
|
|
|
+ conn.commit()
|
|
|
+
|
|
|
+# Глобальная переменная для заполения алфавита выбранного
|
|
|
+alphabet = ""
|
|
|
+
|
|
|
+# Цветовая функция
|
|
|
+def get_color_for_key(letter):
|
|
|
+ colors = ["red", "blue", "green", "orange", "purple", "magenta", "cyan", "brown"]
|
|
|
+ return colors[ord(letter) % len(colors)]
|
|
|
+
|
|
|
+def build_table_lines():
|
|
|
+ cell_width = 3
|
|
|
+ # Выравнивание по првому краю
|
|
|
+ header = " " * cell_width + "".join([letter.rjust(cell_width) for letter in alphabet])
|
|
|
+
|
|
|
+ raw_key = key_entry.get().upper()
|
|
|
+ unique_key = ""
|
|
|
+ for ch in raw_key:
|
|
|
+ if ch in alphabet and ch not in unique_key:
|
|
|
+ unique_key += ch
|
|
|
+
|
|
|
+ rows = []
|
|
|
+ for letter in unique_key:
|
|
|
+ shift = alphabet.index(letter) + 1
|
|
|
+ rotated = alphabet[shift:] + alphabet[:shift]
|
|
|
+ row = letter.rjust(cell_width) + "".join([r.rjust(cell_width) for r in rotated])
|
|
|
+ rows.append(row)
|
|
|
+
|
|
|
+ return [header] + rows, unique_key
|
|
|
+
|
|
|
+def update_table():
|
|
|
+ lines, _ = build_table_lines()
|
|
|
+ full_text = "\n".join(lines)
|
|
|
+ table_display.config(state="normal")
|
|
|
+ table_display.delete("1.0", "end")
|
|
|
+ table_display.insert("1.0", full_text)
|
|
|
+ table_display.config(state="disabled")
|
|
|
+
|
|
|
+def update_table_in_text(content):
|
|
|
+ table_display.config(state="normal")
|
|
|
+ table_display.delete("1.0", "end")
|
|
|
+ table_display.insert("1.0", content)
|
|
|
+ table_display.config(state="disabled")
|
|
|
+
|
|
|
+def animate_intersection(key_letter, plaintext_letter, ciphertext_letter):
|
|
|
+
|
|
|
+ # Анимация сканирования и движения для выбранной буквы ключа
|
|
|
+
|
|
|
+ cell_width = 3
|
|
|
+ lines, unique_key = build_table_lines()
|
|
|
+ if key_letter not in unique_key:
|
|
|
+ return
|
|
|
+ row_index = unique_key.index(key_letter) + 1
|
|
|
+
|
|
|
+ shift = alphabet.index(key_letter) + 1
|
|
|
+ rotated = alphabet[shift:] + alphabet[:shift]
|
|
|
+ try:
|
|
|
+ target_col = rotated.index(ciphertext_letter)
|
|
|
+ except ValueError:
|
|
|
+ target_col = 0
|
|
|
+
|
|
|
+ # Пробег по таблице
|
|
|
+ for j in range(len(alphabet)):
|
|
|
+ new_lines = list(lines)
|
|
|
+ row = new_lines[row_index]
|
|
|
+ cells = [row[i:i+cell_width] for i in range(0, len(row), cell_width)]
|
|
|
+ if j < len(cells) - 1:
|
|
|
+ cells[j+1] = "(" + rotated[j].strip() + ")"
|
|
|
+ new_lines[row_index] = key_letter.rjust(cell_width) + "".join(cells[1:])
|
|
|
+ update_table_in_text("\n".join(new_lines))
|
|
|
+ table_display.update()
|
|
|
+ time.sleep(0.2)
|
|
|
+ if j == target_col:
|
|
|
+ perform_upward_animation(key_letter, target_col, rotated,
|
|
|
+ row_index, cell_width, lines)
|
|
|
+ break
|
|
|
+
|
|
|
+def perform_upward_animation(key_letter, target_col, rotated, row_index, cell_width, base_lines):
|
|
|
+
|
|
|
+ #Анимация подъёма найденной ячейки.
|
|
|
+
|
|
|
+ floating_frames = 4
|
|
|
+ for frame in range(floating_frames):
|
|
|
+ new_lines = list(base_lines)
|
|
|
+ new_row_index = row_index - (frame + 1)
|
|
|
+ if new_row_index < 1:
|
|
|
+ new_row_index = 1
|
|
|
+ # Обновляем строку с буквой ключа
|
|
|
+ orig_line = new_lines[row_index]
|
|
|
+ cells = [orig_line[i:i+cell_width] for i in range(0, len(orig_line), cell_width)]
|
|
|
+ cells[target_col+1] = rotated[target_col].rjust(cell_width)
|
|
|
+ new_lines[row_index] = key_letter.rjust(cell_width) + "".join(cells[1:])
|
|
|
+
|
|
|
+ # Обновляем строку куда перемещаеться
|
|
|
+ float_line = new_lines[new_row_index]
|
|
|
+ float_cells = [float_line[i:i+cell_width] for i in range(0, len(float_line), cell_width)]
|
|
|
+ if target_col+1 < len(float_cells):
|
|
|
+ float_cells[target_col+1] = rotated[target_col].center(cell_width)
|
|
|
+ else:
|
|
|
+ float_cells.append(rotated[target_col].center(cell_width))
|
|
|
+ new_lines[new_row_index] = "".join(float_cells)
|
|
|
+
|
|
|
+ update_table_in_text("\n".join(new_lines))
|
|
|
+ table_display.config(state="normal")
|
|
|
+ line_num = new_row_index + 1
|
|
|
+ start_col = (target_col+1) * cell_width
|
|
|
+ end_col = start_col + cell_width
|
|
|
+ table_display.tag_remove("highlight", "1.0", "end")
|
|
|
+ table_display.tag_add("highlight", f"{line_num}.{start_col}", f"{line_num}.{end_col}")
|
|
|
+ # Выбор цвета
|
|
|
+ table_display.tag_config("highlight", foreground=get_color_for_key(key_letter))
|
|
|
+ table_display.config(state="disabled")
|
|
|
+ table_display.update()
|
|
|
+ time.sleep(0.3)
|
|
|
+ time.sleep(0.5)
|
|
|
+ update_table()
|
|
|
+
|
|
|
+def vigenere_cipher(text, decrypt=False):
|
|
|
+
|
|
|
+ text = text.upper()
|
|
|
+ key = key_entry.get().upper()
|
|
|
+ if not key:
|
|
|
+ return text
|
|
|
+ result = ""
|
|
|
+ for i, char in enumerate(text):
|
|
|
+ if char in alphabet:
|
|
|
+ current_key = key[i % len(key)]
|
|
|
+ shift = alphabet.index(current_key)
|
|
|
+ if decrypt:
|
|
|
+ new_index = (alphabet.index(char) - shift) % len(alphabet)
|
|
|
+ else:
|
|
|
+ new_index = (alphabet.index(char) + shift) % len(alphabet)
|
|
|
+ output_letter = alphabet[new_index]
|
|
|
+ if decrypt:
|
|
|
+ animate_intersection(current_key, output_letter, char)
|
|
|
+ else:
|
|
|
+ animate_intersection(current_key, char, output_letter)
|
|
|
+ result += output_letter
|
|
|
+ else:
|
|
|
+ result += char
|
|
|
+ return result
|
|
|
+
|
|
|
+def encrypt():
|
|
|
+ update_table()
|
|
|
+ encrypted_text = vigenere_cipher(input_text.get(), decrypt=False)
|
|
|
+ output_text.config(text=encrypted_text)
|
|
|
+
|
|
|
+def decrypt():
|
|
|
+ update_table()
|
|
|
+ decrypted_text = vigenere_cipher(input_text.get(), decrypt=True)
|
|
|
+ output_text.config(text=decrypted_text)
|
|
|
+
|
|
|
+def load_alphabet(event=None):
|
|
|
+ global alphabet
|
|
|
+ selected = alphabet_var.get()
|
|
|
+ cursor.execute("SELECT alphabet FROM alphabets WHERE name = ?", (selected,))
|
|
|
+ result = cursor.fetchone()
|
|
|
+ if result:
|
|
|
+ alphabet = result[0]
|
|
|
+ # Вариант с подчеркиванием
|
|
|
+ if selected == "Русский (с подчеркиванием)" and not alphabet.endswith("_"):
|
|
|
+ alphabet += "_"
|
|
|
+ update_table()
|
|
|
+
|
|
|
+# Интерфейс
|
|
|
+root = tk.Tk()
|
|
|
+root.title("Шифр Виженера")
|
|
|
+root.geometry("800x600")
|
|
|
+
|
|
|
+alphabet_var = tk.StringVar()
|
|
|
+ttk.Label(root, text="Выберите алфавит").pack()
|
|
|
+cursor.execute("SELECT name FROM alphabets")
|
|
|
+alphabet_options = [row[0] for row in cursor.fetchall()]
|
|
|
+alphabet_menu = ttk.Combobox(root, textvariable=alphabet_var, values=alphabet_options, state="readonly")
|
|
|
+alphabet_menu.pack()
|
|
|
+alphabet_menu.bind("<<ComboboxSelected>>", load_alphabet)
|
|
|
+
|
|
|
+ttk.Label(root, text="Введите ключ").pack()
|
|
|
+key_entry = tk.Entry(root)
|
|
|
+key_entry.pack()
|
|
|
+key_entry.bind("<KeyRelease>", lambda event: update_table())
|
|
|
+
|
|
|
+table_display = tk.Text(root, font=("Courier", 14), bd=0, highlightthickness=0, wrap="none")
|
|
|
+table_display.pack(pady=10, fill="x")
|
|
|
+table_display.tag_config("highlight", foreground="red")
|
|
|
+table_display.config(state="disabled")
|
|
|
+
|
|
|
+ttk.Label(root, text="Введите текст").pack()
|
|
|
+input_text = tk.Entry(root)
|
|
|
+input_text.pack(pady=5)
|
|
|
+
|
|
|
+buttons_frame = tk.Frame(root)
|
|
|
+buttons_frame.pack(pady=10)
|
|
|
+encrypt_button = tk.Button(buttons_frame, text="Зашифровать", command=encrypt)
|
|
|
+encrypt_button.pack(side=tk.LEFT, padx=10)
|
|
|
+decrypt_button = tk.Button(buttons_frame, text="Дешифровать", command=decrypt)
|
|
|
+decrypt_button.pack(side=tk.RIGHT, padx=10)
|
|
|
+
|
|
|
+ttk.Label(root, text="Результат:").pack()
|
|
|
+output_text = tk.Label(root, text="", fg="red", font=("Courier", 14))
|
|
|
+output_text.pack(pady=10)
|
|
|
+
|
|
|
+root.mainloop()
|
|
|
+conn.close()
|