Explorar o código

Загрузить файлы 'ОАиП/2025-26/36гр/1 сем/Гуркин'

u23-27gurkin hai 1 semana
pai
achega
f4deb43990

BIN=BIN
ОАиП/2025-26/36гр/1 сем/Гуркин/taxicab_results.db


+ 218 - 0
ОАиП/2025-26/36гр/1 сем/Гуркин/Проверка_чисел_такси.py

@@ -0,0 +1,218 @@
+import tkinter as tk
+from tkinter import messagebox
+import sqlite3
+import math
+
+class TaxicabFinder:
+    def __init__(self, window):
+        self.window = window
+        self.window.title("Проверка чисел Такси")
+        self.window.geometry("500x300")
+        
+        # Создание элементов интерфейса
+        self.info_label = tk.Label(
+            window, 
+            text="Проверить, можно ли представить число как сумму кубов двумя разными способами",
+            wraplength=400,
+            justify="center"
+        )
+        self.info_label.pack(pady=10)
+        
+        # Поле для ввода числа
+        self.input_frame = tk.Frame(window)
+        self.input_frame.pack(pady=10)
+        
+        self.input_label = tk.Label(self.input_frame, text="Введите число для проверки:")
+        self.input_label.pack(side=tk.LEFT, padx=5)
+        
+        self.number_entry = tk.Entry(self.input_frame, width=15)
+        self.number_entry.pack(side=tk.LEFT, padx=5)
+        self.number_entry.bind('<Return>', lambda event: self.check_number())  # Поиск по Enter
+
+        # Кнопки
+        self.button_frame = tk.Frame(window)
+        self.button_frame.pack(pady=10)
+        
+        self.check_button = tk.Button(
+            self.button_frame, 
+            text="Проверить число", 
+            command=self.check_number,
+            bg="lightblue"
+        )
+        self.check_button.pack(side=tk.LEFT, padx=5)
+        
+        self.find_button = tk.Button(
+            self.button_frame, 
+            text="Найти следующее число Такси", 
+            command=self.find_next_taxicab,
+            bg="lightgreen"
+        )
+        self.find_button.pack(side=tk.LEFT, padx=5)
+        
+        # Область вывода результатов
+        self.output_label = tk.Label(window, text="Результат: ", wraplength=450, justify="left")
+        self.output_label.pack(pady=10)
+        
+        # История поиска
+        self.history_label = tk.Label(window, text="История найденных чисел:", font=("Arial", 10, "bold"))
+        self.history_label.pack(pady=(20, 5))
+        
+        self.history_text = tk.Text(window, height=6, width=60)
+        self.history_text.pack(pady=5)
+        # Подготовка базы данных
+        self.setup_database()
+        
+        # Загрузка истории
+        self.load_history()
+
+    def setup_database(self):
+        """Настройка базы данных для хранения результатов"""
+        self.db_connection = sqlite3.connect('taxicab_results.db')
+        self.db_cursor = self.db_connection.cursor()
+        self.db_cursor.execute('''
+            CREATE TABLE IF NOT EXISTS found_numbers (
+                id INTEGER PRIMARY KEY AUTOINCREMENT,
+                taxicab_number INTEGER,
+                first_num1 INTEGER, first_num2 INTEGER,
+                second_num1 INTEGER, second_num2 INTEGER
+            )
+        ''')
+        self.db_connection.commit()
+
+    def check_number(self):
+        """Проверка введенного числа"""
+        try:
+            number = int(self.number_entry.get())
+            if number <= 0:
+                messagebox.showerror("Ошибка", "Пожалуйста, введите положительное число")
+                return
+        except ValueError:
+            messagebox.showerror("Ошибка", "Пожалуйста, введите целое число")
+            return
+        
+        # Поиск представлений числа как суммы двух кубов
+        representations = self.find_cube_representations(number)
+        
+        if len(representations) >= 2:
+            # Нашли число Такси
+            result_text = f" Число {number} ЯВЛЯЕТСЯ числом Такси!\n\n"
+            for i, (a, b) in enumerate(representations[:2], 1):
+                result_text += f" Способ {i}: {a}³ + {b}³ = {a**3} + {b**3} = {a**3 + b**3}\n"
+            
+            # Сохраняем в базу данных
+            self.save_result(number, representations[0], representations[1])
+            self.output_label.config(text=result_text, fg="green")
+            
+        else:
+            # Не нашли достаточно представлений
+            if len(representations) == 1:
+                result_text = f" Число {number} можно представить как сумму кубов только одним способом:\n"
+                a, b = representations[0]
+                result_text += f"{a}³ + {b}³ = {a**3} + {b**3} = {number}"
+            else:
+                result_text = f" Число {number} НЕЛЬЗЯ представить как сумму двух кубов"
+            
+            self.output_label.config(text=result_text, fg="red")
+        
+        # Обновляем историю
+        self.load_history()
+
+    def find_cube_representations(self, number):
+        """Найти все представления числа как суммы двух кубов"""
+        representations = []
+        max_cube = int(round(number ** (1/3))) + 1
+        
+        for a in range(1, max_cube + 1):
+            a_cube = a ** 3
+            if a_cube > number:
+                continue
+
+            remaining = number - a_cube
+            b = round(remaining ** (1/3))
+
+            if b >= a and b ** 3 == remaining:  # b >= a, чтобы избежать дубликатов
+                representations.append((a, b))
+
+        return representations
+
+    def find_next_taxicab(self):
+        """Найти следующее число Такси (автоматический поиск)"""
+        self.output_label.config(text="Поиск следующего числа Такси...", fg="blue")
+        self.window.update()
+
+        found_numbers = self.get_existing_numbers()
+        current_number = max(found_numbers) + 1 if found_numbers else 1
+
+        while True:
+            representations = self.find_cube_representations(current_number)
+
+            if len(representations) >= 2:
+                # Нашли число Такси
+                result_text = f" Найдено число Такси: {current_number}\n\n"
+                for i, (a, b) in enumerate(representations[:2], 1):
+                    result_text += f" Способ {i}: {a}³ + {b}³ = {a**3} + {b**3} = {a**3 + b**3}\n"
+
+                # Сохраняем в базу данных
+                self.save_result(current_number, representations[0], representations[1])
+                self.output_label.config(text=result_text, fg="green")
+                self.number_entry.delete(0, tk.END)
+                self.number_entry.insert(0, str(current_number))
+                # Обновляем историю
+                self.load_history()
+                break
+
+            current_number += 1
+
+            # Защита от бесконечного цикла (на всякий случай)
+            if current_number > 10**7:
+                messagebox.showwarning("Прервано", "Поиск прерван на большом числе")
+                self.output_label.config(text="Поиск прерван", fg="orange")
+                break
+
+    def get_existing_numbers(self):
+        """Получить список уже найденных чисел из базы данных"""
+        self.db_cursor.execute("SELECT taxicab_number FROM found_numbers")
+        return [row[0] for row in self.db_cursor.fetchall()]
+
+    def save_result(self, number, first_pair, second_pair):
+        """Сохранение найденного числа в базу данных"""
+        # Проверяем, нет ли уже этого числа в базе
+        self.db_cursor.execute("SELECT id FROM found_numbers WHERE taxicab_number = ?", (number,))
+        if not self.db_cursor.fetchone():
+            self.db_cursor.execute('''
+                INSERT INTO found_numbers (taxicab_number, first_num1, first_num2, second_num1, second_num2)
+                VALUES (?, ?, ?, ?, ?)
+            ''', (number, first_pair[0], first_pair[1], second_pair[0], second_pair[1]))
+            self.db_connection.commit()
+
+    def load_history(self):
+        """Загрузка истории найденных чисел"""
+        self.db_cursor.execute('''
+            SELECT taxicab_number, first_num1, first_num2, second_num1, second_num2 
+            FROM found_numbers 
+            ORDER BY taxicab_number
+        ''')
+        results = self.db_cursor.fetchall()
+
+        self.history_text.delete(1.0, tk.END)
+
+        if not results:
+            self.history_text.insert(tk.END, "История пуста")
+            return
+
+        for row in results:
+            number, a1, b1, a2, b2 = row
+            history_line = f"{number} = {a1}³ + {b1}³ = {a2}³ + {b2}³\n"
+            self.history_text.insert(tk.END, history_line)
+
+    def close_connection(self):
+        """Закрытие соединения с базой данных"""
+        if hasattr(self, 'db_connection'):
+            self.db_connection.close()
+
+if __name__ == "__main__":
+    main_window = tk.Tk()
+    app = TaxicabFinder(main_window)
+    main_window.mainloop()
+    app.close_connection()
+    

