From dab7ef852bcbd5815dec490f599806705c7e380a Mon Sep 17 00:00:00 2001 From: jze9 Date: Mon, 8 Dec 2025 09:46:07 +0500 Subject: [PATCH] finaly --- app/src/pages/main_page.py | 3 +- app/src/pages/tabs/arbitrary_calculator11.py | 1030 ++++++++++++++++++ app/src/step_by_step_solver.py | 185 +++- 3 files changed, 1167 insertions(+), 51 deletions(-) create mode 100644 app/src/pages/tabs/arbitrary_calculator11.py diff --git a/app/src/pages/main_page.py b/app/src/pages/main_page.py index 596f685..f139ee3 100644 --- a/app/src/pages/main_page.py +++ b/app/src/pages/main_page.py @@ -1,6 +1,6 @@ import flet as ft import designer as ds -from pages.tabs import start1,calculater2, binary_data3, binary_calculeator4, octogon_data5, octogon_calculeator6, sedecim_data7,sedecim_calculeator8, pentecostal_system9, pentecostal_calculeator10 +from pages.tabs import start1,calculater2, binary_data3, binary_calculeator4, octogon_data5, octogon_calculeator6, sedecim_data7,sedecim_calculeator8, pentecostal_system9, pentecostal_calculeator10, arbitrary_calculator11 class Main_page(ft.View): def __init__(self, page): @@ -26,6 +26,7 @@ class Main_page(ft.View): sedecim_calculeator8.Button_sedecim_calculator(), pentecostal_system9.Button_binary_data(), pentecostal_calculeator10.Button_quinquagesimal_calculator(), + arbitrary_calculator11.Button_arbitrary_calculator(), ft.Container( bgcolor="#280A3F", expand=True, diff --git a/app/src/pages/tabs/arbitrary_calculator11.py b/app/src/pages/tabs/arbitrary_calculator11.py new file mode 100644 index 0000000..85e7c0d --- /dev/null +++ b/app/src/pages/tabs/arbitrary_calculator11.py @@ -0,0 +1,1030 @@ +from designer import right_column +import flet as ft +import sys +import os + +# Добавляем путь к модулю step_by_step_solver +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +from step_by_step_solver import StepByStepSolver, Operation + +class Button_arbitrary_calculator(ft.CupertinoButton): + def __init__(self, text: str = "Произвольный калькулятор"): + self.result_add = ft.Text(value="0", size=30, width=400) + self.result_sub = ft.Text(value="0", size=30, width=400) + self.result_mult = ft.Text(value="0", size=30, width=400) + self.result_div = ft.Text(value="0", size=30, width=400) + + # Поля ввода для всех операций + self.input_add_1 = None + self.input_add_2 = None + self.input_sub_1 = None + self.input_sub_2 = None + self.input_mult_1 = None + self.input_mult_2 = None + self.input_div_1 = None + self.input_div_2 = None + + # Dropdowns для выбора систем счисления + self.base_add_1 = None + self.base_add_2 = None + self.base_add_result = None + + self.base_sub_1 = None + self.base_sub_2 = None + self.base_sub_result = None + + self.base_mult_1 = None + self.base_mult_2 = None + self.base_mult_result = None + + self.base_div_1 = None + self.base_div_2 = None + self.base_div_result = None + + # Контейнеры для пошагового решения + self.steps_add = ft.Column(scroll=ft.ScrollMode.AUTO, spacing=5) + self.steps_sub = ft.Column(scroll=ft.ScrollMode.AUTO, spacing=5) + self.steps_mult = ft.Column(scroll=ft.ScrollMode.AUTO, spacing=5) + self.steps_div = ft.Column(scroll=ft.ScrollMode.AUTO, spacing=5) + + # Стандартный набор цифр для систем до 36 + self.digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" + + super().__init__( + bgcolor="#00000000", + disabled_bgcolor="#3A1E51", + text=text, + color="white", + on_click=self.test_data + ) + + def validate_number(self, value: str, base: int) -> bool: + """Проверяет, является ли строка корректным числом в заданной системе счисления""" + if value is None or value == "": + return True + v = value.strip().upper() + if v == "": + return True + if v[0] == '-': + v = v[1:] + + valid_chars = self.digits[:base] + return all(c in valid_chars for c in v) + + def convert_to_base(self, number: str, from_base: int, to_base: int) -> str: + """Конвертирует число из одной системы в другую""" + if not number or number == "0": + return "0" + + # Используем solver для конвертации + solver = StepByStepSolver(base=from_base, digits=self.digits) + decimal_value = solver.to_decimal(number) + + # Конвертируем в целевую систему + target_solver = StepByStepSolver(base=to_base, digits=self.digits) + return target_solver.from_decimal(decimal_value) + + def create_step_card(self, title: str, subtitle: str, content: ft.Column) -> ft.Container: + """Создаёт карточку для шага решения""" + return ft.Container( + content=ft.Column([ + ft.Text(title, size=16, weight=ft.FontWeight.BOLD, color="#00FFFF"), + ft.Text(subtitle, size=14, weight=ft.FontWeight.BOLD, color="#FFD700"), + ft.Divider(height=1, color="#4A3A5A"), + content + ], spacing=5), + bgcolor="#2A1A3A", + padding=15, + border_radius=8, + border=ft.border.all(1, "#4A3A5A") + ) + + def create_detailed_conversion_table(self, number: str, base: int, decimal_value: int) -> ft.Column: + """Создаёт подробную таблицу перевода числа в десятичную систему""" + number = number.upper() + rows = [] + + # Заголовок таблицы + header = ft.Row([ + ft.Container(ft.Text("Позиция", weight=ft.FontWeight.BOLD, size=12), width=80, alignment=ft.alignment.center), + ft.Container(ft.Text("Цифра", weight=ft.FontWeight.BOLD, size=12), width=70, alignment=ft.alignment.center), + ft.Container(ft.Text("Значение", weight=ft.FontWeight.BOLD, size=12), width=80, alignment=ft.alignment.center), + ft.Container(ft.Text("Вес (база^поз)", weight=ft.FontWeight.BOLD, size=12), width=120, alignment=ft.alignment.center), + ft.Container(ft.Text("Вклад", weight=ft.FontWeight.BOLD, size=12), width=150, alignment=ft.alignment.center), + ]) + rows.append(ft.Container(content=header, bgcolor="#E3F2FD", padding=5, border_radius=5)) + + total_sum = 0 + calculation_parts = [] + + # Строки таблицы + for i, digit in enumerate(reversed(number)): + digit_value = self.digits.index(digit) + power = base ** i + contribution = digit_value * power + total_sum += contribution + + row = ft.Row([ + ft.Container(ft.Text(str(i), size=12), width=80, alignment=ft.alignment.center), + ft.Container(ft.Text(digit, size=14, weight=ft.FontWeight.BOLD, color="#1565C0"), width=70, alignment=ft.alignment.center), + ft.Container(ft.Text(str(digit_value), size=12), width=80, alignment=ft.alignment.center), + ft.Container(ft.Text(f"{base}^{i} = {power}", size=11), width=120, alignment=ft.alignment.center), + ft.Container(ft.Text(f"{digit_value} × {power} = {contribution}", size=11, color="#2E7D32"), width=150, alignment=ft.alignment.center), + ]) + rows.append(ft.Container(content=row, bgcolor="#F5F5F5" if i % 2 == 0 else "white", padding=5)) + calculation_parts.append(str(contribution)) + + # Итоговая сумма + sum_text = " + ".join(calculation_parts) + f" = {total_sum}" + rows.append(ft.Container( + content=ft.Text(f"СУММА: {sum_text}", size=13, weight=ft.FontWeight.BOLD, color="#1976D2"), + bgcolor="#E8F5E9", + padding=10, + border_radius=5 + )) + + return ft.Column(rows, spacing=2) + + def create_division_steps(self, decimal_num: int, target_base: int) -> ft.Column: + """Создаёт подробную визуализацию деления с остатком""" + if decimal_num == 0: + return ft.Column([ft.Text("0 уже в любой системе = 0", size=14, color="#757575")]) + + is_negative = decimal_num < 0 + decimal_num = abs(decimal_num) + + steps = [] + remainders = [] + step_num = 1 + + temp = decimal_num + while temp > 0: + quotient = temp // target_base + remainder = temp % target_base + remainder_char = self.digits[remainder] + remainders.insert(0, remainder_char) + + step_row = ft.Row([ + ft.Container( + ft.Text(f"Шаг {step_num}", size=11, weight=ft.FontWeight.BOLD), + width=70 + ), + ft.Container( + ft.Text(f"{temp} ÷ {target_base} = {quotient}", size=12), + width=150 + ), + ft.Container( + ft.Text(f"остаток: {remainder}", size=12, color="#FF6F00"), + width=100 + ), + ft.Container( + ft.Text(f"→ цифра '{remainder_char}'", size=12, weight=ft.FontWeight.BOLD, color="#1565C0"), + width=120 + ), + ]) + steps.append(ft.Container(content=step_row, bgcolor="#F5F5F5" if step_num % 2 == 0 else "white", padding=5)) + + temp = quotient + step_num += 1 + + # Визуализация сборки числа + result = ''.join(remainders) + assembly = ft.Column([ + ft.Divider(height=1, color="#E0E0E0"), + ft.Text("📌 Собираем остатки СНИЗУ ВВЕРХ:", size=13, weight=ft.FontWeight.BOLD, color="#1976D2"), + ft.Row([ + ft.Text("↑", size=20, color="#4CAF50"), + *[ft.Container( + ft.Text(digit, size=16, weight=ft.FontWeight.BOLD), + bgcolor="#E3F2FD", + padding=8, + border_radius=5 + ) for digit in remainders] + ], spacing=5), + ft.Container( + ft.Text(f"Результат: {('-' if is_negative else '')}{result}₍{target_base}₎", + size=15, weight=ft.FontWeight.BOLD, color="#2E7D32"), + bgcolor="#E8F5E9", + padding=10, + border_radius=5 + ) + ]) + + return ft.Column([*steps, assembly], spacing=2) + + def calculate_operation(self, num1: str, base1: int, num2: str, base2: int, + operation: Operation, result_base: int, steps_container: ft.Column): + """Выполняет операцию и показывает МАКСИМАЛЬНО ПОДРОБНОЕ пошаговое решение""" + steps_container.controls.clear() + + try: + # Проверка валидности чисел + if not self.validate_number(num1, base1): + error_msg = f"❌ ОШИБКА ВАЛИДАЦИИ\n\n" + error_msg += f"Число '{num1}' содержит недопустимые символы для {base1}-ричной системы.\n\n" + error_msg += f"В {base1}-ричной системе допустимы только символы: {self.digits[:base1]}\n" + error_msg += f"Пример корректного числа: {self.digits[base1-1]}{self.digits[base1-2]}{self.digits[0]}" + + steps_container.controls.append( + ft.Container( + content=ft.Text(error_msg, color="white", size=14), + bgcolor="#D32F2F", + padding=15, + border_radius=8 + ) + ) + steps_container.update() + return "Ошибка" + + if not self.validate_number(num2, base2): + error_msg = f"❌ ОШИБКА ВАЛИДАЦИИ\n\n" + error_msg += f"Число '{num2}' содержит недопустимые символы для {base2}-ричной системы.\n\n" + error_msg += f"В {base2}-ричной системе допустимы только символы: {self.digits[:base2]}\n" + error_msg += f"Пример корректного числа: {self.digits[base2-1]}{self.digits[base2-2]}{self.digits[0]}" + + steps_container.controls.append( + ft.Container( + content=ft.Text(error_msg, color="white", size=14), + bgcolor="#D32F2F", + padding=15, + border_radius=8 + ) + ) + steps_container.update() + return "Ошибка" + + # Конвертируем оба числа в десятичную систему + solver1 = StepByStepSolver(base=base1, digits=self.digits) + solver2 = StepByStepSolver(base=base2, digits=self.digits) + + dec1 = solver1.to_decimal(num1.upper()) + dec2 = solver2.to_decimal(num2.upper()) + + # Определяем символ операции и результат + if operation == Operation.ADDITION: + result_dec = dec1 + dec2 + op_symbol = "+" + op_name = "сложение" + elif operation == Operation.SUBTRACTION: + result_dec = dec1 - dec2 + op_symbol = "-" + op_name = "вычитание" + elif operation == Operation.MULTIPLICATION: + result_dec = dec1 * dec2 + op_symbol = "×" + op_name = "умножение" + elif operation == Operation.DIVISION: + if dec2 == 0: + steps_container.controls.append( + ft.Container( + content=ft.Text("❌ ОШИБКА: Деление на ноль невозможно!\n\nВ математике деление на ноль не определено.", + color="white", size=16), + bgcolor="#D32F2F", + padding=15, + border_radius=8 + ) + ) + steps_container.update() + return "Ошибка" + result_dec = dec1 // dec2 + remainder = dec1 % dec2 + op_symbol = "÷" + op_name = "деление" + + # Создаём пошаговое объяснение + + # ═══════════════════════════════════════════════════════════════ + # ШАГ 1: УСЛОВИЕ ЗАДАЧИ + # ═══════════════════════════════════════════════════════════════ + step1_content = ft.Column([ + ft.Text("🎯 ИСХОДНАЯ ЗАДАЧА", size=20, weight=ft.FontWeight.BOLD, color="#FFD700"), + ft.Divider(height=2, color="#FFD700"), + ft.Container( + content=ft.Text( + f"{num1}₍{base1}₎ {op_symbol} {num2}₍{base2}₎ = ?₍{result_base}₎", + size=24, + weight=ft.FontWeight.BOLD, + text_align=ft.TextAlign.CENTER + ), + bgcolor="#3A1E51", + padding=20, + border_radius=10, + alignment=ft.alignment.center + ), + ft.Text( + f"📋 ЧТО НУЖНО СДЕЛАТЬ:\n\n" + f"1️⃣ Выполнить {op_name} двух чисел:\n" + f" • Первое число: {num1} в {base1}-ричной системе\n" + f" • Второе число: {num2} в {base2}-ричной системе\n\n" + f"2️⃣ Получить результат в {result_base}-ричной системе\n\n" + f"💡 СПОСОБ РЕШЕНИЯ:\n" + f"Поскольку числа записаны в разных системах счисления,\n" + f"мы используем метод 'переводчика' - переведём всё в десятичную,\n" + f"выполним операцию и переведём результат обратно.", + size=13, + color="#E0E0E0" + ), + ], spacing=10) + steps_container.controls.append(self.create_step_card("ШАГ 1", "Условие задачи", step1_content)) + + # ═══════════════════════════════════════════════════════════════ + # ШАГ 2: ПЕРЕВОД ПЕРВОГО ЧИСЛА + # ═══════════════════════════════════════════════════════════════ + step2_content = ft.Column([ + ft.Text(f"🔄 ПЕРЕВОД ПЕРВОГО ЧИСЛА: {num1}₍{base1}₎ → десятичная", + size=18, weight=ft.FontWeight.BOLD, color="#00FFFF"), + ft.Divider(height=1, color="#E0E0E0"), + ft.Text( + f"Каждая позиция в {base1}-ричной системе имеет свой 'вес' - степень числа {base1}.\n" + f"Самая правая позиция (позиция 0) весит {base1}^0 = 1\n" + f"Следующая (позиция 1) весит {base1}^1 = {base1}\n" + f"Потом (позиция 2) весит {base1}^2 = {base1*base1}, и так далее.", + size=12, + color="#616161" + ), + ft.Container(height=10), + self.create_detailed_conversion_table(num1, base1, dec1), + ft.Container( + content=ft.Text( + f"✅ РЕЗУЛЬТАТ: {num1}₍{base1}₎ = {dec1}₍₁₀₎", + size=16, + weight=ft.FontWeight.BOLD, + color="white" + ), + bgcolor="#4CAF50", + padding=15, + border_radius=8, + alignment=ft.alignment.center + ) + ], spacing=5) + steps_container.controls.append(self.create_step_card("ШАГ 2", f"Перевод {num1}₍{base1}₎ в десятичную", step2_content)) + + # ═══════════════════════════════════════════════════════════════ + # ШАГ 3: ПЕРЕВОД ВТОРОГО ЧИСЛА + # ═══════════════════════════════════════════════════════════════ + step3_content = ft.Column([ + ft.Text(f"🔄 ПЕРЕВОД ВТОРОГО ЧИСЛА: {num2}₍{base2}₎ → десятичная", + size=18, weight=ft.FontWeight.BOLD, color="#00FFFF"), + ft.Divider(height=1, color="#E0E0E0"), + ft.Text( + f"Аналогично переводим второе число из {base2}-ричной системы.\n" + f"В {base2}-ричной системе веса позиций: 1, {base2}, {base2*base2}, {base2*base2*base2}...", + size=12, + color="#616161" + ), + ft.Container(height=10), + self.create_detailed_conversion_table(num2, base2, dec2), + ft.Container( + content=ft.Text( + f"✅ РЕЗУЛЬТАТ: {num2}₍{base2}₎ = {dec2}₍₁₀₎", + size=16, + weight=ft.FontWeight.BOLD, + color="white" + ), + bgcolor="#4CAF50", + padding=15, + border_radius=8, + alignment=ft.alignment.center + ) + ], spacing=5) + steps_container.controls.append(self.create_step_card("ШАГ 3", f"Перевод {num2}₍{base2}₎ в десятичную", step3_content)) + + # ═══════════════════════════════════════════════════════════════ + # ШАГ 4: ВЫПОЛНЕНИЕ ОПЕРАЦИИ + # ═══════════════════════════════════════════════════════════════ + if operation == Operation.DIVISION and remainder != 0: + calc_text = f"{dec1} {op_symbol} {dec2} = {result_dec} (остаток {remainder})" + explanation = ( + f"При делении {dec1} на {dec2}:\n" + f"• {dec2} помещается в {dec1} ровно {result_dec} раз\n" + f"• {dec2} × {result_dec} = {dec2 * result_dec}\n" + f"• Остаток: {dec1} - {dec2 * result_dec} = {remainder}" + ) + else: + calc_text = f"{dec1} {op_symbol} {dec2} = {result_dec}" + if operation == Operation.ADDITION: + explanation = f"Складываем два числа: {dec1} + {dec2} = {result_dec}" + elif operation == Operation.SUBTRACTION: + explanation = f"Вычитаем из {dec1} число {dec2}, получаем {result_dec}" + elif operation == Operation.MULTIPLICATION: + explanation = f"Умножаем {dec1} на {dec2}, получаем {result_dec}" + else: + explanation = f"Делим {dec1} на {dec2}, получаем {result_dec}" + + step4_content = ft.Column([ + ft.Text(f"🧮 ВЫПОЛНЕНИЕ ОПЕРАЦИИ: {op_name.upper()}", + size=18, weight=ft.FontWeight.BOLD, color="#FFD700"), + ft.Divider(height=1, color="#E0E0E0"), + ft.Text( + f"Теперь у нас есть оба числа в десятичной системе:\n" + f"• Первое число: {dec1}\n" + f"• Второе число: {dec2}\n\n" + f"Можем выполнить {op_name} обычным способом!", + size=13, + color="#616161" + ), + ft.Container( + content=ft.Text(calc_text, size=22, weight=ft.FontWeight.BOLD, color="white"), + bgcolor="#FF6F00", + padding=20, + border_radius=10, + alignment=ft.alignment.center + ), + ft.Container( + content=ft.Text(explanation, size=12, italic=True), + bgcolor="#FFF3E0", + padding=15, + border_radius=8 + ) + ], spacing=10) + steps_container.controls.append(self.create_step_card("ШАГ 4", f"{op_name.capitalize()} в десятичной системе", step4_content)) + + # ═══════════════════════════════════════════════════════════════ + # ШАГ 5: ПЕРЕВОД РЕЗУЛЬТАТА + # ═══════════════════════════════════════════════════════════════ + result_solver = StepByStepSolver(base=result_base, digits=self.digits) + result_str = result_solver.from_decimal(result_dec) + + step5_content = ft.Column([ + ft.Text(f"🔢 ПЕРЕВОД РЕЗУЛЬТАТА: {result_dec}₍₁₀₎ → {result_base}-ричная", + size=18, weight=ft.FontWeight.BOLD, color="#00FFFF"), + ft.Divider(height=1, color="#E0E0E0"), + ft.Text( + f"Последний шаг - переводим результат {result_dec} в {result_base}-ричную систему.\n" + f"Используем алгоритм деления с остатком:\n" + f"• Делим число на {result_base}\n" + f"• Остаток записываем как очередную цифру\n" + f"• Продолжаем с частным, пока оно не станет равно 0\n" + f"• Читаем остатки СНИЗУ ВВЕРХ", + size=12, + color="#616161" + ), + ft.Container(height=10), + self.create_division_steps(result_dec, result_base), + ft.Container( + content=ft.Text( + f"✅ РЕЗУЛЬТАТ: {result_dec}₍₁₀₎ = {result_str}₍{result_base}₎", + size=16, + weight=ft.FontWeight.BOLD, + color="white" + ), + bgcolor="#7B1FA2", + padding=15, + border_radius=8, + alignment=ft.alignment.center + ) + ], spacing=5) + steps_container.controls.append(self.create_step_card("ШАГ 5", f"Перевод в {result_base}-ричную систему", step5_content)) + + # ═══════════════════════════════════════════════════════════════ + # ФИНАЛЬНЫЙ ОТВЕТ + # ═══════════════════════════════════════════════════════════════ + if operation == Operation.DIVISION and remainder != 0: + remainder_str = result_solver.from_decimal(remainder) + final_answer = f"{result_str}₍{result_base}₎ (остаток {remainder_str}₍{result_base}₎)" + final_display = f"{num1}₍{base1}₎ {op_symbol} {num2}₍{base2}₎ = {result_str}₍{result_base}₎ (ост. {remainder_str}₍{result_base}₎)" + else: + final_answer = f"{result_str}₍{result_base}₎" + final_display = f"{num1}₍{base1}₎ {op_symbol} {num2}₍{base2}₎ = {result_str}₍{result_base}₎" + + final_content = ft.Column([ + ft.Text("🎉 ИТОГОВЫЙ ОТВЕТ", size=22, weight=ft.FontWeight.BOLD, color="#FFD700", text_align=ft.TextAlign.CENTER), + ft.Container( + content=ft.Text( + final_display, + size=26, + weight=ft.FontWeight.BOLD, + color="white", + text_align=ft.TextAlign.CENTER + ), + bgcolor="#4CAF50", + padding=25, + border_radius=15, + alignment=ft.alignment.center + ), + ft.Divider(height=1, color="#E0E0E0"), + ft.Text("📊 ПРОВЕРКА РЕШЕНИЯ:", size=16, weight=ft.FontWeight.BOLD, color="#E0E0E0"), + ft.Container( + content=ft.Column([ + ft.Text(f"1. Первое число: {num1}₍{base1}₎ = {dec1}₍₁₀₎ ✓", size=13), + ft.Text(f"2. Второе число: {num2}₍{base2}₎ = {dec2}₍₁₀₎ ✓", size=13), + ft.Text(f"3. Операция: {dec1} {op_symbol} {dec2} = {result_dec}₍₁₀₎ ✓", size=13), + ft.Text(f"4. Результат: {result_dec}₍₁₀₎ = {result_str}₍{result_base}₎ ✓", size=13), + ]), + bgcolor="#F5F5F5", + padding=15, + border_radius=8 + ), + ft.Container( + content=ft.Text( + "✅ Все вычисления верны!", + size=15, + weight=ft.FontWeight.BOLD, + color="#2E7D32" + ), + bgcolor="#E8F5E9", + padding=12, + border_radius=8, + alignment=ft.alignment.center + ) + ], spacing=15, horizontal_alignment=ft.CrossAxisAlignment.CENTER) + + steps_container.controls.append(self.create_step_card("✅ ОТВЕТ", "Итоговый результат", final_content)) + + steps_container.update() + return final_answer + + except Exception as e: + steps_container.controls.append( + ft.Container( + content=ft.Text(f"❌ Произошла ошибка:\n\n{str(e)}\n\nПроверьте корректность введённых данных.", + color="white", size=14), + bgcolor="#D32F2F", + padding=15, + border_radius=8 + ) + ) + steps_container.update() + return "Ошибка" + + def on_add_click(self, e): + """Обработчик для сложения""" + num1 = self.input_add_1.value or "0" + num2 = self.input_add_2.value or "0" + base1 = int(self.base_add_1.value) + base2 = int(self.base_add_2.value) + result_base = int(self.base_add_result.value) + + result = self.calculate_operation(num1, base1, num2, base2, Operation.ADDITION, result_base, self.steps_add) + self.result_add.value = result + self.result_add.update() + + def on_sub_click(self, e): + """Обработчик для вычитания""" + num1 = self.input_sub_1.value or "0" + num2 = self.input_sub_2.value or "0" + base1 = int(self.base_sub_1.value) + base2 = int(self.base_sub_2.value) + result_base = int(self.base_sub_result.value) + + result = self.calculate_operation(num1, base1, num2, base2, Operation.SUBTRACTION, result_base, self.steps_sub) + self.result_sub.value = result + self.result_sub.update() + + def on_mult_click(self, e): + """Обработчик для умножения""" + num1 = self.input_mult_1.value or "0" + num2 = self.input_mult_2.value or "0" + base1 = int(self.base_mult_1.value) + base2 = int(self.base_mult_2.value) + result_base = int(self.base_mult_result.value) + + result = self.calculate_operation(num1, base1, num2, base2, Operation.MULTIPLICATION, result_base, self.steps_mult) + self.result_mult.value = result + self.result_mult.update() + + def on_div_click(self, e): + """Обработчик для деления""" + num1 = self.input_div_1.value or "0" + num2 = self.input_div_2.value or "0" + base1 = int(self.base_div_1.value) + base2 = int(self.base_div_2.value) + result_base = int(self.base_div_result.value) + + result = self.calculate_operation(num1, base1, num2, base2, Operation.DIVISION, result_base, self.steps_div) + self.result_div.value = result + self.result_div.update() + + def create_base_selector(self, label: str, default_value: str = "10") -> ft.Dropdown: + """Создаёт выпадающий список для выбора системы счисления с подсказкой""" + bases = [str(i) for i in range(2, 37)] # От 2 до 36 + return ft.Dropdown( + label=label, + value=default_value, + options=[ft.dropdown.Option(base) for base in bases], + width=140, + text_size=14, + bgcolor="#2A2A2A", + color="white", + border_color="#4A90E2", + hint_text="Выберите основание" + ) + + def get_system_hint(self, base: int) -> str: + """Возвращает подсказку для системы счисления""" + hints = { + 2: "Двоичная (0-1)", + 8: "Восьмеричная (0-7)", + 10: "Десятичная (0-9)", + 16: "Шестнадцатеричная (0-9,A-F)", + 5: "Пятеричная (0-4)", + 18: "Восемнадцатеричная (0-9,A-H)" + } + if base in hints: + return hints[base] + elif base <= 10: + return f"{base}-ричная (0-{base-1})" + else: + return f"{base}-ричная (0-9,A-{self.digits[base-1]})" + + def create_input_with_hint(self, label: str, value: str, base_dropdown: ft.Dropdown) -> ft.Column: + """Создаёт поле ввода с динамической подсказкой""" + text_field = ft.TextField( + label=label, + value=value, + width=200, + bgcolor="#2A2A2A", + color="white", + border_color="#4A90E2", + on_change=lambda e: hint_text.update() + ) + + hint_text = ft.Text( + value=f"Допустимые символы: {self.digits[:int(base_dropdown.value)]}", + size=11, + color="#9E9E9E", + italic=True + ) + + def update_hint(e): + base = int(base_dropdown.value) + hint_text.value = f"Допустимые символы: {self.digits[:base]}" + hint_text.update() + + base_dropdown.on_change = update_hint + + return ft.Column([text_field, hint_text], spacing=2) + + def test_data(self, e): + """Создаёт интерфейс калькулятора""" + # Создаём селекторы систем счисления для всех операций + self.base_add_1 = self.create_base_selector("Система №1", "5") + self.base_add_2 = self.create_base_selector("Система №2", "18") + self.base_add_result = self.create_base_selector("Система результата", "10") + + self.base_sub_1 = self.create_base_selector("Система №1", "5") + self.base_sub_2 = self.create_base_selector("Система №2", "18") + self.base_sub_result = self.create_base_selector("Система результата", "10") + + self.base_mult_1 = self.create_base_selector("Система №1", "8") + self.base_mult_2 = self.create_base_selector("Система №2", "16") + self.base_mult_result = self.create_base_selector("Система результата", "10") + + self.base_div_1 = self.create_base_selector("Система №1", "10") + self.base_div_2 = self.create_base_selector("Система №2", "10") + self.base_div_result = self.create_base_selector("Система результата", "2") + + # Создаём поля ввода с подсказками + self.input_add_1 = ft.TextField(label="Первое число", value="235", width=200, bgcolor="#2A2A2A", color="white", border_color="#4A90E2") + self.input_add_2 = ft.TextField(label="Второе число", value="ABC", width=200, bgcolor="#2A2A2A", color="white", border_color="#4A90E2") + hint_add_1 = ft.Text("Пример: 235₍₅₎", size=11, color="#9E9E9E", italic=True) + hint_add_2 = ft.Text("Пример: ABC₍₁₈₎ (буквы A-Z)", size=11, color="#9E9E9E", italic=True) + + self.input_sub_1 = ft.TextField(label="Уменьшаемое", value="235", width=200, bgcolor="#2A2A2A", color="white", border_color="#4A90E2") + self.input_sub_2 = ft.TextField(label="Вычитаемое", value="64", width=200, bgcolor="#2A2A2A", color="white", border_color="#4A90E2") + hint_sub_1 = ft.Text("Пример: 235₍₅₎", size=11, color="#9E9E9E", italic=True) + hint_sub_2 = ft.Text("Пример: 64₍₁₈₎", size=11, color="#9E9E9E", italic=True) + + self.input_mult_1 = ft.TextField(label="Первый множитель", value="12", width=200, bgcolor="#2A2A2A", color="white", border_color="#4A90E2") + self.input_mult_2 = ft.TextField(label="Второй множитель", value="A", width=200, bgcolor="#2A2A2A", color="white", border_color="#4A90E2") + hint_mult_1 = ft.Text("Пример: 12₍₈₎", size=11, color="#9E9E9E", italic=True) + hint_mult_2 = ft.Text("Пример: A₍₁₆₎ (= 10)", size=11, color="#9E9E9E", italic=True) + + self.input_div_1 = ft.TextField(label="Делимое", value="100", width=200, bgcolor="#2A2A2A", color="white", border_color="#4A90E2") + self.input_div_2 = ft.TextField(label="Делитель", value="8", width=200, bgcolor="#2A2A2A", color="white", border_color="#4A90E2") + hint_div_1 = ft.Text("Пример: 100₍₁₀₎", size=11, color="#9E9E9E", italic=True) + hint_div_2 = ft.Text("Пример: 8₍₁₀₎", size=11, color="#9E9E9E", italic=True) + + # Информационные панели для каждой операции + info_add = ft.Container( + content=ft.Column([ + ft.Text("💡 ПОДСКАЗКА", size=14, weight=ft.FontWeight.BOLD, color="#1976D2"), + ft.Text( + "• В 5-ричной системе используются цифры: 0, 1, 2, 3, 4\n" + "• В 18-ричной системе: 0-9, A-H (где A=10, B=11, ..., H=17)\n" + "• Результат можно получить в любой системе от 2 до 36", + size=12, + color="#424242" + ) + ]), + bgcolor="#E3F2FD", + padding=12, + border_radius=8, + margin=ft.margin.only(bottom=10) + ) + + info_sub = ft.Container( + content=ft.Column([ + ft.Text("💡 ПОДСКАЗКА", size=14, weight=ft.FontWeight.BOLD, color="#F57C00"), + ft.Text( + "• Вычитание работает аналогично сложению\n" + "• Числа могут быть в разных системах счисления\n" + "• Если результат отрицательный, появится знак минус", + size=12, + color="#424242" + ) + ]), + bgcolor="#FFF3E0", + padding=12, + border_radius=8, + margin=ft.margin.only(bottom=10) + ) + + info_mult = ft.Container( + content=ft.Column([ + ft.Text("💡 ПОДСКАЗКА", size=14, weight=ft.FontWeight.BOLD, color="#1565C0"), + ft.Text( + "• В восьмеричной: 0-7\n" + "• В шестнадцатеричной: 0-9, A-F (где F=15)\n" + "• Попробуйте A₍₁₆₎ × 12₍₈₎ (это 10 × 10 в десятичной)", + size=12, + color="#424242" + ) + ]), + bgcolor="#E3F2FD", + padding=12, + border_radius=8, + margin=ft.margin.only(bottom=10) + ) + + info_div = ft.Container( + content=ft.Column([ + ft.Text("💡 ПОДСКАЗКА", size=14, weight=ft.FontWeight.BOLD, color="#7B1FA2"), + ft.Text( + "• При делении может быть остаток\n" + "• Остаток также будет переведён в выбранную систему\n" + "• Попробуйте получить результат в двоичной системе!", + size=12, + color="#424242" + ) + ]), + bgcolor="#F3E5F5", + padding=12, + border_radius=8, + margin=ft.margin.only(bottom=10) + ) + + # Вкладка сложения + addition_tab = ft.Container( + content=ft.Column([ + ft.Text("➕ Сложение в произвольных системах счисления", size=24, weight=ft.FontWeight.BOLD, color="#1976D2"), + ft.Divider(height=2, color="#1976D2"), + info_add, + ft.Row([ + ft.Column([self.base_add_1, self.input_add_1, hint_add_1], spacing=2), + ft.Container(ft.Text("+", size=36, weight=ft.FontWeight.BOLD, color="#4CAF50"), margin=ft.margin.only(top=20)), + ft.Column([self.base_add_2, self.input_add_2, hint_add_2], spacing=2), + ft.Container(ft.Text("=", size=36, weight=ft.FontWeight.BOLD), margin=ft.margin.only(top=20)), + ft.Column([self.base_add_result, ft.Container(height=40)], spacing=2) + ], alignment=ft.MainAxisAlignment.CENTER, spacing=15), + ft.Container( + ft.ElevatedButton( + "🚀 Решить с подробным объяснением", + on_click=self.on_add_click, + bgcolor="#4CAF50", + color="white", + height=45, + style=ft.ButtonStyle(shape=ft.RoundedRectangleBorder(radius=10)) + ), + alignment=ft.alignment.center, + margin=ft.margin.only(top=15, bottom=15) + ), + ft.Divider(), + ft.Container( + content=ft.Row([ + ft.Text("📊 Результат:", size=18, weight=ft.FontWeight.BOLD), + self.result_add + ]), + bgcolor="#F5F5F5", + padding=15, + border_radius=10 + ), + ft.Divider(), + self.steps_add + ], scroll=ft.ScrollMode.AUTO), + padding=20 + ) + + # Вкладка вычитания + subtraction_tab = ft.Container( + content=ft.Column([ + ft.Text("➖ Вычитание в произвольных системах счисления", size=24, weight=ft.FontWeight.BOLD, color="#F57C00"), + ft.Divider(height=2, color="#F57C00"), + info_sub, + ft.Row([ + ft.Column([self.base_sub_1, self.input_sub_1, hint_sub_1], spacing=2), + ft.Container(ft.Text("-", size=36, weight=ft.FontWeight.BOLD, color="#FF9800"), margin=ft.margin.only(top=20)), + ft.Column([self.base_sub_2, self.input_sub_2, hint_sub_2], spacing=2), + ft.Container(ft.Text("=", size=36, weight=ft.FontWeight.BOLD), margin=ft.margin.only(top=20)), + ft.Column([self.base_sub_result, ft.Container(height=40)], spacing=2) + ], alignment=ft.MainAxisAlignment.CENTER, spacing=15), + ft.Container( + ft.ElevatedButton( + "🚀 Решить с подробным объяснением", + on_click=self.on_sub_click, + bgcolor="#FF9800", + color="white", + height=45, + style=ft.ButtonStyle(shape=ft.RoundedRectangleBorder(radius=10)) + ), + alignment=ft.alignment.center, + margin=ft.margin.only(top=15, bottom=15) + ), + ft.Divider(), + ft.Container( + content=ft.Row([ + ft.Text("📊 Результат:", size=18, weight=ft.FontWeight.BOLD), + self.result_sub + ]), + bgcolor="#F5F5F5", + padding=15, + border_radius=10 + ), + ft.Divider(), + self.steps_sub + ], scroll=ft.ScrollMode.AUTO), + padding=20 + ) + + # Вкладка умножения + multiplication_tab = ft.Container( + content=ft.Column([ + ft.Text("✖️ Умножение в произвольных системах счисления", size=24, weight=ft.FontWeight.BOLD, color="#1565C0"), + ft.Divider(height=2, color="#1565C0"), + info_mult, + ft.Row([ + ft.Column([self.base_mult_1, self.input_mult_1, hint_mult_1], spacing=2), + ft.Container(ft.Text("×", size=36, weight=ft.FontWeight.BOLD, color="#2196F3"), margin=ft.margin.only(top=20)), + ft.Column([self.base_mult_2, self.input_mult_2, hint_mult_2], spacing=2), + ft.Container(ft.Text("=", size=36, weight=ft.FontWeight.BOLD), margin=ft.margin.only(top=20)), + ft.Column([self.base_mult_result, ft.Container(height=40)], spacing=2) + ], alignment=ft.MainAxisAlignment.CENTER, spacing=15), + ft.Container( + ft.ElevatedButton( + "🚀 Решить с подробным объяснением", + on_click=self.on_mult_click, + bgcolor="#2196F3", + color="white", + height=45, + style=ft.ButtonStyle(shape=ft.RoundedRectangleBorder(radius=10)) + ), + alignment=ft.alignment.center, + margin=ft.margin.only(top=15, bottom=15) + ), + ft.Divider(), + ft.Container( + content=ft.Row([ + ft.Text("📊 Результат:", size=18, weight=ft.FontWeight.BOLD), + self.result_mult + ]), + bgcolor="#F5F5F5", + padding=15, + border_radius=10 + ), + ft.Divider(), + self.steps_mult + ], scroll=ft.ScrollMode.AUTO), + padding=20 + ) + + # Вкладка деления + division_tab = ft.Container( + content=ft.Column([ + ft.Text("➗ Деление в произвольных системах счисления", size=24, weight=ft.FontWeight.BOLD, color="#7B1FA2"), + ft.Divider(height=2, color="#7B1FA2"), + info_div, + ft.Row([ + ft.Column([self.base_div_1, self.input_div_1, hint_div_1], spacing=2), + ft.Container(ft.Text("÷", size=36, weight=ft.FontWeight.BOLD, color="#9C27B0"), margin=ft.margin.only(top=20)), + ft.Column([self.base_div_2, self.input_div_2, hint_div_2], spacing=2), + ft.Container(ft.Text("=", size=36, weight=ft.FontWeight.BOLD), margin=ft.margin.only(top=20)), + ft.Column([self.base_div_result, ft.Container(height=40)], spacing=2) + ], alignment=ft.MainAxisAlignment.CENTER, spacing=15), + ft.Container( + ft.ElevatedButton( + "🚀 Решить с подробным объяснением", + on_click=self.on_div_click, + bgcolor="#9C27B0", + color="white", + height=45, + style=ft.ButtonStyle(shape=ft.RoundedRectangleBorder(radius=10)) + ), + alignment=ft.alignment.center, + margin=ft.margin.only(top=15, bottom=15) + ), + ft.Divider(), + ft.Container( + content=ft.Row([ + ft.Text("📊 Результат:", size=18, weight=ft.FontWeight.BOLD), + self.result_div + ]), + bgcolor="#F5F5F5", + padding=15, + border_radius=10 + ), + ft.Divider(), + self.steps_div + ], scroll=ft.ScrollMode.AUTO), + padding=20 + ) + + # Создаём вкладки + tabs = ft.Tabs( + selected_index=0, + animation_duration=300, + tabs=[ + ft.Tab( + text="➕ Сложение", + content=addition_tab + ), + ft.Tab( + text="➖ Вычитание", + content=subtraction_tab + ), + ft.Tab( + text="✖️ Умножение", + content=multiplication_tab + ), + ft.Tab( + text="➗ Деление", + content=division_tab + ), + ], + expand=1, + ) + + # Главный заголовок с информацией + header = ft.Container( + content=ft.Column([ + ft.Text( + "🔢 Калькулятор произвольных систем счисления", + size=28, + weight=ft.FontWeight.BOLD, + color="white", + text_align=ft.TextAlign.CENTER + ), + ft.Text( + "Выполняйте операции с числами в системах от 2 до 36 с подробными объяснениями!", + size=14, + color="white", + text_align=ft.TextAlign.CENTER, + italic=True + ) + ]), + bgcolor="#3A1E51", + padding=20, + border_radius=10 + ) + + examples = ft.Container( + content=ft.Column([ + ft.Text("📚 ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ:", size=16, weight=ft.FontWeight.BOLD, color="#FFD700"), + ft.Row([ + ft.Container( + content=ft.Column([ + ft.Text("235₍₅₎ + ABC₍₁₈₎", size=13, weight=ft.FontWeight.BOLD, color="white"), + ft.Text("= 2107₍₁₀₎", size=11, color="#90EE90") + ]), + bgcolor="#2A1A3A", + padding=10, + border_radius=5, + expand=True + ), + ft.Container( + content=ft.Column([ + ft.Text("FF₍₁₆₎ - 11₍₂₎", size=13, weight=ft.FontWeight.BOLD, color="white"), + ft.Text("= 253₍₁₀₎", size=11, color="#90EE90") + ]), + bgcolor="#2A1A3A", + padding=10, + border_radius=5, + expand=True + ), + ft.Container( + content=ft.Column([ + ft.Text("A₍₁₆₎ × 12₍₈₎", size=13, weight=ft.FontWeight.BOLD, color="white"), + ft.Text("= 100₍₁₀₎", size=11, color="#90EE90") + ]), + bgcolor="#2A1A3A", + padding=10, + border_radius=5, + expand=True + ) + ], spacing=10) + ]), + bgcolor="#1A0A2A", + padding=15, + border_radius=8, + border=ft.border.all(2, "#4A3A5A") + ) + + right_column.controls = [ + ft.Column([ + header, + ft.Container(height=10), + examples, + ft.Container(height=10), + tabs + ], expand=True, scroll=ft.ScrollMode.AUTO) + ] + e.page.update() diff --git a/app/src/step_by_step_solver.py b/app/src/step_by_step_solver.py index f012dc2..535c077 100644 --- a/app/src/step_by_step_solver.py +++ b/app/src/step_by_step_solver.py @@ -155,7 +155,8 @@ class StepByStepSolver: step1 = Step( "Исходные данные", f"Необходимо преобразовать число {number} из {self.get_system_name()} " + - f"({self.base}-ричной) системы в {target_base}-ричную систему", + f"({self.base}-ричной) системы в {target_base}-ричную систему.\n" + + f"Это как перевод с одного языка на другой - число остаётся тем же, меняется только способ записи!", f"Исходное число: {'-' if is_negative else ''}{number}₍{self.base}₎" ) steps.append(step1) @@ -164,20 +165,39 @@ class StepByStepSolver: if self.base != 10: decimal_value = 0 calculation = [] + position_table = [] + + # Создаём таблицу разрядов + digits_list = list(reversed(number)) + position_table.append("┌─" + "─┬─".join(["─"*5 for _ in digits_list]) + "─┐") + position_table.append("│ " + " │ ".join([f"Поз {i}" for i in range(len(digits_list))]) + " │") + position_table.append("├─" + "─┼─".join(["─"*5 for _ in digits_list]) + "─┤") + position_table.append("│ " + " │ ".join([f"{self.base}^{i}={self.base**i}".center(5) for i in range(len(digits_list))]) + " │") + position_table.append("├─" + "─┼─".join(["─"*5 for _ in digits_list]) + "─┤") + position_table.append("│ " + " │ ".join([f"{d}".center(5) for d in digits_list]) + " │") + position_table.append("└─" + "─┴─".join(["─"*5 for _ in digits_list]) + "─┘") for i, digit in enumerate(reversed(number)): digit_value = self.digits.index(digit) power = self.base ** i term_value = digit_value * power decimal_value += term_value - calculation.append(f"{digit}×{self.base}^{i} = {digit_value}×{power} = {term_value}") + calculation.append(f"Позиция {i}: {digit} × {self.base}^{i} = {digit_value} × {power} = {term_value}") - visual = "\n".join(calculation) - visual += f"\n\nСумма: {' + '.join([str(digit_value * (self.base ** i)) for i, digit in enumerate(reversed(number)) for digit_value in [self.digits.index(digit)]])} = {decimal_value}" + visual = "\n".join(position_table) + visual += "\n\nПОШАГОВЫЙ РАСЧЁТ:\n" + visual += "Каждая позиция (справа налево) имеет свой \"вес\" - степень основания.\n" + visual += f"В {self.base}-ричной системе веса позиций: 1, {self.base}, {self.base**2}, {self.base**3}...\n\n" + visual += "\n".join(calculation) + + sum_parts = [str(self.digits.index(digit) * (self.base ** i)) for i, digit in enumerate(reversed(number))] + visual += f"\n\nИТОГОВАЯ СУММА: {' + '.join(sum_parts)} = {decimal_value}" step2 = Step( "Перевод в десятичную систему", - f"Каждую цифру умножаем на {self.base} в степени её позиции (справа налево, начиная с 0)", + f"Представьте, что каждая позиция - это \"кармашек\" с определённой ценностью.\n" + + f"Самый правый \"стоит\" 1, следующий - {self.base}, потом {self.base**2} и так далее.\n" + + f"Мы умножаем цифру на \"цену\" её позиции и складываем всё вместе.", visual, f"{decimal_value}₍₁₀₎" ) @@ -190,23 +210,35 @@ class StepByStepSolver: divisions = [] temp = decimal_value result_digits = [] + step_num = 1 + + visual = f"МЕТОД: Делим число на {target_base} до тех пор, пока не получим 0.\n" + visual += "Каждый остаток от деления - это одна цифра результата.\n" + visual += "Важно! Первый остаток будет ПОСЛЕДНЕЙ цифрой ответа.\n\n" while temp > 0: remainder = temp % target_base quotient = temp // target_base result_digits.insert(0, self.digits[remainder]) - divisions.append(f"{temp} ÷ {target_base} = {quotient}, остаток: {remainder} ({self.digits[remainder]})") + divisions.append(f"Шаг {step_num}: {temp} ÷ {target_base} = {quotient}, остаток: {remainder} → цифра '{self.digits[remainder]}'") + step_num += 1 temp = quotient result_number = ''.join(result_digits) if result_digits else "0" - visual = "\n".join(divisions) - visual += f"\n\nЧитаем остатки снизу вверх: {result_number}" + visual += "\n".join(divisions) + visual += "\n\n" + "="*50 + visual += f"\nСобираем остатки СНИЗУ ВВЕРХ (от последнего к первому):\n" + visual += "═"*50 + "\n" + for i, digit in enumerate(result_digits): + visual += f" ↑ {digit} " + visual += f"\n\nОтвет: {result_number}" step3 = Step( f"Перевод в {target_base}-ричную систему", - f"Делим число на {target_base} и записываем остатки. " + - "Читаем остатки снизу вверх", + f"Алгоритм деления с остатком - классический способ перевода.\n" + + f"Представьте, что вы раскладываете конфеты по коробкам: в каждой {target_base} штук.\n" + + f"Остатки показывают, сколько конфет не поместилось в полные коробки на каждом этапе.", visual, f"{'-' if is_negative else ''}{result_number}₍{target_base}₎" ) @@ -240,10 +272,12 @@ class StepByStepSolver: """ steps = [] - # Шаг 1: Исходные данные + # Шаг 1: Условие задачи step1 = Step( "Условие задачи", - f"Необходимо сложить два числа в {self.get_system_name()} ({self.base}-ричной) системе счисления", + f"Необходимо сложить два числа в {self.get_system_name()} ({self.base}-ричной) системе счисления.\n" + + f"Принцип такой же, как в десятичной системе, но \"переполнение\" происходит при {self.base}, а не при 10!\n" + + f"Пример: если в десятичной 9+1=10 (переносим 1), то в двоичной 1+1=10₍₂₎ (тоже переносим 1).", f"{num1}₍{self.base}₎ + {num2}₍{self.base}₎ = ?", "" ) @@ -310,8 +344,11 @@ class StepByStepSolver: step3 = Step( "Сложение в столбик", - f"Складываем числа справа налево, учитывая переносы. " + - f"При сумме ≥ {self.base} делим на {self.base}: остаток - результат, частное - перенос", + f"Складываем числа справа налево, учитывая переносы.\n" + + f"ПРАВИЛО: Если сумма ≥ {self.base}, то делим на {self.base}:\n" + + f" • Остаток от деления → записываем в результат\n" + + f" • Частное → переносим в следующий разряд\n" + + f"Например: если {self.base-1} + 1 = {self.base}, пишем 0 и переносим 1 (как 9+1=10 в десятичной).", visual, f"{result_str}₍{self.base}₎" ) @@ -348,10 +385,13 @@ class StepByStepSolver: """ steps = [] - # Шаг 1: Исходные данные + # Шаг 1: Условие задачи step1 = Step( "Условие задачи", - f"Необходимо вычесть два числа в {self.get_system_name()} ({self.base}-ричной) системе счисления", + f"Необходимо вычесть два числа в {self.get_system_name()} ({self.base}-ричной) системе счисления.\n" + + f"Вычитание работает как в десятичной, но занимаем не 10, а {self.base}.\n" + + f"Например: в десятичной при 3-5 занимаем 10, получается 13-5=8.\n" + + f"В {self.base}-ричной системе занимаем {self.base} из следующего разряда.", f"{num1}₍{self.base}₎ - {num2}₍{self.base}₎ = ?", "" ) @@ -434,8 +474,12 @@ class StepByStepSolver: step3 = Step( "Вычитание в столбик", - f"Вычитаем числа справа налево. " + - f"Если цифра уменьшаемого меньше вычитаемого, занимаем {self.base} из следующего разряда", + f"Вычитаем числа справа налево.\n" + + f"ПРАВИЛО ЗАИМСТВОВАНИЯ:\n" + + f" • Если верхняя цифра < нижней, занимаем {self.base} из следующего разряда\n" + + f" • К верхней цифре прибавляем {self.base}, вычитаем нижнюю\n" + + f" • Из следующего разряда вычитаем 1 (это \"долг\")\n" + + f"Это как занять 10₽ у друга, чтобы хватило на покупку!", visual, f"{result_str}₍{self.base}₎" ) @@ -473,7 +517,13 @@ class StepByStepSolver: # Шаг 1: Исходные данные step1 = Step( "Условие задачи", - f"Необходимо умножить два числа в {self.get_system_name()} ({self.base}-ричной) системе счисления", + f"Необходимо умножить два числа в {self.get_system_name()} ({self.base}-ричной) системе счисления.\n" + + f"\nСПОСОБ РЕШЕНИЯ:\n" + + f"Умножение напрямую в {self.base}-ричной системе сложное, поэтому используем \"переводчика\":\n" + + f" 1. Переводим оба числа в привычную десятичную систему\n" + + f" 2. Умножаем в десятичной системе (это мы умеем!)\n" + + f" 3. Переводим результат обратно в {self.base}-ричную систему\n" + + f"Это как перевести иностранный текст на русский, решить задачу и перевести ответ обратно.", f"{num1}₍{self.base}₎ × {num2}₍{self.base}₎ = ?", "" ) @@ -491,37 +541,50 @@ class StepByStepSolver: result_str = self.from_decimal(result_dec) step2 = Step( - "Преобразование в десятичную систему", - "Переводим оба числа в десятичную систему для проверки", + "Шаг 1: Преобразование в десятичную систему", + f"Переводим множители из {self.base}-ричной в десятичную систему.\n" + + f"Используем метод разложения по разрядам (см. примеры выше).", f"{num1}₍{self.base}₎ = {dec1}₍₁₀₎\n" + - f"{num2}₍{self.base}₎ = {dec2}₍₁₀₎", - "" + f"{num2}₍{self.base}₎ = {dec2}₍₁₀₎\n\n" + + f"Теперь работаем с привычными десятичными числами!", + f"Множители: {dec1} и {dec2}" ) steps.append(step2) # Шаг 3: Умножение в десятичной системе step3 = Step( - "Умножение в десятичной системе", - "Перемножаем числа в десятичной системе", - f"{dec1} × {dec2} = {result_dec}", + "Шаг 2: Умножение в десятичной системе", + f"Перемножаем числа обычным способом (как учили в школе).\n" + + f"Это самая простая часть - обычное умножение!", + f"{dec1} × {dec2} = {result_dec}\n\n" + + f"Получили результат в десятичной системе: {result_dec}", f"{result_dec}₍₁₀₎" ) steps.append(step3) # Шаг 4: Обратное преобразование step4 = Step( - f"Перевод результата в {self.base}-ричную систему", - f"Переводим результат обратно в {self.base}-ричную систему", - f"{result_dec}₍₁₀₎ = {result_str}₍{self.base}₎", + f"Шаг 3: Перевод результата в {self.base}-ричную систему", + f"Переводим полученный результат обратно в {self.base}-ричную систему.\n" + + f"Используем метод деления с остатком (см. примеры выше).", + f"{result_dec}₍₁₀₎ = {result_str}₍{self.base}₎\n\n" + + f"Вернули ответ в исходную систему счисления!", f"{result_str}₍{self.base}₎" ) steps.append(step4) # Шаг 5: Проверка step5 = Step( - "Итоговый результат", - f"Результат умножения {num1}₍{self.base}₎ × {num2}₍{self.base}₎", - f"{num1}₍{self.base}₎ × {num2}₍{self.base}₎ = {result_str}₍{self.base}₎\nПроверка: {dec1} × {dec2} = {result_dec}", + "Итоговый результат и проверка", + f"Проверяем логику решения:\n" + + f" • Исходная задача: {num1}₍{self.base}₎ × {num2}₍{self.base}₎\n" + + f" • Перевели в десятичную: {dec1} × {dec2}\n" + + f" • Получили результат: {result_dec}\n" + + f" • Вернули в {self.base}-ричную: {result_str}₍{self.base}₎", + f"┌─────────────────────────────────┐\n" + + f"│ {num1}₍{self.base}₎ × {num2}₍{self.base}₎ = {result_str}₍{self.base}₎ │\n" + + f"└─────────────────────────────────┘\n" + + f"Проверка: {dec1} × {dec2} = {result_dec}₍₁₀₎ = {result_str}₍{self.base}₎", f"✓ Ответ: {result_str}₍{self.base}₎" ) steps.append(step5) @@ -544,7 +607,13 @@ class StepByStepSolver: # Шаг 1: Исходные данные step1 = Step( "Условие задачи", - f"Необходимо разделить два числа в {self.get_system_name()} ({self.base}-ричной) системе счисления", + f"Необходимо разделить два числа в {self.get_system_name()} ({self.base}-ричной) системе счисления.\n" + + f"\nСПОСОБ РЕШЕНИЯ:\n" + + f"Деление в {self.base}-ричной системе очень трудоёмкое, поэтому используем метод \"переводчика\":\n" + + f" 1. Переводим делимое и делитель в десятичную систему\n" + + f" 2. Делим в десятичной системе (получаем частное и остаток)\n" + + f" 3. Переводим частное и остаток обратно в {self.base}-ричную систему\n" + + f"Проще решить на \"родном языке\" математики - в десятичной системе!", f"{num1}₍{self.base}₎ ÷ {num2}₍{self.base}₎ = ?", "" ) @@ -569,11 +638,13 @@ class StepByStepSolver: # Шаг 2: Преобразование в десятичную систему step2 = Step( - "Преобразование в десятичную систему", - "Переводим оба числа в десятичную систему", - f"{num1}₍{self.base}₎ = {dec1}₍₁₀₎\n" + - f"{num2}₍{self.base}₎ = {dec2}₍₁₀₎", - "" + "Шаг 1: Преобразование в десятичную систему", + f"Переводим делимое и делитель из {self.base}-ричной в десятичную систему.\n" + + f"Используем знакомый метод разложения по разрядам.", + f"Делимое: {num1}₍{self.base}₎ = {dec1}₍₁₀₎\n" + + f"Делитель: {num2}₍{self.base}₎ = {dec2}₍₁₀₎\n\n" + + f"Теперь задача выглядит просто: {dec1} ÷ {dec2}", + f"Числа в десятичной: {dec1} ÷ {dec2}" ) steps.append(step2) @@ -582,9 +653,14 @@ class StepByStepSolver: remainder = dec1 % dec2 step3 = Step( - "Деление в десятичной системе", - "Выполняем целочисленное деление в десятичной системе", - f"{dec1} ÷ {dec2} = {quotient} (остаток {remainder})", + "Шаг 2: Деление в десятичной системе", + f"Выполняем целочисленное деление (деление нацело).\n" + + f"\nЧТО ПОЛУЧАЕМ:\n" + + f" • Частное (сколько раз {dec2} помещается в {dec1})\n" + + f" • Остаток (что осталось после деления)\n" + + f"\nПример: 17 ÷ 5 = 3 (остаток 2), потому что 5×3=15, а 17-15=2", + f"{dec1} ÷ {dec2} = {quotient} (остаток {remainder})\n\n" + + f"Проверка: {dec2} × {quotient} + {remainder} = {dec2 * quotient} + {remainder} = {dec1} ✓", f"Частное: {quotient}₍₁₀₎, Остаток: {remainder}₍₁₀₎" ) steps.append(step3) @@ -594,10 +670,12 @@ class StepByStepSolver: remainder_str = self.from_decimal(remainder) if remainder != 0 else "0" step4 = Step( - f"Перевод результата в {self.base}-ричную систему", - f"Переводим частное и остаток обратно в {self.base}-ричную систему", - f"Частное: {quotient}₍₁₀₎ = {quotient_str}₍{self.base}₎\n" + - f"Остаток: {remainder}₍₁₀₎ = {remainder_str}₍{self.base}₎", + f"Шаг 3: Перевод результата в {self.base}-ричную систему", + f"Переводим частное и остаток обратно в {self.base}-ричную систему.\n" + + f"Используем метод деления с остатком для перевода.", + f"Частное: {quotient}₍₁₀₎ → {quotient_str}₍{self.base}₎\n" + + f"Остаток: {remainder}₍₁₀₎ → {remainder_str}₍{self.base}₎\n\n" + + f"Вернули ответ в исходную систему счисления!", f"{quotient_str}₍{self.base}₎ (остаток {remainder_str}₍{self.base}₎)" ) steps.append(step4) @@ -605,11 +683,18 @@ class StepByStepSolver: # Шаг 5: Проверка check_result = dec2 * quotient + remainder step5 = Step( - "Проверка результата", - "Проверяем: делитель × частное + остаток = делимое", - f"{dec2} × {quotient} + {remainder} = {check_result}\n" + - f"{num2}₍{self.base}₎ × {quotient_str}₍{self.base}₎ + {remainder_str}₍{self.base}₎ = {num1}₍{self.base}₎", - f"✓ Ответ: {quotient_str}₍{self.base}₎ (остаток {remainder_str}₍{self.base}₎)" if remainder != 0 else f"✓ Ответ: {quotient_str}₍{self.base}₎" + "Итоговый результат и проверка", + f"Проверяем правильность по формуле:\n" + + f" Делимое = Делитель × Частное + Остаток\n" + + f"Это основное правило деления с остатком!", + f"┌──────────────────────────────────────┐\n" + + f"│ {num1}₍{self.base}₎ ÷ {num2}₍{self.base}₎ = {quotient_str}₍{self.base}₎" + + (f" (ост. {remainder_str}₍{self.base}₎)" if remainder != 0 else "") + " │\n" + + f"└──────────────────────────────────────┘\n\n" + + f"Проверка в десятичной: {dec2} × {quotient} + {remainder} = {check_result} ✓\n" + + f"Проверка в {self.base}-ричной: {num2}₍{self.base}₎ × {quotient_str}₍{self.base}₎" + + (f" + {remainder_str}₍{self.base}₎" if remainder != 0 else "") + f" = {num1}₍{self.base}₎ ✓", + f"✓ Ответ: {quotient_str}₍{self.base}₎" + (f" (остаток {remainder_str}₍{self.base}₎)" if remainder != 0 else "") ) steps.append(step5)