From 86a9d2bad98e9eb28ce1aa0155ea8ff2a1c99e5a Mon Sep 17 00:00:00 2001 From: jze9 Date: Mon, 15 Dec 2025 09:08:49 +0500 Subject: [PATCH] fanaly --- app/src/pages/main_page.py | 7 +- app/src/pages/tabs/arbitrary_calculator11.py | 76 +- app/src/pages/tabs/roman_calculator12.py | 754 +++++++++++++++++++ app/src/pages/tabs/roman_converter13.py | 358 +++++++++ app/src/step_by_step_solver.py | 6 +- 5 files changed, 1159 insertions(+), 42 deletions(-) create mode 100644 app/src/pages/tabs/roman_calculator12.py create mode 100644 app/src/pages/tabs/roman_converter13.py diff --git a/app/src/pages/main_page.py b/app/src/pages/main_page.py index f139ee3..7b4bdc3 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, arbitrary_calculator11 +from pages.tabs import roman_converter13, roman_calculator12, 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): @@ -15,6 +15,7 @@ class Main_page(ft.View): horizontal_alignment=ft.CrossAxisAlignment.START, width=300, alignment=ft.MainAxisAlignment.START, + scroll="auto", controls=[ start1.Button_text_data(), calculater2.Button_calculeator(), @@ -27,8 +28,10 @@ class Main_page(ft.View): pentecostal_system9.Button_binary_data(), pentecostal_calculeator10.Button_quinquagesimal_calculator(), arbitrary_calculator11.Button_arbitrary_calculator(), + roman_calculator12.Button_roman_calculator(), + roman_converter13.RomanConverter(), ft.Container( - bgcolor="#280A3F", + bgcolor="#221929", expand=True, ) ] diff --git a/app/src/pages/tabs/arbitrary_calculator11.py b/app/src/pages/tabs/arbitrary_calculator11.py index 85e7c0d..1734ba6 100644 --- a/app/src/pages/tabs/arbitrary_calculator11.py +++ b/app/src/pages/tabs/arbitrary_calculator11.py @@ -47,11 +47,12 @@ class Button_arbitrary_calculator(ft.CupertinoButton): 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" + # Стандартный набор цифр для систем до 50 + # 0-9 (10 цифр) + A-Z (26 букв) + a-n (14 букв) = 50 символов + self.digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn" super().__init__( - bgcolor="#00000000", + bgcolor="#211D1D00", disabled_bgcolor="#3A1E51", text=text, color="white", @@ -112,7 +113,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton): 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)) + rows.append(ft.Container(content=header, bgcolor="#71838C", padding=5, border_radius=5)) total_sum = 0 calculation_parts = [] @@ -125,20 +126,20 @@ class Button_arbitrary_calculator(ft.CupertinoButton): total_sum += contribution row = ft.Row([ - ft.Container(ft.Text(str(i), size=12), width=80, alignment=ft.alignment.center), + ft.Container(ft.Text(str(i),color="#FF0000", 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(str(digit_value),color="#FF0000", size=12), width=80, alignment=ft.alignment.center), + ft.Container(ft.Text(f"{base}^{i} = {power}",color="#FF0000", 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)) + rows.append(ft.Container(content=row, bgcolor="#2E2727" 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", + bgcolor="#2B2F2B", padding=10, border_radius=5 )) @@ -148,7 +149,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton): 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")]) + return ft.Column([ft.Text("0 уже в любой системе = 0", size=14, color="#1A1717")]) is_negative = decimal_num < 0 decimal_num = abs(decimal_num) @@ -166,11 +167,11 @@ class Button_arbitrary_calculator(ft.CupertinoButton): step_row = ft.Row([ ft.Container( - ft.Text(f"Шаг {step_num}", size=11, weight=ft.FontWeight.BOLD), + ft.Text(f"Шаг {step_num}", size=11,color="#FF6F00", weight=ft.FontWeight.BOLD), width=70 ), ft.Container( - ft.Text(f"{temp} ÷ {target_base} = {quotient}", size=12), + ft.Text(f"{temp} ÷ {target_base} = {quotient}",color="#FF6F00", size=12), width=150 ), ft.Container( @@ -182,7 +183,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton): width=120 ), ]) - steps.append(ft.Container(content=step_row, bgcolor="#F5F5F5" if step_num % 2 == 0 else "white", padding=5)) + steps.append(ft.Container(content=step_row, bgcolor="#2E2B2B" if step_num % 2 == 0 else "white", padding=5)) temp = quotient step_num += 1 @@ -190,13 +191,13 @@ class Button_arbitrary_calculator(ft.CupertinoButton): # Визуализация сборки числа result = ''.join(remainders) assembly = ft.Column([ - ft.Divider(height=1, color="#E0E0E0"), + ft.Divider(height=1, color="#0B0909"), 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", + bgcolor="#94BBCF", padding=8, border_radius=5 ) for digit in remainders] @@ -204,7 +205,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton): ft.Container( ft.Text(f"Результат: {('-' if is_negative else '')}{result}₍{target_base}₎", size=15, weight=ft.FontWeight.BOLD, color="#2E7D32"), - bgcolor="#E8F5E9", + bgcolor="#0F110F", padding=10, border_radius=5 ) @@ -322,7 +323,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton): f"мы используем метод 'переводчика' - переведём всё в десятичную,\n" f"выполним операцию и переведём результат обратно.", size=13, - color="#E0E0E0" + color="#B27171" ), ], spacing=10) steps_container.controls.append(self.create_step_card("ШАГ 1", "Условие задачи", step1_content)) @@ -333,14 +334,14 @@ class Button_arbitrary_calculator(ft.CupertinoButton): step2_content = ft.Column([ ft.Text(f"🔄 ПЕРЕВОД ПЕРВОГО ЧИСЛА: {num1}₍{base1}₎ → десятичная", size=18, weight=ft.FontWeight.BOLD, color="#00FFFF"), - ft.Divider(height=1, color="#E0E0E0"), + ft.Divider(height=1, color="#000000"), 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" + color="#9E7979" ), ft.Container(height=10), self.create_detailed_conversion_table(num1, base1, dec1), @@ -365,12 +366,12 @@ class Button_arbitrary_calculator(ft.CupertinoButton): step3_content = ft.Column([ ft.Text(f"🔄 ПЕРЕВОД ВТОРОГО ЧИСЛА: {num2}₍{base2}₎ → десятичная", size=18, weight=ft.FontWeight.BOLD, color="#00FFFF"), - ft.Divider(height=1, color="#E0E0E0"), + ft.Divider(height=1, color="#000000"), ft.Text( f"Аналогично переводим второе число из {base2}-ричной системы.\n" f"В {base2}-ричной системе веса позиций: 1, {base2}, {base2*base2}, {base2*base2*base2}...", size=12, - color="#616161" + color="#CB8686" ), ft.Container(height=10), self.create_detailed_conversion_table(num2, base2, dec2), @@ -414,14 +415,14 @@ class Button_arbitrary_calculator(ft.CupertinoButton): 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.Divider(height=1, color="#1D1919"), ft.Text( f"Теперь у нас есть оба числа в десятичной системе:\n" f"• Первое число: {dec1}\n" f"• Второе число: {dec2}\n\n" f"Можем выполнить {op_name} обычным способом!", size=13, - color="#616161" + color="#C9A5A5" ), ft.Container( content=ft.Text(calc_text, size=22, weight=ft.FontWeight.BOLD, color="white"), @@ -432,7 +433,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton): ), ft.Container( content=ft.Text(explanation, size=12, italic=True), - bgcolor="#FFF3E0", + bgcolor="#282724", padding=15, border_radius=8 ) @@ -448,7 +449,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton): 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.Divider(height=1, color="#7A5555"), ft.Text( f"Последний шаг - переводим результат {result_dec} в {result_base}-ричную систему.\n" f"Используем алгоритм деления с остатком:\n" @@ -457,7 +458,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton): f"• Продолжаем с частным, пока оно не станет равно 0\n" f"• Читаем остатки СНИЗУ ВВЕРХ", size=12, - color="#616161" + color="#FAE1E1" ), ft.Container(height=10), self.create_division_steps(result_dec, result_base), @@ -502,7 +503,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton): border_radius=15, alignment=ft.alignment.center ), - ft.Divider(height=1, color="#E0E0E0"), + ft.Divider(height=1, color="#231D1D"), ft.Text("📊 ПРОВЕРКА РЕШЕНИЯ:", size=16, weight=ft.FontWeight.BOLD, color="#E0E0E0"), ft.Container( content=ft.Column([ @@ -511,7 +512,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton): 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", + bgcolor="#1F1919", padding=15, border_radius=8 ), @@ -597,7 +598,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton): def create_base_selector(self, label: str, default_value: str = "10") -> ft.Dropdown: """Создаёт выпадающий список для выбора системы счисления с подсказкой""" - bases = [str(i) for i in range(2, 37)] # От 2 до 36 + bases = [str(i) for i in range(2, 51)] # От 2 до 50 return ft.Dropdown( label=label, value=default_value, @@ -702,9 +703,10 @@ class Button_arbitrary_calculator(ft.CupertinoButton): ft.Text( "• В 5-ричной системе используются цифры: 0, 1, 2, 3, 4\n" "• В 18-ричной системе: 0-9, A-H (где A=10, B=11, ..., H=17)\n" - "• Результат можно получить в любой системе от 2 до 36", + "• В 50-ричной: 0-9, A-Z, a-n (всего 50 символов!)\n" + "• Результат можно получить в любой системе от 2 до 50", size=12, - color="#424242" + color="#281B1B" ) ]), bgcolor="#E3F2FD", @@ -721,7 +723,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton): "• Числа могут быть в разных системах счисления\n" "• Если результат отрицательный, появится знак минус", size=12, - color="#424242" + color="#1F1C1C" ) ]), bgcolor="#FFF3E0", @@ -738,7 +740,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton): "• В шестнадцатеричной: 0-9, A-F (где F=15)\n" "• Попробуйте A₍₁₆₎ × 12₍₈₎ (это 10 × 10 в десятичной)", size=12, - color="#424242" + color="#292424" ) ]), bgcolor="#E3F2FD", @@ -792,7 +794,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton): ft.Divider(), ft.Container( content=ft.Row([ - ft.Text("📊 Результат:", size=18, weight=ft.FontWeight.BOLD), + ft.Text("📊 Результат:",color="#3C2525", size=18, weight=ft.FontWeight.BOLD), self.result_add ]), bgcolor="#F5F5F5", @@ -833,7 +835,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton): ft.Divider(), ft.Container( content=ft.Row([ - ft.Text("📊 Результат:", size=18, weight=ft.FontWeight.BOLD), + ft.Text("📊 Результат:",color="#452020", size=18, weight=ft.FontWeight.BOLD), self.result_sub ]), bgcolor="#F5F5F5", @@ -874,7 +876,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton): ft.Divider(), ft.Container( content=ft.Row([ - ft.Text("📊 Результат:", size=18, weight=ft.FontWeight.BOLD), + ft.Text("📊 Результат:",color="#422525", size=18, weight=ft.FontWeight.BOLD), self.result_mult ]), bgcolor="#F5F5F5", @@ -964,7 +966,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton): text_align=ft.TextAlign.CENTER ), ft.Text( - "Выполняйте операции с числами в системах от 2 до 36 с подробными объяснениями!", + "Выполняйте операции с числами в системах от 2 до 50 с подробными объяснениями!", size=14, color="white", text_align=ft.TextAlign.CENTER, diff --git a/app/src/pages/tabs/roman_calculator12.py b/app/src/pages/tabs/roman_calculator12.py new file mode 100644 index 0000000..3e931fe --- /dev/null +++ b/app/src/pages/tabs/roman_calculator12.py @@ -0,0 +1,754 @@ +from designer import right_column, StepByStepDisplay +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_roman_calculator(ft.CupertinoButton): + def __init__(self, text: str = "Римский калькулятор"): + self.result_left = ft.Text(value="", size=30, width=300) + self.result_right = ft.Text(value="", size=30, width=300) + self.result_mult = ft.Text(value="", size=30, width=300) + self.result_div = ft.Text(value="", size=30, width=300) + + self.decimal_left = ft.Text(value="", size=14, color="#B0B0B0", width=300) + self.decimal_right = ft.Text(value="", size=14, color="#B0B0B0", width=300) + self.decimal_mult = ft.Text(value="", size=14, color="#B0B0B0", width=300) + self.decimal_div = ft.Text(value="", size=14, color="#B0B0B0", width=300) + + # Поля ввода для вычитания + self.input_left_1 = None + self.input_left_2 = None + + # Поля ввода для сложения + self.input_right_1 = None + self.input_right_2 = None + + # Поля ввода для умножения + self.input_mult_1 = None + self.input_mult_2 = None + + # Поля ввода для деления + self.input_div_1 = None + self.input_div_2 = None + + # Контейнеры для пошагового решения + self.steps_left = ft.Column(scroll=ft.ScrollMode.AUTO, spacing=5) + self.steps_right = 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) + + # Римские числа от 1 до 3999 + self.roman_map = [ + (1000, 'M'), (900, 'CM'), (500, 'D'), (400, 'CD'), + (100, 'C'), (90, 'XC'), (50, 'L'), (40, 'XL'), + (10, 'X'), (9, 'IX'), (5, 'V'), (4, 'IV'), (1, 'I') + ] + + super().__init__( + bgcolor="#00000000", + disabled_bgcolor="#3A1E51", + text=text, + color="white", + on_click=self.test_data + ) + + def validate_roman(self, value: str) -> bool: + """Проверяет, является ли строка корректным римским числом.""" + if value is None: + return True + v = value.strip().upper() + if v == "": + return True + # Проверяем, что строка содержит только римские цифры + return all(c in 'IVXLCDM' for c in v) + + def roman_to_int(self, roman: str) -> int: + """Преобразует римское число в десятичное.""" + roman = roman.strip().upper() + if not roman: + return 0 + + roman_values = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000} + result = 0 + prev_value = 0 + + for char in reversed(roman): + if char not in roman_values: + raise ValueError(f"Неверный символ '{char}' в римском числе") + value = roman_values[char] + if value < prev_value: + result -= value + else: + result += value + prev_value = value + + return result + + def int_to_roman(self, num: int) -> str: + """Преобразует десятичное число в римское.""" + if num <= 0: + return "Нет" # Римские числа не поддерживают 0 и отрицательные числа + if num >= 4000: + return "Превышает 3999" + + result = [] + for value, numeral in self.roman_map: + count = num // value + if count: + result.append(numeral * count) + num -= value * count + return ''.join(result) + + def get_steps_text(self, roman: str) -> str: + """Создает текстовое описание разбора римского числа.""" + roman = roman.strip().upper() + if not roman: + return "" + + roman_values = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000} + steps = [] + result = 0 + prev_value = 0 + + for i, char in enumerate(reversed(roman)): + value = roman_values[char] + if value < prev_value: + steps.append(f"{char} = {value} (вычитаем, т.к. меньше следующего)") + result -= value + else: + steps.append(f"{char} = {value} (добавляем)") + result += value + prev_value = value + + return "\n".join(reversed(steps)) + f"\n\nИтого: {result}" + + def calculate_subtraction(self, e): + try: + val1 = (self.input_left_1.value or "").strip().upper() + val2 = (self.input_left_2.value or "").strip().upper() + + # Проверка корректности римских чисел + if not self.validate_roman(val1) or not self.validate_roman(val2): + self.result_left.value = "Ошибка: неверный формат" + self.decimal_left.value = "" + self.result_left.update() + self.decimal_left.update() + return + + # Преобразуем в десятичные числа + num1 = self.roman_to_int(val1) if val1 else 0 + num2 = self.roman_to_int(val2) if val2 else 0 + + # Вычисляем результат + result = num1 - num2 + + # Преобразуем обратно в римское число + roman_result = self.int_to_roman(result) + + self.result_left.value = roman_result + self.decimal_left.value = f"({result}₁₀)" if result > 0 else f"({result}₁₀, не представимо)" + self.result_left.update() + self.decimal_left.update() + + # Показываем пошаговое решение + self.show_steps_left_custom(val1, val2, num1, num2, result, "Вычитание") + + except ValueError as ex: + self.result_left.value = "Ошибка" + self.decimal_left.value = str(ex) + self.result_left.update() + self.decimal_left.update() + + def calculate_addition(self, e): + try: + val1 = (self.input_right_1.value or "").strip().upper() + val2 = (self.input_right_2.value or "").strip().upper() + + # Проверка корректности римских чисел + if not self.validate_roman(val1) or not self.validate_roman(val2): + self.result_right.value = "Ошибка: неверный формат" + self.decimal_right.value = "" + self.result_right.update() + self.decimal_right.update() + return + + num1 = self.roman_to_int(val1) if val1 else 0 + num2 = self.roman_to_int(val2) if val2 else 0 + + # Вычисляем результат + result = num1 + num2 + + # Преобразуем обратно в римское число + roman_result = self.int_to_roman(result) + + self.result_right.value = roman_result + self.decimal_right.value = f"({result}₁₀)" if result <= 3999 else f"({result}₁₀, превышает 3999)" + self.result_right.update() + self.decimal_right.update() + + # Показываем пошаговое решение + self.show_steps_right_custom(val1, val2, num1, num2, result, "Сложение") + + except ValueError as ex: + self.result_right.value = "Ошибка" + self.decimal_right.value = str(ex) + self.result_right.update() + self.decimal_right.update() + + def calculate_multiplication(self, e): + try: + val1 = (self.input_mult_1.value or "").strip().upper() + val2 = (self.input_mult_2.value or "").strip().upper() + + if not self.validate_roman(val1) or not self.validate_roman(val2): + self.result_mult.value = "Ошибка: неверный формат" + self.decimal_mult.value = "" + self.result_mult.update() + self.decimal_mult.update() + return + + num1 = self.roman_to_int(val1) if val1 else 0 + num2 = self.roman_to_int(val2) if val2 else 0 + result = num1 * num2 + + roman_result = self.int_to_roman(result) + + self.result_mult.value = roman_result + self.decimal_mult.value = f"({result}₁₀)" if result <= 3999 else f"({result}₁₀, превышает 3999)" + self.result_mult.update() + self.decimal_mult.update() + + self.show_steps_mult_custom(val1, val2, num1, num2, result, "Умножение") + + except ValueError as ex: + self.result_mult.value = "Ошибка" + self.decimal_mult.value = str(ex) + self.result_mult.update() + self.decimal_mult.update() + + def calculate_division(self, e): + try: + val1 = (self.input_div_1.value or "").strip().upper() + val2 = (self.input_div_2.value or "").strip().upper() + + if not self.validate_roman(val1) or not self.validate_roman(val2): + self.result_div.value = "Ошибка: неверный формат" + self.decimal_div.value = "" + self.result_div.update() + self.decimal_div.update() + return + + num1 = self.roman_to_int(val1) if val1 else 0 + num2 = self.roman_to_int(val2) if val2 else 0 + + if num2 == 0: + self.result_div.value = "Деление на 0!" + self.decimal_div.value = "" + self.result_div.update() + self.decimal_div.update() + return + + quotient = num1 // num2 + remainder = num1 % num2 + + roman_quotient = self.int_to_roman(quotient) + + if remainder == 0: + self.result_div.value = roman_quotient + self.decimal_div.value = f"({quotient}₁₀)" + else: + roman_remainder = self.int_to_roman(remainder) if remainder <= 3999 else str(remainder) + self.result_div.value = roman_quotient + self.decimal_div.value = f"({quotient}₁₀, ост. {remainder}₁₀ = {roman_remainder})" + + self.result_div.update() + self.decimal_div.update() + + self.show_steps_div_custom(val1, val2, num1, num2, quotient, remainder, "Деление") + + except ValueError as ex: + self.result_div.value = "Ошибка" + self.decimal_div.value = str(ex) + self.result_div.update() + self.decimal_div.update() + + def show_steps_left_custom(self, val1: str, val2: str, num1: int, num2: int, result: int, operation: str): + """Отображает пошаговое решение для вычитания""" + self.steps_left.controls.clear() + + self.steps_left.controls.append( + ft.Text("📝 Ход решения:", size=14, weight=ft.FontWeight.BOLD, color="#FFD700") + ) + + # Шаг 1: Преобразование первого числа + step1_content = [] + step1_content.append(ft.Text(f"Шаг 1: Преобразование {val1} в десятичное", size=12, weight=ft.FontWeight.BOLD, color="#00FFFF")) + step1_content.append(ft.Text(self.get_steps_text(val1), size=10, font_family="Courier New", color="#90EE90")) + self.steps_left.controls.append( + ft.Container( + content=ft.Column(step1_content, spacing=3), + bgcolor="#2A1A3A", + padding=8, + border_radius=5, + border=ft.border.all(1, "#4A3A5A") + ) + ) + + # Шаг 2: Преобразование второго числа + step2_content = [] + step2_content.append(ft.Text(f"Шаг 2: Преобразование {val2} в десятичное", size=12, weight=ft.FontWeight.BOLD, color="#00FFFF")) + step2_content.append(ft.Text(self.get_steps_text(val2), size=10, font_family="Courier New", color="#90EE90")) + self.steps_left.controls.append( + ft.Container( + content=ft.Column(step2_content, spacing=3), + bgcolor="#2A1A3A", + padding=8, + border_radius=5, + border=ft.border.all(1, "#4A3A5A") + ) + ) + + # Шаг 3: Вычитание в десятичной системе + step3_content = [] + step3_content.append(ft.Text(f"Шаг 3: {operation} в десятичной системе", size=12, weight=ft.FontWeight.BOLD, color="#00FFFF")) + step3_content.append(ft.Text(f"{num1} - {num2} = {result}", size=10, color="#E0E0E0")) + self.steps_left.controls.append( + ft.Container( + content=ft.Column(step3_content, spacing=3), + bgcolor="#2A1A3A", + padding=8, + border_radius=5, + border=ft.border.all(1, "#4A3A5A") + ) + ) + + # Шаг 4: Преобразование результата обратно в римское + step4_content = [] + step4_content.append(ft.Text(f"Шаг 4: Преобразование {result} в римское число", size=12, weight=ft.FontWeight.BOLD, color="#00FFFF")) + roman_result = self.int_to_roman(result) + step4_content.append(ft.Text(f"Результат: {roman_result}", size=11, weight=ft.FontWeight.BOLD, color="#00FF00")) + self.steps_left.controls.append( + ft.Container( + content=ft.Column(step4_content, spacing=3), + bgcolor="#2A1A3A", + padding=8, + border_radius=5, + border=ft.border.all(1, "#4A3A5A") + ) + ) + + self.steps_left.update() + + def show_steps_right_custom(self, val1: str, val2: str, num1: int, num2: int, result: int, operation: str): + """Отображает пошаговое решение для сложения""" + self.steps_right.controls.clear() + + self.steps_right.controls.append( + ft.Text("📝 Ход решения:", size=14, weight=ft.FontWeight.BOLD, color="#FFD700") + ) + + # Шаг 1: Преобразование первого числа + step1_content = [] + step1_content.append(ft.Text(f"Шаг 1: Преобразование {val1} в десятичное", size=12, weight=ft.FontWeight.BOLD, color="#00FFFF")) + step1_content.append(ft.Text(self.get_steps_text(val1), size=10, font_family="Courier New", color="#90EE90")) + self.steps_right.controls.append( + ft.Container( + content=ft.Column(step1_content, spacing=3), + bgcolor="#2A1A3A", + padding=8, + border_radius=5, + border=ft.border.all(1, "#4A3A5A") + ) + ) + + # Шаг 2: Преобразование второго числа + step2_content = [] + step2_content.append(ft.Text(f"Шаг 2: Преобразование {val2} в десятичное", size=12, weight=ft.FontWeight.BOLD, color="#00FFFF")) + step2_content.append(ft.Text(self.get_steps_text(val2), size=10, font_family="Courier New", color="#90EE90")) + self.steps_right.controls.append( + ft.Container( + content=ft.Column(step2_content, spacing=3), + bgcolor="#2A1A3A", + padding=8, + border_radius=5, + border=ft.border.all(1, "#4A3A5A") + ) + ) + + # Шаг 3: Сложение в десятичной системе + step3_content = [] + step3_content.append(ft.Text(f"Шаг 3: {operation} в десятичной системе", size=12, weight=ft.FontWeight.BOLD, color="#00FFFF")) + step3_content.append(ft.Text(f"{num1} + {num2} = {result}", size=10, color="#E0E0E0")) + self.steps_right.controls.append( + ft.Container( + content=ft.Column(step3_content, spacing=3), + bgcolor="#2A1A3A", + padding=8, + border_radius=5, + border=ft.border.all(1, "#4A3A5A") + ) + ) + + # Шаг 4: Преобразование результата обратно в римское + step4_content = [] + step4_content.append(ft.Text(f"Шаг 4: Преобразование {result} в римское число", size=12, weight=ft.FontWeight.BOLD, color="#00FFFF")) + roman_result = self.int_to_roman(result) + step4_content.append(ft.Text(f"Результат: {roman_result}", size=11, weight=ft.FontWeight.BOLD, color="#00FF00")) + self.steps_right.controls.append( + ft.Container( + content=ft.Column(step4_content, spacing=3), + bgcolor="#2A1A3A", + padding=8, + border_radius=5, + border=ft.border.all(1, "#4A3A5A") + ) + ) + + self.steps_right.update() + + def show_steps_mult_custom(self, val1: str, val2: str, num1: int, num2: int, result: int, operation: str): + """Отображает пошаговое решение для умножения""" + self.steps_mult.controls.clear() + + self.steps_mult.controls.append( + ft.Text("📝 Ход решения:", size=14, weight=ft.FontWeight.BOLD, color="#FFD700") + ) + + # Шаг 1: Преобразование первого числа + step1_content = [] + step1_content.append(ft.Text(f"Шаг 1: Преобразование {val1} в десятичное", size=12, weight=ft.FontWeight.BOLD, color="#00FFFF")) + step1_content.append(ft.Text(self.get_steps_text(val1), size=10, font_family="Courier New", color="#90EE90")) + self.steps_mult.controls.append( + ft.Container( + content=ft.Column(step1_content, spacing=3), + bgcolor="#2A1A3A", + padding=8, + border_radius=5, + border=ft.border.all(1, "#4A3A5A") + ) + ) + + # Шаг 2: Преобразование второго числа + step2_content = [] + step2_content.append(ft.Text(f"Шаг 2: Преобразование {val2} в десятичное", size=12, weight=ft.FontWeight.BOLD, color="#00FFFF")) + step2_content.append(ft.Text(self.get_steps_text(val2), size=10, font_family="Courier New", color="#90EE90")) + self.steps_mult.controls.append( + ft.Container( + content=ft.Column(step2_content, spacing=3), + bgcolor="#2A1A3A", + padding=8, + border_radius=5, + border=ft.border.all(1, "#4A3A5A") + ) + ) + + # Шаг 3: Умножение в десятичной системе + step3_content = [] + step3_content.append(ft.Text(f"Шаг 3: {operation} в десятичной системе", size=12, weight=ft.FontWeight.BOLD, color="#00FFFF")) + step3_content.append(ft.Text(f"{num1} × {num2} = {result}", size=10, color="#E0E0E0")) + self.steps_mult.controls.append( + ft.Container( + content=ft.Column(step3_content, spacing=3), + bgcolor="#2A1A3A", + padding=8, + border_radius=5, + border=ft.border.all(1, "#4A3A5A") + ) + ) + + # Шаг 4: Преобразование результата обратно в римское + step4_content = [] + step4_content.append(ft.Text(f"Шаг 4: Преобразование {result} в римское число", size=12, weight=ft.FontWeight.BOLD, color="#00FFFF")) + roman_result = self.int_to_roman(result) + step4_content.append(ft.Text(f"Результат: {roman_result}", size=11, weight=ft.FontWeight.BOLD, color="#00FF00")) + self.steps_mult.controls.append( + ft.Container( + content=ft.Column(step4_content, spacing=3), + bgcolor="#2A1A3A", + padding=8, + border_radius=5, + border=ft.border.all(1, "#4A3A5A") + ) + ) + + self.steps_mult.update() + + def show_steps_div_custom(self, val1: str, val2: str, num1: int, num2: int, quotient: int, remainder: int, operation: str): + """Отображает пошаговое решение для деления""" + self.steps_div.controls.clear() + + self.steps_div.controls.append( + ft.Text("📝 Ход решения:", size=14, weight=ft.FontWeight.BOLD, color="#FFD700") + ) + + # Шаг 1: Преобразование первого числа + step1_content = [] + step1_content.append(ft.Text(f"Шаг 1: Преобразование {val1} в десятичное", size=12, weight=ft.FontWeight.BOLD, color="#00FFFF")) + step1_content.append(ft.Text(self.get_steps_text(val1), size=10, font_family="Courier New", color="#90EE90")) + self.steps_div.controls.append( + ft.Container( + content=ft.Column(step1_content, spacing=3), + bgcolor="#2A1A3A", + padding=8, + border_radius=5, + border=ft.border.all(1, "#4A3A5A") + ) + ) + + # Шаг 2: Преобразование второго числа + step2_content = [] + step2_content.append(ft.Text(f"Шаг 2: Преобразование {val2} в десятичное", size=12, weight=ft.FontWeight.BOLD, color="#00FFFF")) + step2_content.append(ft.Text(self.get_steps_text(val2), size=10, font_family="Courier New", color="#90EE90")) + self.steps_div.controls.append( + ft.Container( + content=ft.Column(step2_content, spacing=3), + bgcolor="#2A1A3A", + padding=8, + border_radius=5, + border=ft.border.all(1, "#4A3A5A") + ) + ) + + # Шаг 3: Деление в десятичной системе + step3_content = [] + step3_content.append(ft.Text(f"Шаг 3: {operation} в десятичной системе", size=12, weight=ft.FontWeight.BOLD, color="#00FFFF")) + if remainder == 0: + step3_content.append(ft.Text(f"{num1} ÷ {num2} = {quotient}", size=10, color="#E0E0E0")) + else: + step3_content.append(ft.Text(f"{num1} ÷ {num2} = {quotient} (остаток {remainder})", size=10, color="#E0E0E0")) + self.steps_div.controls.append( + ft.Container( + content=ft.Column(step3_content, spacing=3), + bgcolor="#2A1A3A", + padding=8, + border_radius=5, + border=ft.border.all(1, "#4A3A5A") + ) + ) + + # Шаг 4: Преобразование результата обратно в римское + step4_content = [] + step4_content.append(ft.Text(f"Шаг 4: Преобразование {quotient} в римское число", size=12, weight=ft.FontWeight.BOLD, color="#00FFFF")) + roman_quotient = self.int_to_roman(quotient) + if remainder == 0: + step4_content.append(ft.Text(f"Результат: {roman_quotient}", size=11, weight=ft.FontWeight.BOLD, color="#00FF00")) + else: + roman_remainder = self.int_to_roman(remainder) if remainder <= 3999 else str(remainder) + step4_content.append(ft.Text(f"Результат: {roman_quotient} (остаток {remainder}₁₀ = {roman_remainder})", size=11, weight=ft.FontWeight.BOLD, color="#00FF00")) + self.steps_div.controls.append( + ft.Container( + content=ft.Column(step4_content, spacing=3), + bgcolor="#2A1A3A", + padding=8, + border_radius=5, + border=ft.border.all(1, "#4A3A5A") + ) + ) + + self.steps_div.update() + + def test_data(self, e): + # Создаем поля ввода с валидацией для римских чисел + self.input_left_1 = ft.TextField( + label="Римское число 1", + width=250, + text_align=ft.TextAlign.RIGHT, + value="", + input_filter=ft.InputFilter(regex_string=r"^[IVXLCDMivxlcdm]*$"), + hint_text="Например: X (10) или MCMXC (1990)" + ) + self.input_left_2 = ft.TextField( + label="Римское число 2", + width=250, + text_align=ft.TextAlign.RIGHT, + value="", + input_filter=ft.InputFilter(regex_string=r"^[IVXLCDMivxlcdm]*$"), + hint_text="Например: V (5)" + ) + + self.input_right_1 = ft.TextField( + label="Римское число 1", + width=250, + text_align=ft.TextAlign.RIGHT, + value="", + input_filter=ft.InputFilter(regex_string=r"^[IVXLCDMivxlcdm]*$"), + hint_text="Например: XII (12)" + ) + self.input_right_2 = ft.TextField( + label="Римское число 2", + width=250, + text_align=ft.TextAlign.RIGHT, + value="", + input_filter=ft.InputFilter(regex_string=r"^[IVXLCDMivxlcdm]*$"), + hint_text="Например: VIII (8)" + ) + + self.input_mult_1 = ft.TextField( + label="Римское число 1", + width=250, + text_align=ft.TextAlign.RIGHT, + value="", + input_filter=ft.InputFilter(regex_string=r"^[IVXLCDMivxlcdm]*$"), + hint_text="Например: X (10)" + ) + self.input_mult_2 = ft.TextField( + label="Римское число 2", + width=250, + text_align=ft.TextAlign.RIGHT, + value="", + input_filter=ft.InputFilter(regex_string=r"^[IVXLCDMivxlcdm]*$"), + hint_text="Например: III (3)" + ) + + self.input_div_1 = ft.TextField( + label="Римское число 1", + width=250, + text_align=ft.TextAlign.RIGHT, + value="", + input_filter=ft.InputFilter(regex_string=r"^[IVXLCDMivxlcdm]*$"), + hint_text="Например: C (100)" + ) + self.input_div_2 = ft.TextField( + label="Римское число 2", + width=250, + text_align=ft.TextAlign.RIGHT, + value="", + input_filter=ft.InputFilter(regex_string=r"^[IVXLCDMivxlcdm]*$"), + hint_text="Например: X (10)" + ) + + right_column.controls = [ft.Container( + bgcolor="#55257D", + padding=ft.padding.all(10), + border_radius=10, + expand=True, + content=ft.Column( + scroll=ft.ScrollMode.AUTO, + expand=True, + controls=[ + ft.Text("Римский калькулятор", size=20, color="white", weight=ft.FontWeight.BOLD), + ft.Text("Вводите числа римскими цифрами (I, V, X, L, C, D, M). Диапазон: 1-3999.", size=11, color="#B0B0B0", italic=True), + ft.Text(f"Пример: XII = 12₁₀, MCMXC = 1990₁₀. Регистр не важен.", size=11, color="#B0B0B0"), + ft.Row( + expand=True, + alignment=ft.MainAxisAlignment.CENTER, + vertical_alignment=ft.CrossAxisAlignment.START, + controls=[ + ft.Column( + expand=True, + alignment=ft.MainAxisAlignment.START, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + self.input_left_1, + ft.Text("——— Вычитание", size=12, color="white"), + self.input_left_2, + ft.Container( + content=ft.Column([ + self.result_left, + self.decimal_left + ], horizontal_alignment=ft.CrossAxisAlignment.CENTER), + bgcolor="#3A1E51", + padding=10, + border_radius=5, + ), + ft.CupertinoButton("=", on_click=self.calculate_subtraction), + ft.Container( + expand=True, + content=self.steps_left, + bgcolor="#1A0A2A", + padding=10, + border_radius=5, + ) + ] + ), + ft.Column( + expand=True, + alignment=ft.MainAxisAlignment.START, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + self.input_right_1, + ft.Text("—|— Сложение", size=12, color="white"), + self.input_right_2, + ft.Container( + content=ft.Column([ + self.result_right, + self.decimal_right + ], horizontal_alignment=ft.CrossAxisAlignment.CENTER), + bgcolor="#3A1E51", + padding=10, + border_radius=5, + ), + ft.CupertinoButton("=", on_click=self.calculate_addition), + ft.Container( + expand=True, + content=self.steps_right, + bgcolor="#1A0A2A", + padding=10, + border_radius=5, + ) + ] + ), + ft.Column( + expand=True, + alignment=ft.MainAxisAlignment.START, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + self.input_mult_1, + ft.Text("× Умножение", size=12, color="white"), + self.input_mult_2, + ft.Container( + content=ft.Column([ + self.result_mult, + self.decimal_mult + ], horizontal_alignment=ft.CrossAxisAlignment.CENTER), + bgcolor="#3A1E51", + padding=10, + border_radius=5, + ), + ft.CupertinoButton("=", on_click=self.calculate_multiplication), + ft.Container( + expand=True, + content=self.steps_mult, + bgcolor="#1A0A2A", + padding=10, + border_radius=5, + ) + ] + ), + ft.Column( + expand=True, + alignment=ft.MainAxisAlignment.START, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + self.input_div_1, + ft.Text("÷ Деление", size=12, color="white"), + self.input_div_2, + ft.Container( + content=ft.Column([ + self.result_div, + self.decimal_div + ], horizontal_alignment=ft.CrossAxisAlignment.CENTER), + bgcolor="#3A1E51", + padding=10, + border_radius=5, + ), + ft.CupertinoButton("=", on_click=self.calculate_division), + ft.Container( + expand=True, + content=self.steps_div, + bgcolor="#1A0A2A", + padding=10, + border_radius=5, + ) + ] + ) + ] + ) + ], + ) + )] + e.page.update() diff --git a/app/src/pages/tabs/roman_converter13.py b/app/src/pages/tabs/roman_converter13.py new file mode 100644 index 0000000..287892d --- /dev/null +++ b/app/src/pages/tabs/roman_converter13.py @@ -0,0 +1,358 @@ +from designer import right_column, StepByStepDisplay +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__)))) + +class RomanConverter(ft.CupertinoButton): + def __init__(self, text: str = "Римские числа - конвертер"): + self.result_to_roman = ft.Text(value="I", size=30, width=300) + self.result_from_roman = ft.Text(value="1", size=30, width=300) + + # Поля ввода + self.input_decimal = None + self.input_roman = None + + # Контейнеры для пошагового решения + self.steps_to_roman = ft.Column(scroll=ft.ScrollMode.AUTO, spacing=5, expand=True) + self.steps_from_roman = ft.Column(scroll=ft.ScrollMode.AUTO, spacing=5, expand=True) + + super().__init__( + bgcolor="#00000000", + disabled_bgcolor="#3A1E51", + text=text, + color="white", + on_click=self.test_data + ) + + def decimal_to_roman(self, num): + """Преобразует десятичное число в римское (1-3999)""" + if num <= 0 or num > 3999: + return None + + val = [ + 1000, 900, 500, 400, + 100, 90, 50, 40, + 10, 9, 5, 4, + 1 + ] + syms = [ + "M", "CM", "D", "CD", + "C", "XC", "L", "XL", + "X", "IX", "V", "IV", + "I" + ] + roman_num = '' + i = 0 + while num > 0: + for _ in range(num // val[i]): + roman_num += syms[i] + num -= val[i] + i += 1 + return roman_num + + def decimal_to_roman_with_steps(self, num): + """Преобразует десятичное число в римское с пошаговым объяснением""" + if num <= 0 or num > 3999: + return None, [] + + val = [ + 1000, 900, 500, 400, + 100, 90, 50, 40, + 10, 9, 5, 4, + 1 + ] + syms = [ + "M", "CM", "D", "CD", + "C", "XC", "L", "XL", + "X", "IX", "V", "IV", + "I" + ] + + steps = [] + roman_num = '' + remaining = num + i = 0 + + steps.append(f"Начальное число: {num}") + steps.append("") + + while remaining > 0: + count = remaining // val[i] + if count > 0: + added = syms[i] * count + roman_num += added + steps.append(f"{remaining} ÷ {val[i]} = {count}") + steps.append(f"Добавляем: {added} (римское обозначение {val[i]})") + remaining -= val[i] * count + steps.append(f"Результат: {roman_num}") + steps.append(f"Осталось: {remaining}") + steps.append("") + i += 1 + + steps.append(f"Итоговое римское число: {roman_num}") + return roman_num, steps + + def roman_to_decimal(self, s): + """Преобразует римское число в десятичное""" + roman = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000} + total = 0 + prev_value = 0 + + for char in reversed(s.upper()): + if char not in roman: + return None + value = roman[char] + if value < prev_value: + total -= value + else: + total += value + prev_value = value + + return total + + def roman_to_decimal_with_steps(self, s): + """Преобразует римское число в десятичное с пошаговым объяснением""" + roman = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000} + s = s.upper() + + # Проверка валидности + for char in s: + if char not in roman: + return None, [f"Ошибка: '{char}' не является римской цифрой"] + + steps = [] + total = 0 + prev_value = 0 + + steps.append(f"Римское число: {s}") + steps.append("Читаем справа налево:") + steps.append("") + + operations = [] + for char in reversed(s): + value = roman[char] + if value < prev_value: + operations.append(f"- {char} ({value})") + total -= value + else: + operations.append(f"+ {char} ({value})") + total += value + prev_value = value + + # Показываем в обратном порядке (как читается) + for op in reversed(operations): + steps.append(op) + + steps.append("") + steps.append(f"Итоговое десятичное число: {total}") + return total, steps + + def convert_to_roman(self, e): + """Конвертирует из десятичной в римскую""" + try: + num = int(self.input_decimal.value or 0) + + if num <= 0 or num > 3999: + self.result_to_roman.value = "Ошибка: 1-3999" + self.result_to_roman.update() + self.steps_to_roman.controls.clear() + self.steps_to_roman.controls.append( + ft.Text("Римские числа поддерживают только диапазон от 1 до 3999", + size=14, color="#FF6B6B") + ) + self.steps_to_roman.update() + return + + roman, steps = self.decimal_to_roman_with_steps(num) + self.result_to_roman.value = roman + self.result_to_roman.update() + + # Показываем шаги + self.steps_to_roman.controls.clear() + for step in steps: + if step: + self.steps_to_roman.controls.append( + ft.Text(step, size=14, color="white") + ) + else: + self.steps_to_roman.controls.append(ft.Divider(color="#3A1E51")) + self.steps_to_roman.update() + + except ValueError: + self.result_to_roman.value = "Ошибка" + self.result_to_roman.update() + + def convert_from_roman(self, e): + """Конвертирует из римской в десятичную""" + try: + roman_num = (self.input_roman.value or "I").strip().upper() + + if not roman_num: + roman_num = "I" + + result, steps = self.roman_to_decimal_with_steps(roman_num) + + if result is None: + self.result_from_roman.value = "Ошибка" + self.result_from_roman.update() + self.steps_from_roman.controls.clear() + for step in steps: + self.steps_from_roman.controls.append( + ft.Text(step, size=14, color="#FF6B6B") + ) + self.steps_from_roman.update() + return + + self.result_from_roman.value = str(result) + self.result_from_roman.update() + + # Показываем шаги + self.steps_from_roman.controls.clear() + for step in steps: + if step: + self.steps_from_roman.controls.append( + ft.Text(step, size=14, color="white") + ) + else: + self.steps_from_roman.controls.append(ft.Divider(color="#3A1E51")) + self.steps_from_roman.update() + + except Exception as ex: + self.result_from_roman.value = "Ошибка" + self.result_from_roman.update() + + def test_data(self, e): + # Создаем поля ввода + self.input_decimal = ft.TextField( + label="Десятичное число", + width=300, + text_align=ft.TextAlign.RIGHT, + value="1", + input_filter=ft.InputFilter(regex_string=r"^[0-9]*$"), + keyboard_type=ft.KeyboardType.NUMBER, + hint_text="Например: 1984" + ) + + self.input_roman = ft.TextField( + label="Римское число", + width=300, + text_align=ft.TextAlign.CENTER, + value="I", + hint_text="Например: MCMLXXXIV", + input_filter=ft.InputFilter(regex_string=r"^[IVXLCDMivxlcdm]*$") + ) + + right_column.controls = [ft.Container( + bgcolor="#55257D", + padding=ft.padding.all(10), + border_radius=10, + expand=True, + content=ft.Column( + scroll=ft.ScrollMode.AUTO, + expand=True, + controls=[ + ft.Text("Конвертер римских чисел", size=20, color="white", weight=ft.FontWeight.BOLD), + ft.Text("Поддерживаются числа от 1 до 3999", size=11, color="#B0B0B0", italic=True), + ft.Container(height=10), + ft.Row( + expand=True, + alignment=ft.MainAxisAlignment.CENTER, + vertical_alignment=ft.CrossAxisAlignment.START, + spacing=20, + controls=[ + # Конвертация из десятичной в римскую + ft.Column( + expand=True, + alignment=ft.MainAxisAlignment.START, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text("Десятичная → Римская", size=16, color="white", weight=ft.FontWeight.BOLD), + ft.Container(height=10), + self.input_decimal, + ft.Container(height=10), + ft.Icon(ft.Icons.ARROW_DOWNWARD, color="white", size=30), + ft.Container(height=10), + ft.Container( + content=ft.Column([ + self.result_to_roman, + ], horizontal_alignment=ft.CrossAxisAlignment.CENTER), + bgcolor="#3A1E51", + padding=10, + border_radius=5, + width=300, + ), + ft.Container(height=10), + ft.CupertinoButton("Конвертировать", on_click=self.convert_to_roman), + ft.Container(height=10), + ft.Text("Пошаговое объяснение:", size=14, color="#B0B0B0"), + ft.Container( + expand=True, + content=self.steps_to_roman, + bgcolor="#1A0A2A", + padding=10, + border_radius=5, + ) + ] + ), + + # Разделитель + ft.VerticalDivider(width=1, color="#3A1E51"), + + # Конвертация из римской в десятичную + ft.Column( + expand=True, + alignment=ft.MainAxisAlignment.START, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text("Римская → Десятичная", size=16, color="white", weight=ft.FontWeight.BOLD), + ft.Container(height=10), + self.input_roman, + ft.Container(height=10), + ft.Icon(ft.Icons.ARROW_DOWNWARD, color="white", size=30), + ft.Container(height=10), + ft.Container( + content=ft.Column([ + self.result_from_roman, + ], horizontal_alignment=ft.CrossAxisAlignment.CENTER), + bgcolor="#3A1E51", + padding=10, + border_radius=5, + width=300, + ), + ft.Container(height=10), + ft.CupertinoButton("Конвертировать", on_click=self.convert_from_roman), + ft.Container(height=10), + ft.Text("Пошаговое объяснение:", size=14, color="#B0B0B0"), + ft.Container( + expand=True, + content=self.steps_from_roman, + bgcolor="#1A0A2A", + padding=10, + border_radius=5, + ) + ] + ) + ] + ), + ft.Container(height=20), + ft.Text("Справка по римским цифрам:", size=14, color="#B0B0B0", weight=ft.FontWeight.BOLD), + ft.Container( + content=ft.Column([ + ft.Text("I = 1, V = 5, X = 10, L = 50, C = 100, D = 500, M = 1000", + size=12, color="white"), + ft.Text("Правило вычитания: если меньшая цифра стоит перед большей, она вычитается", + size=12, color="white"), + ft.Text("Примеры: IV = 4, IX = 9, XL = 40, XC = 90, CD = 400, CM = 900", + size=12, color="white"), + ]), + bgcolor="#3A1E51", + padding=10, + border_radius=5, + ) + ], + ) + )] + e.page.update() diff --git a/app/src/step_by_step_solver.py b/app/src/step_by_step_solver.py index 535c077..08f1a0c 100644 --- a/app/src/step_by_step_solver.py +++ b/app/src/step_by_step_solver.py @@ -330,12 +330,12 @@ class StepByStepSolver: else: explanation += f" = {digit_result}" - detailed_calc.insert(0, explanation) + detailed_calc.append(explanation) carry = new_carry if carry > 0: result.insert(0, self.digits[carry]) - detailed_calc.insert(0, f"Финальный перенос: {carry}") + detailed_calc.append(f"Финальный перенос: {carry}") result_str = ''.join(result) @@ -460,7 +460,7 @@ class StepByStepSolver: digit_result = d1 - d2 result.insert(0, self.digits[digit_result]) - detailed_calc.insert(0, explanation) + detailed_calc.append(explanation) # Убираем ведущие нули result_str = ''.join(result).lstrip('0') or '0'