+ 188 - 0
ОАиП/2025-26/36гр/1 сем/Гуркин/Техническое задание.md

@@ -0,0 +1,188 @@
+### Техническое задание: программа «Taxicab Finder» («Поиск чисел Такси»)
+
+
+#### 1. Общее описание продукта
+
+**1.1. Название**  
+«Taxicab Finder» (Поиск чисел Такси).
+
+**1.2. Суть продукта**  
+Десктоп‑приложение на языке Python, позволяющее исследовать числа, которые можно представить в виде суммы двух кубов натуральных чисел **двумя или более различными способами** (так называемые числа Такси).
+
+**1.3. Цель разработки**  
+Создать инструмент для:
+* проверки произвольных чисел на свойство числа Такси;
+* автоматического поиска новых чисел Такси;
+* накопления и просмотра истории найденных чисел;
+* наглядной демонстрации математического свойства чисел.
+
+**1.4. Сфера применения**  
+* образование (уроки математики, факультативы, проектная деятельность);
+* самостоятельные математические исследования;
+* популяризация математики и числовых головоломок;
+* демонстрация применения программирования в теории чисел.
+
+
+#### 2. Функциональные требования
+
+**2.1. Проверка введённого числа**  
+Программа должна:
+* принимать от пользователя целое положительное число;
+* проверять корректность ввода (тип данных, знак);
+* искать все возможные представления числа в виде $a^3 + b^3$, где $a, b \in \mathbb{N}$ и $a \leq b$ (чтобы исключить зеркальные пары);
+* определять, является ли число числом Такси (есть ли минимум два разных представления);
+* выводить найденные способы представления числа;
+* визуально маркировать результат (цвет текста в зависимости от исхода).
+
+
+**2.2. Автоматический поиск следующего числа Такси**  
+Программа должна:
+* определять максимальное число из уже найденных (из локальной базы данных);
+* последовательно проверять числа, начиная с $N_{\text{max}} + 1$;
+* для каждого числа искать все представления в виде суммы двух кубов;
+* останавливаться при нахождении первого числа, имеющего два или более представления;
+* отображать найденное число и его представления;
+* сохранять результат в базу данных;
+* иметь защитный механизм от бесконечного поиска (ограничение по порогу, например, $10^7$).
+
+
+**2.3. Работа с историей найденных чисел**  
+Программа должна:
+* создавать и поддерживать локальную базу данных (SQLite);
+* сохранять каждое найденное число Такси с двумя способами его представления;
+* исключать дублирование записей (не сохранять одно и то же число дважды);
+* загружать и отображать историю найденных чисел при запуске и после каждой операции;
+* представлять историю в виде списка строк формата:  
+  $N = a^3 + b^3 = c^3 + d^3$;
+* сортировать историю по возрастанию чисел.
+
+**2.4. Обработка ошибок и уведомлений**  
+Программа должна реагировать на:
+* некорректный ввод (не число, отрицательное число, ноль) — выводить диалоговое окно с ошибкой;
+* отсутствие представлений числа в виде суммы кубов — сообщать, что число не представимо таким образом;
+* превышение порога поиска — выводить предупреждение и прерывать поиск;
+* другие исключительные ситуации — информировать пользователя через диалоговые окна.
+
+
+#### 3. Архитектурное описание
+
+**3.1. Общий принцип построения**  
+Программа реализована по шаблону **MVC (Model‑View‑Controller)** с дополнительным слоем доступа к данным:
+
+* **View (Представление)** — графический интерфейс пользователя на базе библиотеки `tkinter`.
+* **Controller (Контроллер)** — основной класс `TaxicabFinder`, обрабатывающий события и координирующий работу компонентов.
+* **Model (Модель)** — алгоритмы поиска представлений чисел и проверки на свойство Такси.
+* **Data Access Layer (Слой доступа к данным)** — работа с локальной базой данных SQLite.
+
+**3.2. Компоненты и их функции**
+
+* **Графический интерфейс (View)**  
+  Реализован с использованием модуля `tkinter`. Включает:
+  * главное окно с фиксированными размерами;
+  * информационные надписи;
+  * поле ввода числа;
+  * кнопки управления;
+  * область вывода результатов;
+  * текстовую область для отображения истории.
+
+* **Контроллер (Controller)**  
+  Класс `TaxicabFinder`:
+  * инициализирует интерфейс и подключает базу данных;
+  * обрабатывает события (нажатие кнопок, ввод с клавиатуры);
+  * вызывает алгоритмы модели для вычислений;
+  * обновляет интерфейс на основе полученных результатов;
+  * управляет жизненным циклом базы данных (открытие, закрытие).
+
+* **Модель (Model)**  
+  Содержит ключевые алгоритмы:
+  * `find_cube_representations(number)` — поиск всех пар $(a, b)$, таких что $a^3 + b^3 = \text{number}$;
+  * логика проверки, является ли число числом Такси (наличие ≥ 2 представлений);
+  * `find_next_taxicab()` — алгоритм поиска следующего числа Такси после уже найденных.
+
+* **Слой доступа к данным (Data Access Layer)**  
+  Реализован через модуль `sqlite3`:
+  * создаёт и поддерживает базу данных `taxicab_results.db`;
+  * обеспечивает CRUD‑операции (создание, чтение, обновление, удаление записей);
+  * предотвращает дублирование чисел в базе;
+  * загружает историю при старте и после каждой операции.
+
+**3.3. Структура базы данных**
+
+Используется одна таблица — `found_numbers`:
+
+* `id` — уникальный идентификатор записи (автоинкремент);
+* `taxicab_number` — само число Такси;
+* `first_num1`, `first_num2` — первое представление: $a^3 + b^3$;
+* `second_num1`, `second_num2` — второе представление: $c^3 + d^3$.
+
+
+Назначение: хранение найденных чисел и их представлений для последующего отображения в истории.
+
+#### 4. Описание пользовательского интерфейса
+
+**4.1. Главное окно**  
+* Размер: 500 × 300 пикселей.
+* Заголовок: «Проверка чисел Такси».
+* Фон: стандартный для `tkinter`.
+
+**4.2. Элементы интерфейса**
+
+* **Информационная надпись (вверху окна)**  
+  * Текст: «Проверить, можно ли представить число как сумму кубов двумя разными способами».
+  * Выравнивание: по центру.
+  * Перенос строк: при ширине 400 пикселей.
+  * Шрифт: стандартный.
+
+* **Панель ввода числа**  
+  * Контейнер: `Frame` для группировки элементов.
+  * Надпись слева: «Введите число для проверки:».
+  * Поле ввода (`Entry`):  
+    * ширина — 15 символов;
+    * привязка к событию `<Return>` (нажатие Enter) — запуск проверки числа.
+
+
+* **Панель кнопок (под панелью ввода)**  
+  * Контейнер: `Frame`.
+  * Кнопка «Проверить число»:  
+    * текст: «Проверить число»;
+    * цвет фона: светло‑голубой (`lightblue`);
+    * действие: вызов метода `check_number()`.
+  * Кнопка «Найти следующее число Такси»:  
+    * текст: «Найти следующее число Такси»;
+    * цвет фона: светло‑зелёный (`lightgreen`);
+    * действие: вызов метода `find_next_taxicab()`.
+
+* **Область вывода результата (под кнопками)**  
+  * Надпись слева: «Результат: ».
+  * Текстовое поле с переносом строк (ширина 450 пикселей).
+  * Цветовая индикация:  
+    * зелёный — число является числом Такси;
+    * красный — число не является числом Такси;
+    * синий — идёт процесс поиска;
+    * оранжевый — поиск прерван (превышен порог).
+
+
+* **Раздел истории (в нижней части окна)**  
+  * Надпись‑заголовок: «История найденных чисел:» (жирный шрифт, размер 10).
+  * Текстовая область (`Text`):  
+    * высота: 6 строк;
+    * ширина: 60 символов;
+    * формат вывода: $N = a^3 + b^3 = c^3 + d^3$;
+    * если история пуста — выводится текст: «История пуста».
+
+
+#### 5. Алгоритмы работы
+
+**5.1. Алгоритм проверки числа на свойство Такси**
+
+1. Получение ввода из поля `number_entry`.
+2. Проверка на целочисленность и положительность:
+   * если ввод не является числом — вывод ошибки;
+   * если число ≤ 0 — вывод ошибки.
+3. Поиск всех пар $(a, b)$ таких, что $a^3 + b^3 = N$:
+   * вычисление максимального возможного значения $a$:  
+     $\text{max\_cube} = \lfloor \sqrt[3]{N} \rfloor + 1$;
+   * перебор $a$ от 1 до $\text{max\_cube}$;
+   * для каждого $a$: вычисление $a^3$, затем остатка $r = N - a^3$;
+   * вычисление $b = \text{round}(\sqrt[3]{r})$;
+   * проверка условий: $b \geq a$ и $b^3 = r$ (чтобы избежать дубликатов и ошибок