fanaly
This commit is contained in:
@@ -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,
|
||||
)
|
||||
]
|
||||
|
||||
@@ -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,
|
||||
|
||||
754
app/src/pages/tabs/roman_calculator12.py
Normal file
754
app/src/pages/tabs/roman_calculator12.py
Normal file
@@ -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()
|
||||
358
app/src/pages/tabs/roman_converter13.py
Normal file
358
app/src/pages/tabs/roman_converter13.py
Normal file
@@ -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()
|
||||
@@ -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'
|
||||
|
||||
Reference in New Issue
Block a user