Files
Calculater_chelgu/app/src/pages/tabs/pentecostal_calculeator10.py
2025-11-10 12:38:21 +05:00

484 lines
23 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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_quinquagesimal_calculator(ft.CupertinoButton):
def __init__(self, text: str = "50-ричный калькулятор"):
self.result_left = ft.Text(value="0", size=30, width=300)
self.result_right = ft.Text(value="0", size=30, width=300)
self.result_mult = ft.Text(value="0", size=30, width=300)
self.result_div = ft.Text(value="0", size=30, width=300)
self.decimal_left = ft.Text(value="(0₁₀)", size=14, color="#B0B0B0", width=300)
self.decimal_right = ft.Text(value="(0₁₀)", size=14, color="#B0B0B0", width=300)
self.decimal_mult = ft.Text(value="(0₁₀)", size=14, color="#B0B0B0", width=300)
self.decimal_div = ft.Text(value="(0₁₀)", 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)
# Допустимые символы: 0-9, A-Z, a-n (всего: 10 + 26 + 14 = 50)
self.digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn"
# Солвер для 50-ричной системы с нашим алфавитом
self.solver = StepByStepSolver(base=50, digits=self.digits)
super().__init__(
bgcolor="#00000000",
disabled_bgcolor="#3A1E51",
text=text,
color="white",
on_click=self.test_data
)
def validate_base50(self, value: str) -> bool:
"""Проверяет, является ли строка корректным 50-ричным числом.
Допустимые символы: 0-9, A-Z, a-n (0-49), опциональный знак минус
"""
if value is None or value == "":
return True
v = value.strip()
if v == "":
return True
if v[0] == '-':
v = v[1:]
# В 50-ричной системе используются цифры 0-9, A-Z, a-n (всего 50 символов)
valid_chars = self.digits # 0-9, A-Z, a-n
return all(c in valid_chars for c in v)
def to_base50(self, decimal_num: int) -> str:
"""Преобразование десятичного числа в 50-ричное"""
if decimal_num == 0:
return "0"
is_negative = decimal_num < 0
decimal_num = abs(decimal_num)
result = ""
while decimal_num > 0:
remainder = decimal_num % 50
result = self.digits[remainder] + result
decimal_num //= 50
return ("-" + result) if is_negative else result
def from_base50(self, base50_str: str) -> int:
"""Преобразование 50-ричного числа в десятичное"""
if not base50_str:
return 0
base50_str = base50_str.strip()
if base50_str == "" or base50_str == "0":
return 0
is_negative = base50_str.startswith('-')
if is_negative:
base50_str = base50_str[1:]
result = 0
for char in base50_str:
if char in self.digits:
digit_value = self.digits.index(char)
result = result * 50 + digit_value
else:
raise ValueError(f"Недопустимый символ '{char}' для 50-ричной системы")
return -result if is_negative else result
def show_steps_left(self, num1: str, num2: str, operation: Operation):
"""Отображает пошаговое решение для левой колонки (вычитание)"""
StepByStepDisplay.show_steps(self.steps_left, self.solver, num1, num2, operation)
def show_steps_right(self, num1: str, num2: str, operation: Operation):
"""Отображает пошаговое решение для правой колонки (сложение)"""
StepByStepDisplay.show_steps(self.steps_right, self.solver, num1, num2, operation)
def show_steps_mult(self, num1: str, num2: str, operation: Operation):
"""Отображает пошаговое решение для колонки умножения"""
StepByStepDisplay.show_steps(self.steps_mult, self.solver, num1, num2, operation)
def show_steps_div(self, num1: str, num2: str, operation: Operation):
"""Отображает пошаговое решение для колонки деления"""
StepByStepDisplay.show_steps(self.steps_div, self.solver, num1, num2, operation)
def calculate_subtraction(self, e):
try:
val1 = (self.input_left_1.value or "").strip()
val2 = (self.input_left_2.value or "").strip()
# Проверка корректности 50-ричных чисел
if not self.validate_base50(val1) or not self.validate_base50(val2):
self.result_left.value = "Ошибка: неверный формат"
self.decimal_left.value = "Используйте 0-9, A-Z, a-n"
e.page.update()
return
# Преобразуем в десятичные числа
num1 = self.from_base50(val1 if val1 else "0")
num2 = self.from_base50(val2 if val2 else "0")
# Вычисляем результат
result = num1 - num2
# Преобразуем обратно в 50-ричный формат
base50_result = self.to_base50(result)
self.result_left.value = base50_result
self.decimal_left.value = f"({result}₁₀)"
e.page.update()
# Получаем пошаговое решение (убираем знак минус для солвера)
clean_val1 = val1.lstrip('-') if val1.startswith('-') else val1
clean_val2 = val2.lstrip('-') if val2.startswith('-') else val2
self.show_steps_left(clean_val1 if clean_val1 else "0", clean_val2 if clean_val2 else "0", Operation.SUBTRACTION)
except ValueError as ex:
self.result_left.value = "Ошибка"
self.decimal_left.value = str(ex)
e.page.update()
def calculate_addition(self, e):
try:
val1 = (self.input_right_1.value or "").strip()
val2 = (self.input_right_2.value or "").strip()
# Проверка корректности 50-ричных чисел
if not self.validate_base50(val1) or not self.validate_base50(val2):
self.result_right.value = "Ошибка: неверный формат"
self.decimal_right.value = "Используйте 0-9, A-Z, a-n"
e.page.update()
return
# Преобразуем в десятичные числа
num1 = self.from_base50(val1 if val1 else "0")
num2 = self.from_base50(val2 if val2 else "0")
# Вычисляем результат
result = num1 + num2
# Преобразуем обратно в 50-ричный формат
base50_result = self.to_base50(result)
self.result_right.value = base50_result
self.decimal_right.value = f"({result}₁₀)"
e.page.update()
# Получаем пошаговое решение
clean_val1 = val1.lstrip('-') if val1.startswith('-') else val1
clean_val2 = val2.lstrip('-') if val2.startswith('-') else val2
self.show_steps_right(clean_val1 if clean_val1 else "0", clean_val2 if clean_val2 else "0", Operation.ADDITION)
except ValueError as ex:
self.result_right.value = "Ошибка"
self.decimal_right.value = str(ex)
e.page.update()
def calculate_multiplication(self, e):
try:
val1 = (self.input_mult_1.value or "").strip()
val2 = (self.input_mult_2.value or "").strip()
# Проверка корректности 50-ричных чисел
if not self.validate_base50(val1) or not self.validate_base50(val2):
self.result_mult.value = "Ошибка: неверный формат"
self.decimal_mult.value = "Используйте 0-9, A-Z, a-n"
e.page.update()
return
# Преобразуем в десятичные числа
num1 = self.from_base50(val1 if val1 else "0")
num2 = self.from_base50(val2 if val2 else "0")
# Вычисляем результат
result = num1 * num2
# Преобразуем обратно в 50-ричный формат
base50_result = self.to_base50(result)
self.result_mult.value = base50_result
self.decimal_mult.value = f"({result}₁₀)"
e.page.update()
# Получаем пошаговое решение
clean_val1 = val1.lstrip('-') if val1.startswith('-') else val1
clean_val2 = val2.lstrip('-') if val2.startswith('-') else val2
self.show_steps_mult(clean_val1 if clean_val1 else "0", clean_val2 if clean_val2 else "0", Operation.MULTIPLICATION)
except ValueError as ex:
self.result_mult.value = "Ошибка"
self.decimal_mult.value = str(ex)
e.page.update()
def calculate_division(self, e):
try:
val1 = (self.input_div_1.value or "").strip()
val2 = (self.input_div_2.value or "").strip()
# Проверка корректности 50-ричных чисел
if not self.validate_base50(val1) or not self.validate_base50(val2):
self.result_div.value = "Ошибка: неверный формат"
self.decimal_div.value = "Используйте 0-9, A-Z, a-n"
e.page.update()
return
# Преобразуем в десятичные числа
num1 = self.from_base50(val1 if val1 else "0")
num2 = self.from_base50(val2 if val2 else "0")
# Проверка деления на ноль
if num2 == 0:
self.result_div.value = "Ошибка"
self.decimal_div.value = "Деление на ноль!"
e.page.update()
return
# Вычисляем результат (целочисленное деление)
result = num1 // num2
# Преобразуем обратно в 50-ричный формат
base50_result = self.to_base50(result)
self.result_div.value = base50_result
self.decimal_div.value = f"({result}₁₀)"
e.page.update()
# Получаем пошаговое решение
clean_val1 = val1.lstrip('-') if val1.startswith('-') else val1
clean_val2 = val2.lstrip('-') if val2.startswith('-') else val2
self.show_steps_div(clean_val1 if clean_val1 else "0", clean_val2 if clean_val2 else "0", Operation.DIVISION)
except ValueError as ex:
self.result_div.value = "Ошибка"
self.decimal_div.value = str(ex)
e.page.update()
def test_data(self, e):
# Создаем поля ввода для 50-ричных чисел
# Явно перечисляем ВСЕ 50 допустимых символов в regex
# 0-9 (10), A-Z (26), a-n (14) = 50 символов
allowed_chars = r"^-?[0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn]*$"
self.input_left_1 = ft.TextField(
label="50-ричное число 1",
width=250,
text_align=ft.TextAlign.RIGHT,
value="0",
input_filter=ft.InputFilter(regex_string=allowed_chars),
hint_text="Например: 1A (60₁₀) или Z (35₁₀) или a (36₁₀)"
)
self.input_left_2 = ft.TextField(
label="50-ричное число 2",
width=250,
text_align=ft.TextAlign.RIGHT,
value="0",
input_filter=ft.InputFilter(regex_string=allowed_chars),
hint_text="Например: B (11₁₀) или n (49₁₀)"
)
self.input_right_1 = ft.TextField(
label="50-ричное число 1",
width=250,
text_align=ft.TextAlign.RIGHT,
value="0",
input_filter=ft.InputFilter(regex_string=allowed_chars),
hint_text="Например: 1A (60₁₀) или c (38₁₀)"
)
self.input_right_2 = ft.TextField(
label="50-ричное число 2",
width=250,
text_align=ft.TextAlign.RIGHT,
value="0",
input_filter=ft.InputFilter(regex_string=allowed_chars),
hint_text="Например: C (12₁₀) или k (46₁₀)"
)
self.input_mult_1 = ft.TextField(
label="50-ричное число 1",
width=250,
text_align=ft.TextAlign.RIGHT,
value="0",
input_filter=ft.InputFilter(regex_string=allowed_chars),
hint_text="Например: A (10₁₀) или d (39₁₀)"
)
self.input_mult_2 = ft.TextField(
label="50-ричное число 2",
width=250,
text_align=ft.TextAlign.RIGHT,
value="0",
input_filter=ft.InputFilter(regex_string=allowed_chars),
hint_text="Например: 5 (5₁₀) или B (11₁₀)"
)
self.input_div_1 = ft.TextField(
label="50-ричное число 1",
width=250,
text_align=ft.TextAlign.RIGHT,
value="0",
input_filter=ft.InputFilter(regex_string=allowed_chars),
hint_text="Например: 14 (54₁₀) или Z (35₁₀)"
)
self.input_div_2 = ft.TextField(
label="50-ричное число 2",
width=250,
text_align=ft.TextAlign.RIGHT,
value="0",
input_filter=ft.InputFilter(regex_string=allowed_chars),
hint_text="Например: 2 (2₁₀) или A (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("50-ричный калькулятор", size=20, color="white", weight=ft.FontWeight.BOLD),
ft.Text("Система счисления с основанием 50", size=11, color="#B0B0B0", italic=True),
ft.Text("Используйте: 0-9 (0-9), A-Z (10-35), a-n (36-49)", size=11, color="#B0B0B0"),
ft.Text("Примеры: 10₍₅₀₎=50₁₀, A₍₅₀₎=10₁₀, Z₍₅₀₎=35₁₀, n₍₅₀₎=49₁₀", size=10, color="#90EE90"),
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()