fanaly
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import flet as ft
|
import flet as ft
|
||||||
import designer as ds
|
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):
|
class Main_page(ft.View):
|
||||||
def __init__(self, page):
|
def __init__(self, page):
|
||||||
@@ -15,6 +15,7 @@ class Main_page(ft.View):
|
|||||||
horizontal_alignment=ft.CrossAxisAlignment.START,
|
horizontal_alignment=ft.CrossAxisAlignment.START,
|
||||||
width=300,
|
width=300,
|
||||||
alignment=ft.MainAxisAlignment.START,
|
alignment=ft.MainAxisAlignment.START,
|
||||||
|
scroll="auto",
|
||||||
controls=[
|
controls=[
|
||||||
start1.Button_text_data(),
|
start1.Button_text_data(),
|
||||||
calculater2.Button_calculeator(),
|
calculater2.Button_calculeator(),
|
||||||
@@ -27,8 +28,10 @@ class Main_page(ft.View):
|
|||||||
pentecostal_system9.Button_binary_data(),
|
pentecostal_system9.Button_binary_data(),
|
||||||
pentecostal_calculeator10.Button_quinquagesimal_calculator(),
|
pentecostal_calculeator10.Button_quinquagesimal_calculator(),
|
||||||
arbitrary_calculator11.Button_arbitrary_calculator(),
|
arbitrary_calculator11.Button_arbitrary_calculator(),
|
||||||
|
roman_calculator12.Button_roman_calculator(),
|
||||||
|
roman_converter13.RomanConverter(),
|
||||||
ft.Container(
|
ft.Container(
|
||||||
bgcolor="#280A3F",
|
bgcolor="#221929",
|
||||||
expand=True,
|
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_mult = ft.Column(scroll=ft.ScrollMode.AUTO, spacing=5)
|
||||||
self.steps_div = ft.Column(scroll=ft.ScrollMode.AUTO, spacing=5)
|
self.steps_div = ft.Column(scroll=ft.ScrollMode.AUTO, spacing=5)
|
||||||
|
|
||||||
# Стандартный набор цифр для систем до 36
|
# Стандартный набор цифр для систем до 50
|
||||||
self.digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
# 0-9 (10 цифр) + A-Z (26 букв) + a-n (14 букв) = 50 символов
|
||||||
|
self.digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn"
|
||||||
|
|
||||||
super().__init__(
|
super().__init__(
|
||||||
bgcolor="#00000000",
|
bgcolor="#211D1D00",
|
||||||
disabled_bgcolor="#3A1E51",
|
disabled_bgcolor="#3A1E51",
|
||||||
text=text,
|
text=text,
|
||||||
color="white",
|
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=120, alignment=ft.alignment.center),
|
||||||
ft.Container(ft.Text("Вклад", weight=ft.FontWeight.BOLD, size=12), width=150, 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
|
total_sum = 0
|
||||||
calculation_parts = []
|
calculation_parts = []
|
||||||
@@ -125,20 +126,20 @@ class Button_arbitrary_calculator(ft.CupertinoButton):
|
|||||||
total_sum += contribution
|
total_sum += contribution
|
||||||
|
|
||||||
row = ft.Row([
|
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(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(str(digit_value),color="#FF0000", size=12), width=80, alignment=ft.alignment.center),
|
||||||
ft.Container(ft.Text(f"{base}^{i} = {power}", size=11), width=120, alignment=ft.alignment.center),
|
ft.Container(ft.Text(f"{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),
|
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))
|
calculation_parts.append(str(contribution))
|
||||||
|
|
||||||
# Итоговая сумма
|
# Итоговая сумма
|
||||||
sum_text = " + ".join(calculation_parts) + f" = {total_sum}"
|
sum_text = " + ".join(calculation_parts) + f" = {total_sum}"
|
||||||
rows.append(ft.Container(
|
rows.append(ft.Container(
|
||||||
content=ft.Text(f"СУММА: {sum_text}", size=13, weight=ft.FontWeight.BOLD, color="#1976D2"),
|
content=ft.Text(f"СУММА: {sum_text}", size=13, weight=ft.FontWeight.BOLD, color="#1976D2"),
|
||||||
bgcolor="#E8F5E9",
|
bgcolor="#2B2F2B",
|
||||||
padding=10,
|
padding=10,
|
||||||
border_radius=5
|
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:
|
def create_division_steps(self, decimal_num: int, target_base: int) -> ft.Column:
|
||||||
"""Создаёт подробную визуализацию деления с остатком"""
|
"""Создаёт подробную визуализацию деления с остатком"""
|
||||||
if decimal_num == 0:
|
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
|
is_negative = decimal_num < 0
|
||||||
decimal_num = abs(decimal_num)
|
decimal_num = abs(decimal_num)
|
||||||
@@ -166,11 +167,11 @@ class Button_arbitrary_calculator(ft.CupertinoButton):
|
|||||||
|
|
||||||
step_row = ft.Row([
|
step_row = ft.Row([
|
||||||
ft.Container(
|
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
|
width=70
|
||||||
),
|
),
|
||||||
ft.Container(
|
ft.Container(
|
||||||
ft.Text(f"{temp} ÷ {target_base} = {quotient}", size=12),
|
ft.Text(f"{temp} ÷ {target_base} = {quotient}",color="#FF6F00", size=12),
|
||||||
width=150
|
width=150
|
||||||
),
|
),
|
||||||
ft.Container(
|
ft.Container(
|
||||||
@@ -182,7 +183,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton):
|
|||||||
width=120
|
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
|
temp = quotient
|
||||||
step_num += 1
|
step_num += 1
|
||||||
@@ -190,13 +191,13 @@ class Button_arbitrary_calculator(ft.CupertinoButton):
|
|||||||
# Визуализация сборки числа
|
# Визуализация сборки числа
|
||||||
result = ''.join(remainders)
|
result = ''.join(remainders)
|
||||||
assembly = ft.Column([
|
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.Text("📌 Собираем остатки СНИЗУ ВВЕРХ:", size=13, weight=ft.FontWeight.BOLD, color="#1976D2"),
|
||||||
ft.Row([
|
ft.Row([
|
||||||
ft.Text("↑", size=20, color="#4CAF50"),
|
ft.Text("↑", size=20, color="#4CAF50"),
|
||||||
*[ft.Container(
|
*[ft.Container(
|
||||||
ft.Text(digit, size=16, weight=ft.FontWeight.BOLD),
|
ft.Text(digit, size=16, weight=ft.FontWeight.BOLD),
|
||||||
bgcolor="#E3F2FD",
|
bgcolor="#94BBCF",
|
||||||
padding=8,
|
padding=8,
|
||||||
border_radius=5
|
border_radius=5
|
||||||
) for digit in remainders]
|
) for digit in remainders]
|
||||||
@@ -204,7 +205,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton):
|
|||||||
ft.Container(
|
ft.Container(
|
||||||
ft.Text(f"Результат: {('-' if is_negative else '')}{result}₍{target_base}₎",
|
ft.Text(f"Результат: {('-' if is_negative else '')}{result}₍{target_base}₎",
|
||||||
size=15, weight=ft.FontWeight.BOLD, color="#2E7D32"),
|
size=15, weight=ft.FontWeight.BOLD, color="#2E7D32"),
|
||||||
bgcolor="#E8F5E9",
|
bgcolor="#0F110F",
|
||||||
padding=10,
|
padding=10,
|
||||||
border_radius=5
|
border_radius=5
|
||||||
)
|
)
|
||||||
@@ -322,7 +323,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton):
|
|||||||
f"мы используем метод 'переводчика' - переведём всё в десятичную,\n"
|
f"мы используем метод 'переводчика' - переведём всё в десятичную,\n"
|
||||||
f"выполним операцию и переведём результат обратно.",
|
f"выполним операцию и переведём результат обратно.",
|
||||||
size=13,
|
size=13,
|
||||||
color="#E0E0E0"
|
color="#B27171"
|
||||||
),
|
),
|
||||||
], spacing=10)
|
], spacing=10)
|
||||||
steps_container.controls.append(self.create_step_card("ШАГ 1", "Условие задачи", step1_content))
|
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([
|
step2_content = ft.Column([
|
||||||
ft.Text(f"🔄 ПЕРЕВОД ПЕРВОГО ЧИСЛА: {num1}₍{base1}₎ → десятичная",
|
ft.Text(f"🔄 ПЕРЕВОД ПЕРВОГО ЧИСЛА: {num1}₍{base1}₎ → десятичная",
|
||||||
size=18, weight=ft.FontWeight.BOLD, color="#00FFFF"),
|
size=18, weight=ft.FontWeight.BOLD, color="#00FFFF"),
|
||||||
ft.Divider(height=1, color="#E0E0E0"),
|
ft.Divider(height=1, color="#000000"),
|
||||||
ft.Text(
|
ft.Text(
|
||||||
f"Каждая позиция в {base1}-ричной системе имеет свой 'вес' - степень числа {base1}.\n"
|
f"Каждая позиция в {base1}-ричной системе имеет свой 'вес' - степень числа {base1}.\n"
|
||||||
f"Самая правая позиция (позиция 0) весит {base1}^0 = 1\n"
|
f"Самая правая позиция (позиция 0) весит {base1}^0 = 1\n"
|
||||||
f"Следующая (позиция 1) весит {base1}^1 = {base1}\n"
|
f"Следующая (позиция 1) весит {base1}^1 = {base1}\n"
|
||||||
f"Потом (позиция 2) весит {base1}^2 = {base1*base1}, и так далее.",
|
f"Потом (позиция 2) весит {base1}^2 = {base1*base1}, и так далее.",
|
||||||
size=12,
|
size=12,
|
||||||
color="#616161"
|
color="#9E7979"
|
||||||
),
|
),
|
||||||
ft.Container(height=10),
|
ft.Container(height=10),
|
||||||
self.create_detailed_conversion_table(num1, base1, dec1),
|
self.create_detailed_conversion_table(num1, base1, dec1),
|
||||||
@@ -365,12 +366,12 @@ class Button_arbitrary_calculator(ft.CupertinoButton):
|
|||||||
step3_content = ft.Column([
|
step3_content = ft.Column([
|
||||||
ft.Text(f"🔄 ПЕРЕВОД ВТОРОГО ЧИСЛА: {num2}₍{base2}₎ → десятичная",
|
ft.Text(f"🔄 ПЕРЕВОД ВТОРОГО ЧИСЛА: {num2}₍{base2}₎ → десятичная",
|
||||||
size=18, weight=ft.FontWeight.BOLD, color="#00FFFF"),
|
size=18, weight=ft.FontWeight.BOLD, color="#00FFFF"),
|
||||||
ft.Divider(height=1, color="#E0E0E0"),
|
ft.Divider(height=1, color="#000000"),
|
||||||
ft.Text(
|
ft.Text(
|
||||||
f"Аналогично переводим второе число из {base2}-ричной системы.\n"
|
f"Аналогично переводим второе число из {base2}-ричной системы.\n"
|
||||||
f"В {base2}-ричной системе веса позиций: 1, {base2}, {base2*base2}, {base2*base2*base2}...",
|
f"В {base2}-ричной системе веса позиций: 1, {base2}, {base2*base2}, {base2*base2*base2}...",
|
||||||
size=12,
|
size=12,
|
||||||
color="#616161"
|
color="#CB8686"
|
||||||
),
|
),
|
||||||
ft.Container(height=10),
|
ft.Container(height=10),
|
||||||
self.create_detailed_conversion_table(num2, base2, dec2),
|
self.create_detailed_conversion_table(num2, base2, dec2),
|
||||||
@@ -414,14 +415,14 @@ class Button_arbitrary_calculator(ft.CupertinoButton):
|
|||||||
step4_content = ft.Column([
|
step4_content = ft.Column([
|
||||||
ft.Text(f"🧮 ВЫПОЛНЕНИЕ ОПЕРАЦИИ: {op_name.upper()}",
|
ft.Text(f"🧮 ВЫПОЛНЕНИЕ ОПЕРАЦИИ: {op_name.upper()}",
|
||||||
size=18, weight=ft.FontWeight.BOLD, color="#FFD700"),
|
size=18, weight=ft.FontWeight.BOLD, color="#FFD700"),
|
||||||
ft.Divider(height=1, color="#E0E0E0"),
|
ft.Divider(height=1, color="#1D1919"),
|
||||||
ft.Text(
|
ft.Text(
|
||||||
f"Теперь у нас есть оба числа в десятичной системе:\n"
|
f"Теперь у нас есть оба числа в десятичной системе:\n"
|
||||||
f"• Первое число: {dec1}\n"
|
f"• Первое число: {dec1}\n"
|
||||||
f"• Второе число: {dec2}\n\n"
|
f"• Второе число: {dec2}\n\n"
|
||||||
f"Можем выполнить {op_name} обычным способом!",
|
f"Можем выполнить {op_name} обычным способом!",
|
||||||
size=13,
|
size=13,
|
||||||
color="#616161"
|
color="#C9A5A5"
|
||||||
),
|
),
|
||||||
ft.Container(
|
ft.Container(
|
||||||
content=ft.Text(calc_text, size=22, weight=ft.FontWeight.BOLD, color="white"),
|
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(
|
ft.Container(
|
||||||
content=ft.Text(explanation, size=12, italic=True),
|
content=ft.Text(explanation, size=12, italic=True),
|
||||||
bgcolor="#FFF3E0",
|
bgcolor="#282724",
|
||||||
padding=15,
|
padding=15,
|
||||||
border_radius=8
|
border_radius=8
|
||||||
)
|
)
|
||||||
@@ -448,7 +449,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton):
|
|||||||
step5_content = ft.Column([
|
step5_content = ft.Column([
|
||||||
ft.Text(f"🔢 ПЕРЕВОД РЕЗУЛЬТАТА: {result_dec}₍₁₀₎ → {result_base}-ричная",
|
ft.Text(f"🔢 ПЕРЕВОД РЕЗУЛЬТАТА: {result_dec}₍₁₀₎ → {result_base}-ричная",
|
||||||
size=18, weight=ft.FontWeight.BOLD, color="#00FFFF"),
|
size=18, weight=ft.FontWeight.BOLD, color="#00FFFF"),
|
||||||
ft.Divider(height=1, color="#E0E0E0"),
|
ft.Divider(height=1, color="#7A5555"),
|
||||||
ft.Text(
|
ft.Text(
|
||||||
f"Последний шаг - переводим результат {result_dec} в {result_base}-ричную систему.\n"
|
f"Последний шаг - переводим результат {result_dec} в {result_base}-ричную систему.\n"
|
||||||
f"Используем алгоритм деления с остатком:\n"
|
f"Используем алгоритм деления с остатком:\n"
|
||||||
@@ -457,7 +458,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton):
|
|||||||
f"• Продолжаем с частным, пока оно не станет равно 0\n"
|
f"• Продолжаем с частным, пока оно не станет равно 0\n"
|
||||||
f"• Читаем остатки СНИЗУ ВВЕРХ",
|
f"• Читаем остатки СНИЗУ ВВЕРХ",
|
||||||
size=12,
|
size=12,
|
||||||
color="#616161"
|
color="#FAE1E1"
|
||||||
),
|
),
|
||||||
ft.Container(height=10),
|
ft.Container(height=10),
|
||||||
self.create_division_steps(result_dec, result_base),
|
self.create_division_steps(result_dec, result_base),
|
||||||
@@ -502,7 +503,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton):
|
|||||||
border_radius=15,
|
border_radius=15,
|
||||||
alignment=ft.alignment.center
|
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.Text("📊 ПРОВЕРКА РЕШЕНИЯ:", size=16, weight=ft.FontWeight.BOLD, color="#E0E0E0"),
|
||||||
ft.Container(
|
ft.Container(
|
||||||
content=ft.Column([
|
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"3. Операция: {dec1} {op_symbol} {dec2} = {result_dec}₍₁₀₎ ✓", size=13),
|
||||||
ft.Text(f"4. Результат: {result_dec}₍₁₀₎ = {result_str}₍{result_base}₎ ✓", size=13),
|
ft.Text(f"4. Результат: {result_dec}₍₁₀₎ = {result_str}₍{result_base}₎ ✓", size=13),
|
||||||
]),
|
]),
|
||||||
bgcolor="#F5F5F5",
|
bgcolor="#1F1919",
|
||||||
padding=15,
|
padding=15,
|
||||||
border_radius=8
|
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:
|
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(
|
return ft.Dropdown(
|
||||||
label=label,
|
label=label,
|
||||||
value=default_value,
|
value=default_value,
|
||||||
@@ -702,9 +703,10 @@ class Button_arbitrary_calculator(ft.CupertinoButton):
|
|||||||
ft.Text(
|
ft.Text(
|
||||||
"• В 5-ричной системе используются цифры: 0, 1, 2, 3, 4\n"
|
"• В 5-ричной системе используются цифры: 0, 1, 2, 3, 4\n"
|
||||||
"• В 18-ричной системе: 0-9, A-H (где A=10, B=11, ..., H=17)\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,
|
size=12,
|
||||||
color="#424242"
|
color="#281B1B"
|
||||||
)
|
)
|
||||||
]),
|
]),
|
||||||
bgcolor="#E3F2FD",
|
bgcolor="#E3F2FD",
|
||||||
@@ -721,7 +723,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton):
|
|||||||
"• Числа могут быть в разных системах счисления\n"
|
"• Числа могут быть в разных системах счисления\n"
|
||||||
"• Если результат отрицательный, появится знак минус",
|
"• Если результат отрицательный, появится знак минус",
|
||||||
size=12,
|
size=12,
|
||||||
color="#424242"
|
color="#1F1C1C"
|
||||||
)
|
)
|
||||||
]),
|
]),
|
||||||
bgcolor="#FFF3E0",
|
bgcolor="#FFF3E0",
|
||||||
@@ -738,7 +740,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton):
|
|||||||
"• В шестнадцатеричной: 0-9, A-F (где F=15)\n"
|
"• В шестнадцатеричной: 0-9, A-F (где F=15)\n"
|
||||||
"• Попробуйте A₍₁₆₎ × 12₍₈₎ (это 10 × 10 в десятичной)",
|
"• Попробуйте A₍₁₆₎ × 12₍₈₎ (это 10 × 10 в десятичной)",
|
||||||
size=12,
|
size=12,
|
||||||
color="#424242"
|
color="#292424"
|
||||||
)
|
)
|
||||||
]),
|
]),
|
||||||
bgcolor="#E3F2FD",
|
bgcolor="#E3F2FD",
|
||||||
@@ -792,7 +794,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton):
|
|||||||
ft.Divider(),
|
ft.Divider(),
|
||||||
ft.Container(
|
ft.Container(
|
||||||
content=ft.Row([
|
content=ft.Row([
|
||||||
ft.Text("📊 Результат:", size=18, weight=ft.FontWeight.BOLD),
|
ft.Text("📊 Результат:",color="#3C2525", size=18, weight=ft.FontWeight.BOLD),
|
||||||
self.result_add
|
self.result_add
|
||||||
]),
|
]),
|
||||||
bgcolor="#F5F5F5",
|
bgcolor="#F5F5F5",
|
||||||
@@ -833,7 +835,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton):
|
|||||||
ft.Divider(),
|
ft.Divider(),
|
||||||
ft.Container(
|
ft.Container(
|
||||||
content=ft.Row([
|
content=ft.Row([
|
||||||
ft.Text("📊 Результат:", size=18, weight=ft.FontWeight.BOLD),
|
ft.Text("📊 Результат:",color="#452020", size=18, weight=ft.FontWeight.BOLD),
|
||||||
self.result_sub
|
self.result_sub
|
||||||
]),
|
]),
|
||||||
bgcolor="#F5F5F5",
|
bgcolor="#F5F5F5",
|
||||||
@@ -874,7 +876,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton):
|
|||||||
ft.Divider(),
|
ft.Divider(),
|
||||||
ft.Container(
|
ft.Container(
|
||||||
content=ft.Row([
|
content=ft.Row([
|
||||||
ft.Text("📊 Результат:", size=18, weight=ft.FontWeight.BOLD),
|
ft.Text("📊 Результат:",color="#422525", size=18, weight=ft.FontWeight.BOLD),
|
||||||
self.result_mult
|
self.result_mult
|
||||||
]),
|
]),
|
||||||
bgcolor="#F5F5F5",
|
bgcolor="#F5F5F5",
|
||||||
@@ -964,7 +966,7 @@ class Button_arbitrary_calculator(ft.CupertinoButton):
|
|||||||
text_align=ft.TextAlign.CENTER
|
text_align=ft.TextAlign.CENTER
|
||||||
),
|
),
|
||||||
ft.Text(
|
ft.Text(
|
||||||
"Выполняйте операции с числами в системах от 2 до 36 с подробными объяснениями!",
|
"Выполняйте операции с числами в системах от 2 до 50 с подробными объяснениями!",
|
||||||
size=14,
|
size=14,
|
||||||
color="white",
|
color="white",
|
||||||
text_align=ft.TextAlign.CENTER,
|
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:
|
else:
|
||||||
explanation += f" = {digit_result}"
|
explanation += f" = {digit_result}"
|
||||||
|
|
||||||
detailed_calc.insert(0, explanation)
|
detailed_calc.append(explanation)
|
||||||
carry = new_carry
|
carry = new_carry
|
||||||
|
|
||||||
if carry > 0:
|
if carry > 0:
|
||||||
result.insert(0, self.digits[carry])
|
result.insert(0, self.digits[carry])
|
||||||
detailed_calc.insert(0, f"Финальный перенос: {carry}")
|
detailed_calc.append(f"Финальный перенос: {carry}")
|
||||||
|
|
||||||
result_str = ''.join(result)
|
result_str = ''.join(result)
|
||||||
|
|
||||||
@@ -460,7 +460,7 @@ class StepByStepSolver:
|
|||||||
|
|
||||||
digit_result = d1 - d2
|
digit_result = d1 - d2
|
||||||
result.insert(0, self.digits[digit_result])
|
result.insert(0, self.digits[digit_result])
|
||||||
detailed_calc.insert(0, explanation)
|
detailed_calc.append(explanation)
|
||||||
|
|
||||||
# Убираем ведущие нули
|
# Убираем ведущие нули
|
||||||
result_str = ''.join(result).lstrip('0') or '0'
|
result_str = ''.join(result).lstrip('0') or '0'
|
||||||
|
|||||||
Reference in New Issue
Block a user