This commit is contained in:
2025-11-08 11:16:24 +05:00
parent 81c60f2c70
commit 760fb43e62
16 changed files with 2798 additions and 257 deletions

View File

@@ -0,0 +1,342 @@
# Документация алгоритма пошагового решения задач с системами счисления
## Описание
Алгоритм для пошагового решения задач с различными системами счисления (2, 8, 16, n-ричные), аналогичный работе Photomath. Показывает каждый шаг решения с подробными объяснениями.
## Основные возможности
### 1. Поддерживаемые системы счисления
- **Двоичная (base=2)**: 0, 1
- **Восьмеричная (base=8)**: 0-7
- **Десятичная (base=10)**: 0-9
- **Шестнадцатеричная (base=16)**: 0-9, A-F
- **Любая n-ричная (base=n)**: до base=36
### 2. Поддерживаемые операции
- Сложение (+)
- Вычитание (-)
- Преобразование между системами счисления
## Структура алгоритма
### Класс `Step`
Представляет один шаг решения:
- `title` - название шага
- `description` - описание что делается
- `visual` - визуальное представление (формулы, вычисления)
- `result` - результат этого шага
### Класс `StepByStepSolver`
Основной класс для решения задач:
#### Методы:
- `solve(num1, num2, operation)` - решить задачу
- `add_with_steps(num1, num2)` - сложение с шагами
- `subtract_with_steps(num1, num2)` - вычитание с шагами
- `convert_with_steps(number, target_base)` - конвертация с шагами
- `print_solution(steps)` - вывод решения
## Алгоритм сложения (подробно)
### Шаг 1: Анализ условия
```
Входные данные:
- Число 1 в n-ричной системе
- Число 2 в n-ричной системе
- Основание системы счисления (n)
Пример: 1011₍₂₎ + 110₍₂₎
```
### Шаг 2: Выравнивание разрядов
```
Алгоритм:
1. Определить максимальную длину чисел
2. Дополнить короткое число нулями слева
Пример:
1011 (уже 4 разряда)
+ 0110 (дополнено до 4 разрядов)
------
```
### Шаг 3: Сложение в столбик (справа налево)
```
Для каждого разряда i (от младшего к старшему):
1. Взять цифру d1 из первого числа
2. Взять цифру d2 из второго числа
3. Добавить перенос carry из предыдущего разряда
4. Вычислить: total = d1 + d2 + carry
5. Результат в разряде: digit = total mod base
6. Новый перенос: carry = total div base
7. Записать digit в результат
Пример (двоичная система, base=2):
Позиция 0 (самая правая):
1 + 0 + 0(перенос) = 1
1 mod 2 = 1 (цифра результата)
1 div 2 = 0 (новый перенос)
Позиция 1:
1 + 1 + 0(перенос) = 2
2 mod 2 = 0 (цифра результата)
2 div 2 = 1 (новый перенос)
Позиция 2:
0 + 1 + 1(перенос) = 2
2 mod 2 = 0 (цифра результата)
2 div 2 = 1 (новый перенос)
Позиция 3:
1 + 0 + 1(перенос) = 2
2 mod 2 = 0 (цифра результата)
2 div 2 = 1 (новый перенос)
Финальный перенос: 1
Результат: 10001₍₂₎
```
### Шаг 4: Проверка через десятичную систему
```
Алгоритм проверки:
1. Перевести оба числа в десятичную систему
2. Выполнить операцию в десятичной системе
3. Перевести результат обратно в исходную систему
4. Сравнить с полученным результатом
Пример:
1011₍₂₎ = 1×2³ + 0×2² + 1×2¹ + 1×2⁰ = 8+0+2+1 = 11₍₁₀₎
0110₍₂₎ = 0×2³ + 1×2² + 1×2¹ + 0×2⁰ = 0+4+2+0 = 6₍₁₀₎
11 + 6 = 17₍₁₀₎
17₍₁₀₎ = 10001₍₂₎ ✓
```
## Алгоритм вычитания (подробно)
### Шаг 1: Анализ условия
```
Входные данные:
- Уменьшаемое в n-ричной системе
- Вычитаемое в n-ричной системе
- Основание системы счисления (n)
Пример: 1101₍₂₎ - 1011₍₂₎
```
### Шаг 2: Выравнивание разрядов
```
Аналогично сложению - дополнение нулями слева
```
### Шаг 3: Вычитание в столбик (справа налево)
```
Для каждого разряда i (от младшего к старшему):
1. Взять цифру d1 из уменьшаемого
2. Взять цифру d2 из вычитаемого
3. Учесть заем borrow из текущего разряда
4. Если (d1 - borrow) < d2:
- Занять base из следующего разряда
- d1 = d1 + base
- borrow = 1 для следующей итерации
5. Иначе:
- borrow = 0
6. Результат: digit = d1 - borrow - d2
Пример (двоичная система, base=2):
1101
- 1011
------
Позиция 0:
1 - 1 = 0 (заем не нужен)
Позиция 1:
0 - 1 → нужен заем
0 + 2 - 1 = 1 (занимаем 2)
Новый заем = 1
Позиция 2:
1 - 1(заем) = 0
0 - 0 = 0
Позиция 3:
1 - 1 = 0
Результат: 0010₍₂₎ = 10₍₂₎
```
### Шаг 4: Проверка
```
Аналогично сложению - проверка через десятичную систему
```
## Алгоритм конвертации между системами
### Из n-ричной в десятичную
```
Алгоритм:
1. Для каждой цифры digit на позиции i (справа налево, начиная с 0):
result += digit_value × base^i
Пример: 2A₍₁₆₎ → 10-ичная
A×16⁰ = 10×1 = 10
2×16¹ = 2×16 = 32
Сумма: 10 + 32 = 42₍₁₀₎
```
### Из десятичной в n-ричную
```
Алгоритм:
1. Делим число на base, записываем остаток
2. Результат деления становится новым числом
3. Повторяем пока число > 0
4. Читаем остатки снизу вверх
Пример: 42₍₁₀₎ → 16-ричная
42 ÷ 16 = 2, остаток: 10 (A)
2 ÷ 16 = 0, остаток: 2
Читаем снизу вверх: 2A₍₁₆₎
```
## Использование в коде
### Пример 1: Сложение в двоичной системе
```python
from step_by_step_solver import StepByStepSolver, Operation
# Создаем решатель для двоичной системы
solver = StepByStepSolver(base=2)
# Решаем задачу
steps = solver.solve("1011", "110", Operation.ADDITION)
# Выводим решение
solver.print_solution(steps)
```
### Пример 2: Вычитание в восьмеричной системе
```python
solver = StepByStepSolver(base=8)
steps = solver.solve("756", "237", Operation.SUBTRACTION)
solver.print_solution(steps)
```
### Пример 3: Получение шагов для UI
```python
solver = StepByStepSolver(base=16)
steps = solver.solve("A5", "3F", Operation.ADDITION)
# Обработка шагов для отображения в интерфейсе
for i, step in enumerate(steps, 1):
print(f"Шаг {i}: {step.title}")
print(f"Описание: {step.description}")
print(f"Визуализация:\n{step.visual}")
print(f"Результат: {step.result}\n")
```
## Интеграция с Flet UI
### Пример компонента для отображения решения
```python
import flet as ft
from step_by_step_solver import StepByStepSolver, Operation
class StepByStepView(ft.Column):
def __init__(self, base: int):
super().__init__()
self.solver = StepByStepSolver(base=base)
self.steps_display = ft.Column(scroll=ft.ScrollMode.AUTO)
def show_solution(self, num1: str, num2: str, operation: Operation):
# Получить шаги решения
steps = self.solver.solve(num1, num2, operation)
# Очистить предыдущее решение
self.steps_display.controls.clear()
# Добавить каждый шаг в UI
for i, step in enumerate(steps, 1):
step_container = ft.Container(
content=ft.Column([
ft.Text(f"Шаг {i}: {step.title}",
size=18, weight=ft.FontWeight.BOLD),
ft.Text(step.description, size=14),
ft.Text(step.visual,
font_family="Courier New", size=12) if step.visual else None,
ft.Text(f"➤ {step.result}",
size=14, color="green") if step.result else None,
]),
bgcolor="#3A1E51",
padding=15,
border_radius=10,
margin=ft.margin.only(bottom=10)
)
self.steps_display.controls.append(step_container)
self.update()
```
## Расширение алгоритма
### Добавление новых операций
```python
class Operation(Enum):
ADDITION = "сложение"
SUBTRACTION = "вычитание"
MULTIPLICATION = "умножение" # Новая операция
DIVISION = "деление" # Новая операция
```
### Поддержка дробных чисел
```python
def add_fraction_support(self):
# Обработка чисел с дробной частью
# Разделение на целую и дробную части
# Отдельная обработка каждой части
pass
```
## Оптимизация и производительность
### Кэширование результатов
```python
from functools import lru_cache
@lru_cache(maxsize=128)
def to_decimal_cached(self, number: str) -> int:
return self.to_decimal(number)
```
### Ограничение количества шагов
```python
def solve_optimized(self, num1: str, num2: str, operation: Operation,
max_steps: int = 10) -> List[Step]:
steps = self.solve(num1, num2, operation)
return steps[:max_steps] # Ограничение
```
## Тестирование
### Примеры тестовых случаев
```python
def test_binary_addition():
solver = StepByStepSolver(base=2)
steps = solver.solve("1011", "110", Operation.ADDITION)
assert len(steps) == 4
assert steps[-1].result == "10001₍₂₎"
def test_octal_subtraction():
solver = StepByStepSolver(base=8)
steps = solver.solve("756", "237", Operation.SUBTRACTION)
assert len(steps) == 4
assert steps[-1].result == "517₍₈₎"
```
## Заключение
Этот алгоритм предоставляет полное пошаговое решение задач с системами счисления, аналогично Photomath. Он может быть легко интегрирован в UI приложения и расширен дополнительными функциями.

233
app/src/README_SOLVER.md Normal file
View File

@@ -0,0 +1,233 @@
# Калькулятор систем счисления с пошаговым решением
## Описание
Интерактивный калькулятор для работы с различными системами счисления (2, 8, 10, 16-ричные) с **пошаговым объяснением решения** аналогично Photomath.
## Возможности ✨
- ✅ Сложение и вычитание в двоичной системе (с дополнительным кодом)
- ✅ Сложение и вычитание в восьмеричной системе
- ✅ Сложение и вычитание в десятичной системе
- ✅ Сложение и вычитание в шестнадцатеричной системе
- 📝 **Пошаговое объяснение каждого решения**
- ✓ Автоматическая проверка результатов
- 🎨 Красивый UI с цветовой подсветкой
## Быстрый старт
### Запуск примера алгоритма
```bash
cd app/src
python3 step_by_step_solver.py
```
Вы увидите примеры пошагового решения для разных систем счисления.
### Использование в коде
```python
from step_by_step_solver import StepByStepSolver, Operation
# Создать решатель для двоичной системы
solver = StepByStepSolver(base=2)
# Решить задачу
steps = solver.solve("1011", "110", Operation.ADDITION)
# Вывести решение
solver.print_solution(steps)
```
### Пример вывода
```
═══════════════════════════════════════════════════════════
ПОШАГОВОЕ РЕШЕНИЕ
═══════════════════════════════════════════════════════════
████████████████████████████████████████████████████████████
ШАГ 1: Условие задачи
████████████████████████████████████████████████████████████
Необходимо сложить два числа в двоичная (2-ричной) системе счисления
1011₍2₎ + 110₍2₎ = ?
████████████████████████████████████████████████████████████
ШАГ 2: Выравнивание чисел
████████████████████████████████████████████████████████████
Дополняем числа нулями слева до одинаковой длины (4 разрядов)
1011
+ 0110
------
████████████████████████████████████████████████████████████
ШАГ 3: Сложение в столбик
████████████████████████████████████████████████████████████
Складываем числа справа налево, учитывая переносы...
➤ Результат: 10001₍2₎
████████████████████████████████████████████████████████████
ШАГ 4: Проверка результата
████████████████████████████████████████████████████████████
Проверим правильность через перевод в десятичную систему
1011₍2₎ = 11₍₁₀₎
110₍2₎ = 6₍₁₀₎
11 + 6 = 17
17₍₁₀₎ = 10001₍2₎
➤ Результат: ✓ Ответ верен: 10001₍2₎
═══════════════════════════════════════════════════════════
РЕШЕНИЕ ЗАВЕРШЕНО
═══════════════════════════════════════════════════════════
```
## Структура проекта
```
app/src/
├── step_by_step_solver.py # Основной алгоритм пошагового решения
├── calculator_mixin.py # Миксин для интеграции в UI
├── ALGORITHM_DOCUMENTATION.md # Подробная документация алгоритма
├── USER_GUIDE.md # Руководство пользователя
└── pages/tabs/
├── binary_calculeator4.py # Двоичный калькулятор с пошаговым решением
├── calculater2.py # Десятичный калькулятор с пошаговым решением
├── octogon_calculeator6.py # Восьмеричный калькулятор с пошаговым решением
└── sedecim_calculeator8.py # Шестнадцатеричный калькулятор с пошаговым решением
```
## Ключевые особенности алгоритма
### 1. Универсальность
Работает с любой системой счисления от 2 до 36:
```python
binary_solver = StepByStepSolver(base=2) # Двоичная
octal_solver = StepByStepSolver(base=8) # Восьмеричная
decimal_solver = StepByStepSolver(base=10) # Десятичная
hex_solver = StepByStepSolver(base=16) # Шестнадцатеричная
quinary_solver = StepByStepSolver(base=5) # Пятеричная
```
### 2. Подробное объяснение
Каждый шаг включает:
- 📋 Название и описание
- 📐 Визуализация вычислений
- ✅ Промежуточные результаты
- 🔍 Проверка правильности
### 3. Поддерживаемые операции
- Сложение (с переносами)
- Вычитание (с заимствованиями)
- 🔄 Конвертация между системами (в разработке)
## Примеры использования
### Двоичное сложение
```python
solver = StepByStepSolver(base=2)
steps = solver.add_with_steps("1011", "110")
# Результат: 10001₍₂₎
```
### Восьмеричное вычитание
```python
solver = StepByStepSolver(base=8)
steps = solver.subtract_with_steps("756", "237")
# Результат: 517₍₈₎
```
### Шестнадцатеричное сложение
```python
solver = StepByStepSolver(base=16)
steps = solver.add_with_steps("A5", "3F")
# Результат: E4₍₁₆₎
```
## Интеграция в UI (Flet)
Калькуляторы уже интегрированы с пошаговым решением. При нажатии кнопки "=" автоматически:
1. Вычисляется результат
2. Генерируется пошаговое решение
3. Отображается в специальной области под калькулятором
### Визуальное оформление
- 🟡 Золотой цвет - заголовки
- 🔵 Циан - названия шагов
- 🟢 Зеленый - результаты
- ⚪ Серый - описания
## API алгоритма
### Класс `StepByStepSolver`
#### Методы:
- `solve(num1, num2, operation)` - Решить задачу с пошаговым объяснением
- `add_with_steps(num1, num2)` - Сложение с шагами
- `subtract_with_steps(num1, num2)` - Вычитание с шагами
- `convert_with_steps(number, target_base)` - Конвертация с шагами
- `print_solution(steps)` - Вывести решение в консоль
#### Класс `Step`
Представляет один шаг решения:
- `title` - Название шага
- `description` - Описание что делается
- `visual` - Визуальное представление
- `result` - Результат шага
## Тестирование
Запустите встроенные примеры:
```bash
python3 step_by_step_solver.py
```
Вы увидите 4 примера:
1. Сложение в двоичной системе
2. Вычитание в восьмеричной системе
3. Сложение в шестнадцатеричной системе
4. Сложение в пятеричной системе
## Документация
- 📘 [ALGORITHM_DOCUMENTATION.md](ALGORITHM_DOCUMENTATION.md) - Полное описание алгоритма
- 📗 [USER_GUIDE.md](USER_GUIDE.md) - Руководство пользователя
## Технологии
- Python 3.x
- Flet (для UI)
- Enum (для типов операций)
- Type hints (для типобезопасности)
## Будущие улучшения
- [ ] Поддержка умножения и деления
- [ ] Работа с дробными числами
- [ ] Конвертация между любыми системами счисления
- [ ] Экспорт решения в PDF
- [ ] История вычислений
- [ ] Темная/светлая тема
## Лицензия
Этот проект разработан для образовательных целей.
## Авторы
Разработано как часть проекта калькулятора систем счисления.
---
**Примечание**: Алгоритм полностью автономен и может использоваться отдельно от UI калькулятора.

249
app/src/USER_GUIDE.md Normal file
View File

@@ -0,0 +1,249 @@
# Руководство пользователя - Калькулятор с системами счисления
## Обзор
Калькулятор с пошаговым решением задач для различных систем счисления (2, 8, 10, 16-ричные). Каждая операция сопровождается подробным объяснением хода решения, аналогично приложению Photomath.
## Доступные калькуляторы
### 1. Двоичный калькулятор (base=2)
- **Система счисления**: Двоичная (цифры: 0, 1)
- **Функции**: Сложение и вычитание двоичных чисел
- **Особенности**:
- Поддержка дополнительного кода для отрицательных чисел
- Разрядность: 16 бит
- Автоматическое определение знаковых чисел
**Пример использования:**
```
Ввод: 1011 + 110
Результат: 10001
Пошаговое решение покажет:
- Выравнивание разрядов
- Сложение в столбик с переносами
- Проверку через десятичную систему
```
### 2. Восьмеричный калькулятор (base=8)
- **Система счисления**: Восьмеричная (цифры: 0-7)
- **Функции**: Сложение и вычитание восьмеричных чисел
- **Особенности**: Поддержка отрицательных чисел
**Пример использования:**
```
Ввод: 756 - 237
Результат: 517₍₈₎ = 335₍₁₀₎
```
### 3. Десятичный калькулятор (base=10)
- **Система счисления**: Десятичная (цифры: 0-9)
- **Функции**: Сложение и вычитание целых чисел
- **Особенности**: Стандартная арифметика с подробным объяснением
### 4. Шестнадцатеричный калькулятор (base=16)
- **Система счисления**: Шестнадцатеричная (цифры: 0-9, A-F)
- **Функции**: Сложение и вычитание шестнадцатеричных чисел
- **Особенности**:
- Поддержка дробных чисел (пошаговое решение только для целых)
- Автоматическое преобразование в десятичную систему
**Пример использования:**
```
Ввод: A5 + 3F
Результат: E4₍₁₆₎ = 228₍₁₀₎
```
## Как использовать пошаговое решение
### Что показывается в решении:
#### Шаг 1: Условие задачи
- Исходные числа
- Тип операции (сложение/вычитание)
- Система счисления
#### Шаг 2: Выравнивание чисел
- Дополнение нулями слева до одинаковой длины
- Визуальное представление выровненных чисел
#### Шаг 3: Вычисление в столбик
- **Для сложения:**
- Пошаговое сложение справа налево
- Объяснение переносов
- Когда сумма ≥ base: остаток идет в результат, частное - в перенос
- **Для вычитания:**
- Пошаговое вычитание справа налево
- Объяснение заимствований
- Когда нужно занять из следующего разряда
#### Шаг 4: Проверка результата
- Перевод в десятичную систему
- Вычисление в десятичной системе
- Обратный перевод и сравнение
### Визуальное представление
Каждый шаг содержит:
- 📝 **Заголовок**: Краткое название шага
- **Описание**: Что делается на этом шаге
- **Визуализация**: Формулы и вычисления в монoширинном шрифте
-**Результат**: Итог шага (выделен зеленым)
### Цветовая схема
- 🟡 **Золотой** (#FFD700): Заголовки разделов
- 🔵 **Циан** (#00FFFF): Названия шагов
-**Светло-серый** (#E0E0E0): Описания
- 🟢 **Светло-зеленый** (#90EE90): Визуализация вычислений
- 🟢 **Зеленый** (#00FF00): Результаты
## Примеры работы алгоритма
### Пример 1: Сложение в двоичной системе
**Задача:** 1011₍₂₎ + 110₍₂₎
**Решение:**
```
Шаг 1: Условие задачи
1011₍₂₎ + 110₍₂₎ = ?
Шаг 2: Выравнивание
1011
+ 0110
------
Шаг 3: Сложение в столбик
Позиция 0: 1 + 0 = 1
Позиция 1: 1 + 1 = 2 = 0 (перенос 1)
Позиция 2: 0 + 1 + перенос(1) = 2 = 0 (перенос 1)
Позиция 3: 1 + 0 + перенос(1) = 2 = 0 (перенос 1)
Финальный перенос: 1
Результат: 10001₍₂₎
Шаг 4: Проверка
1011₍₂₎ = 11₍₁₀₎
0110₍₂₎ = 6₍₁₀₎
11 + 6 = 17
17₍₁₀₎ = 10001₍₂₎ ✓
```
### Пример 2: Вычитание в восьмеричной системе
**Задача:** 756₍₈₎ - 237₍₈₎
**Решение:**
```
Шаг 1: Условие задачи
756₍₈₎ - 237₍₈₎ = ?
Шаг 2: Выравнивание
756
- 237
-----
Шаг 3: Вычитание в столбик
Позиция 0: 6 - 7 → занимаем 8, получаем 14 - 7 = 7
Позиция 1: 5 - заем(1) = 4, 4 - 3 = 1
Позиция 2: 7 - 2 = 5
Результат: 517₍₈₎
Шаг 4: Проверка
756₍₈₎ = 494₍₁₀₎
237₍₈₎ = 159₍₁₀₎
494 - 159 = 335
335₍₁₀₎ = 517₍₈₎ ✓
```
### Пример 3: Сложение в шестнадцатеричной системе
**Задача:** A5₍₁₆₎ + 3F₍₁₆₎
**Решение:**
```
Шаг 1: Условие задачи
A5₍₁₆₎ + 3F₍₁₆₎ = ?
Шаг 2: Выравнивание
A5
+ 3F
----
Шаг 3: Сложение в столбик
Позиция 0: 5 + F(15) = 20 = 4 (перенос 1)
Позиция 1: A(10) + 3 + перенос(1) = 14 = E
Результат: E4₍₁₆₎
Шаг 4: Проверка
A5₍₁₆₎ = 165₍₁₀₎
3F₍₁₆₎ = 63₍₁₀₎
165 + 63 = 228
228₍₁₀₎ = E4₍₁₆₎ ✓
```
## Советы по использованию
### 1. Ввод чисел
- Используйте только допустимые цифры для каждой системы
- Для шестнадцатеричной: можно вводить как заглавные, так и строчные буквы (A-F)
- Отрицательные числа вводите со знаком "-"
### 2. Интерпретация результатов
- Результат всегда показывается в исходной системе счисления
- Десятичный эквивалент показывается для справки
- Пошаговое решение прокручивается - смотрите все шаги
### 3. Обучение
- Читайте каждый шаг последовательно
- Обращайте внимание на объяснения переносов и заимствований
- Проверяйте результаты через десятичную систему
### 4. Ограничения
- Пошаговое решение для шестнадцатеричной системы работает только с целыми числами
- Двоичная система использует дополнительный код для отрицательных чисел
## Техническая информация
### Алгоритм работы
1. **Парсинг ввода**: Проверка корректности введенных чисел
2. **Нормализация**: Выравнивание разрядов
3. **Вычисление**: Операция в столбик с отслеживанием переносов/заимствований
4. **Проверка**: Верификация через десятичную систему
5. **Отображение**: Форматированный вывод всех шагов
### Файлы модулей
- `step_by_step_solver.py` - Основной алгоритм решения
- `calculator_mixin.py` - Миксин для интеграции в калькуляторы
- `ALGORITHM_DOCUMENTATION.md` - Подробная документация алгоритма
## Часто задаваемые вопросы
**Q: Почему пошаговое решение не отображается для дробных чисел в hex?**
A: Текущая версия алгоритма оптимизирована для целочисленной арифметики. Поддержка дробей планируется в будущих версиях.
**Q: Как работает дополнительный код в двоичной системе?**
A: Отрицательные числа представляются в дополнительном коде: если старший бит = 1 и длина ≥ 8 бит, число интерпретируется как отрицательное.
**Q: Можно ли увеличить разрядность для двоичного калькулятора?**
A: Текущая разрядность - 16 бит. Для изменения нужно отредактировать параметр `bit_width` в коде.
**Q: Поддерживаются ли другие системы счисления (например, пятеричная)?**
A: Алгоритм поддерживает любую систему счисления от 2 до 36. Для добавления нового калькулятора создайте экземпляр `StepByStepSolver(base=n)`.
## Контакты и поддержка
Для сообщений об ошибках и предложений по улучшению обращайтесь к разработчикам проекта.
---
*Версия документации: 1.0*
*Дата обновления: 7 ноября 2025 г.*

117
app/src/calculator_mixin.py Normal file
View File

@@ -0,0 +1,117 @@
"""
Миксин для добавления пошагового решения в калькуляторы
"""
import flet as ft
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from step_by_step_solver import StepByStepSolver, Operation
class StepByStepMixin:
"""
Миксин для добавления функциональности пошагового решения в калькуляторы
"""
def init_solver(self, base: int):
"""Инициализация солвера и контейнеров для шагов"""
self.solver = StepByStepSolver(base=base)
self.steps_left = ft.Column(scroll=ft.ScrollMode.AUTO, spacing=5)
self.steps_right = ft.Column(scroll=ft.ScrollMode.AUTO, spacing=5)
def show_steps(self, steps_container: ft.Column, num1: str, num2: str, operation: Operation):
"""
Отображает пошаговое решение
Args:
steps_container: контейнер для отображения шагов (self.steps_left или self.steps_right)
num1: первое число (строка)
num2: второе число (строка)
operation: операция (сложение или вычитание)
"""
try:
# Получаем шаги решения
steps = self.solver.solve(num1, num2, operation)
# Очищаем предыдущие шаги
steps_container.controls.clear()
# Добавляем заголовок
steps_container.controls.append(
ft.Text("📝 Ход решения:", size=14, weight=ft.FontWeight.BOLD, color="#FFD700")
)
# Добавляем каждый шаг
for i, step in enumerate(steps, 1):
step_content = []
# Название шага
step_content.append(
ft.Text(f"Шаг {i}: {step.title}",
size=12, weight=ft.FontWeight.BOLD, color="#00FFFF")
)
# Описание
step_content.append(
ft.Text(step.description, size=10, color="#E0E0E0")
)
# Визуализация (если есть)
if step.visual:
step_content.append(
ft.Text(step.visual,
size=10,
font_family="Courier New",
color="#90EE90",
selectable=True)
)
# Результат (если есть)
if step.result:
step_content.append(
ft.Text(f"{step.result}",
size=11,
weight=ft.FontWeight.BOLD,
color="#00FF00")
)
# Добавляем контейнер с шагом
steps_container.controls.append(
ft.Container(
content=ft.Column(step_content, spacing=3),
bgcolor="#2A1A3A",
padding=8,
border_radius=5,
border=ft.border.all(1, "#4A3A5A")
)
)
steps_container.update()
except Exception as ex:
steps_container.controls.clear()
steps_container.controls.append(
ft.Text(f"Ошибка при генерации решения: {str(ex)}", color="red", size=10)
)
steps_container.update()
def create_steps_container(self, steps_column: ft.Column, height: int = 400, width: int = 350):
"""
Создает контейнер для отображения шагов решения
Args:
steps_column: колонка с шагами (self.steps_left или self.steps_right)
height: высота контейнера
width: ширина контейнера
Returns:
ft.Container с настроенным стилем
"""
return ft.Container(
content=steps_column,
bgcolor="#1A0A2A",
padding=10,
border_radius=5,
height=height,
width=width,
)

View File

@@ -8,3 +8,12 @@ right_column = ft.Column(
) )
alphabet="αβγδεζηθικλμνξοπρστυφχψω" alphabet="αβγδεζηθικλμνξοπρστυφχψω"
class Obstr(ft.Column):
def __init__(self):
super().__init__(
controls=[
]
)

View File

@@ -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 from pages.tabs import start1,calculater2, binary_data3, binary_calculeator4, octogon_data5, octogon_calculeator6, sedecim_data7,sedecim_calculeator8, pentecostal_system9, pentecostal_calculeator10
class Main_page(ft.View): class Main_page(ft.View):
def __init__(self, page): def __init__(self, page):
@@ -25,6 +25,7 @@ class Main_page(ft.View):
sedecim_data7.Button_sedecim_data(), sedecim_data7.Button_sedecim_data(),
sedecim_calculeator8.Button_sedecim_calculator(), sedecim_calculeator8.Button_sedecim_calculator(),
pentecostal_system9.Button_binary_data(), pentecostal_system9.Button_binary_data(),
pentecostal_calculeator10.Button_quinquagesimal_calculator(),
ft.Container( ft.Container(
bgcolor="#280A3F", bgcolor="#280A3F",
expand=True, expand=True,

View File

@@ -1,5 +1,11 @@
from designer import right_column from designer import right_column
import flet as ft 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_binary_calculator(ft.CupertinoButton): class Button_binary_calculator(ft.CupertinoButton):
def __init__(self, text: str = "Двоичный калькулятор"): def __init__(self, text: str = "Двоичный калькулятор"):
@@ -16,6 +22,13 @@ class Button_binary_calculator(ft.CupertinoButton):
self.input_right_1 = None self.input_right_1 = None
self.input_right_2 = None self.input_right_2 = None
# Контейнеры для пошагового решения
self.steps_left = ft.Column(scroll=ft.ScrollMode.AUTO, spacing=5, expand=True)
self.steps_right = ft.Column(scroll=ft.ScrollMode.AUTO, spacing=5, expand=True)
# Солвер для двоичной системы
self.solver = StepByStepSolver(base=2)
# Количество бит для представления (по умолчанию 8) # Количество бит для представления (по умолчанию 8)
self.bit_width = 16 self.bit_width = 16
@@ -54,6 +67,140 @@ class Button_binary_calculator(ft.CupertinoButton):
# Только 0 и 1 # Только 0 и 1
return all(c in "01" for c in value) return all(c in "01" for c in value)
def show_steps_left(self, num1: str, num2: str, operation: Operation):
"""Отображает пошаговое решение для левой колонки (вычитание)"""
try:
# Получаем шаги решения
steps = self.solver.solve(num1, num2, operation)
# Очищаем предыдущие шаги
self.steps_left.controls.clear()
# Добавляем заголовок
self.steps_left.controls.append(
ft.Text("📝 Ход решения:", size=14, weight=ft.FontWeight.BOLD, color="#FFD700")
)
# Добавляем каждый шаг
for i, step in enumerate(steps, 1):
step_content = []
# Название шага
step_content.append(
ft.Text(f"Шаг {i}: {step.title}",
size=12, weight=ft.FontWeight.BOLD, color="#00FFFF")
)
# Описание
step_content.append(
ft.Text(step.description, size=10, color="#E0E0E0")
)
# Визуализация (если есть)
if step.visual:
step_content.append(
ft.Text(step.visual,
size=10,
font_family="Courier New",
color="#90EE90",
selectable=True)
)
# Результат (если есть)
if step.result:
step_content.append(
ft.Text(f"{step.result}",
size=11,
weight=ft.FontWeight.BOLD,
color="#00FF00")
)
# Добавляем контейнер с шагом
self.steps_left.controls.append(
ft.Container(
content=ft.Column(step_content, spacing=3),
bgcolor="#2A1A3A",
padding=8,
border_radius=5,
border=ft.border.all(1, "#4A3A5A")
)
)
self.steps_left.update()
except Exception as ex:
self.steps_left.controls.clear()
self.steps_left.controls.append(
ft.Text(f"Ошибка при генерации решения: {str(ex)}", color="red", size=10)
)
self.steps_left.update()
def show_steps_right(self, num1: str, num2: str, operation: Operation):
"""Отображает пошаговое решение для правой колонки (сложение)"""
try:
# Получаем шаги решения
steps = self.solver.solve(num1, num2, operation)
# Очищаем предыдущие шаги
self.steps_right.controls.clear()
# Добавляем заголовок
self.steps_right.controls.append(
ft.Text("📝 Ход решения:", size=14, weight=ft.FontWeight.BOLD, color="#FFD700")
)
# Добавляем каждый шаг
for i, step in enumerate(steps, 1):
step_content = []
# Название шага
step_content.append(
ft.Text(f"Шаг {i}: {step.title}",
size=12, weight=ft.FontWeight.BOLD, color="#00FFFF")
)
# Описание
step_content.append(
ft.Text(step.description, size=10, color="#E0E0E0")
)
# Визуализация (если есть)
if step.visual:
step_content.append(
ft.Text(step.visual,
size=10,
font_family="Courier New",
color="#90EE90",
selectable=True)
)
# Результат (если есть)
if step.result:
step_content.append(
ft.Text(f"{step.result}",
size=11,
weight=ft.FontWeight.BOLD,
color="#00FF00")
)
# Добавляем контейнер с шагом
self.steps_right.controls.append(
ft.Container(
content=ft.Column(step_content, spacing=3),
bgcolor="#2A1A3A",
padding=8,
border_radius=5,
border=ft.border.all(1, "#4A3A5A")
)
)
self.steps_right.update()
except Exception as ex:
self.steps_right.controls.clear()
self.steps_right.controls.append(
ft.Text(f"Ошибка при генерации решения: {str(ex)}", color="red", size=10)
)
self.steps_right.update()
def calculate_subtraction(self, e): def calculate_subtraction(self, e):
try: try:
bin1 = self.input_left_1.value or "0" bin1 = self.input_left_1.value or "0"
@@ -89,6 +236,10 @@ class Button_binary_calculator(ft.CupertinoButton):
self.decimal_left.value = f"({result}₁₀)" self.decimal_left.value = f"({result}₁₀)"
self.result_left.update() self.result_left.update()
self.decimal_left.update() self.decimal_left.update()
# Получаем пошаговое решение
self.show_steps_left(bin1, bin2, Operation.SUBTRACTION)
except ValueError as ex: except ValueError as ex:
self.result_left.value = "Ошибка" self.result_left.value = "Ошибка"
self.decimal_left.value = str(ex) self.decimal_left.value = str(ex)
@@ -130,6 +281,10 @@ class Button_binary_calculator(ft.CupertinoButton):
self.decimal_right.value = f"({result}₁₀)" self.decimal_right.value = f"({result}₁₀)"
self.result_right.update() self.result_right.update()
self.decimal_right.update() self.decimal_right.update()
# Получаем пошаговое решение
self.show_steps_right(bin1, bin2, Operation.ADDITION)
except ValueError as ex: except ValueError as ex:
self.result_right.value = "Ошибка" self.result_right.value = "Ошибка"
self.decimal_right.value = str(ex) self.decimal_right.value = str(ex)
@@ -191,7 +346,7 @@ class Button_binary_calculator(ft.CupertinoButton):
controls=[ controls=[
ft.Column( ft.Column(
expand=True, expand=True,
alignment=ft.MainAxisAlignment.CENTER, alignment=ft.MainAxisAlignment.START,
horizontal_alignment=ft.CrossAxisAlignment.CENTER, horizontal_alignment=ft.CrossAxisAlignment.CENTER,
controls=[ controls=[
self.input_left_1, self.input_left_1,
@@ -206,12 +361,19 @@ class Button_binary_calculator(ft.CupertinoButton):
padding=10, padding=10,
border_radius=5, border_radius=5,
), ),
ft.CupertinoButton("=", on_click=self.calculate_subtraction) ft.CupertinoButton("=", on_click=self.calculate_subtraction),
ft.Container(
expand=True,
content=self.steps_left,
bgcolor="#1A0A2A",
padding=10,
border_radius=5,
)
] ]
), ),
ft.Column( ft.Column(
expand=True, expand=True,
alignment=ft.MainAxisAlignment.CENTER, alignment=ft.MainAxisAlignment.START,
horizontal_alignment=ft.CrossAxisAlignment.CENTER, horizontal_alignment=ft.CrossAxisAlignment.CENTER,
controls=[ controls=[
self.input_right_1, self.input_right_1,
@@ -226,7 +388,14 @@ class Button_binary_calculator(ft.CupertinoButton):
padding=10, padding=10,
border_radius=5, border_radius=5,
), ),
ft.CupertinoButton("=", on_click=self.calculate_addition) ft.CupertinoButton("=", on_click=self.calculate_addition),
ft.Container(
expand=True,
content=self.steps_right,
bgcolor="#1A0A2A",
padding=10,
border_radius=5,
)
] ]
) )
] ]

View File

@@ -1,12 +1,16 @@
from designer import right_column from designer import right_column
import flet as ft 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_calculeator(ft.CupertinoButton): class Button_calculeator(ft.CupertinoButton):
def __init__(self, text: str = "Десятичный калькулятор"): def __init__(self, text: str = "Десятичный калькулятор"):
self.result_left = ft.Text(value="0", size=30, width=300) self.result_left = ft.Text(value="0", size=30, width=300)
self.result_right = ft.Text(value="0", size=30, width=300) self.result_right = ft.Text(value="0", size=30, width=300)
#self.binary_left = ft.Text(value="(0₂)", size=14, color="#B0B0B0", width=300)
#self.binary_right = ft.Text(value="(0₂)", size=14, color="#B0B0B0", width=300)
# Поля ввода для вычитания # Поля ввода для вычитания
self.input_left_1 = None self.input_left_1 = None
@@ -16,6 +20,13 @@ class Button_calculeator(ft.CupertinoButton):
self.input_right_1 = None self.input_right_1 = None
self.input_right_2 = None self.input_right_2 = None
# Контейнеры для пошагового решения
self.steps_left = ft.Column(scroll=ft.ScrollMode.AUTO, spacing=5, expand=True)
self.steps_right = ft.Column(scroll=ft.ScrollMode.AUTO, spacing=5, expand=True)
# Солвер для десятичной системы
self.solver = StepByStepSolver(base=10)
super().__init__( super().__init__(
bgcolor="#00000000", bgcolor="#00000000",
disabled_bgcolor="#3A1E51", disabled_bgcolor="#3A1E51",
@@ -38,15 +49,14 @@ class Button_calculeator(ft.CupertinoButton):
result = num1 - num2 result = num1 - num2
self.result_left.value = str(result) self.result_left.value = str(result)
#self.binary_left.value = f"({self.to_binary(result)}₂)"
self.result_left.update() self.result_left.update()
#self.binary_left.update()
# Получаем пошаговое решение
self.show_steps_left(str(num1), str(num2), Operation.SUBTRACTION)
except ValueError: except ValueError:
self.result_left.value = "Ошибка" self.result_left.value = "Ошибка"
#self.binary_left.value = "Неверный формат"
self.result_left.update() self.result_left.update()
#self.binary_left.update()
def calculate_addition(self, e): def calculate_addition(self, e):
try: try:
@@ -55,15 +65,124 @@ class Button_calculeator(ft.CupertinoButton):
result = num1 + num2 result = num1 + num2
self.result_right.value = str(result) self.result_right.value = str(result)
#self.binary_right.value = f"({self.to_binary(result)}₂)"
self.result_right.update() self.result_right.update()
#self.binary_right.update()
# Получаем пошаговое решение
self.show_steps_right(str(num1), str(num2), Operation.ADDITION)
except ValueError: except ValueError:
self.result_right.value = "Ошибка" self.result_right.value = "Ошибка"
#self.binary_right.value = "Неверный формат"
self.result_right.update() self.result_right.update()
#self.binary_right.update()
def show_steps_left(self, num1: str, num2: str, operation: Operation):
"""Отображает пошаговое решение для левой колонки (вычитание)"""
try:
steps = self.solver.solve(num1, num2, operation)
self.steps_left.controls.clear()
self.steps_left.controls.append(
ft.Text("📝 Ход решения:", size=14, weight=ft.FontWeight.BOLD, color="#FFD700")
)
for i, step in enumerate(steps, 1):
step_content = []
step_content.append(
ft.Text(f"Шаг {i}: {step.title}",
size=12, weight=ft.FontWeight.BOLD, color="#00FFFF")
)
step_content.append(
ft.Text(step.description, size=10, color="#E0E0E0")
)
if step.visual:
step_content.append(
ft.Text(step.visual,
size=10,
font_family="Courier New",
color="#90EE90",
selectable=True)
)
if step.result:
step_content.append(
ft.Text(f"{step.result}",
size=11,
weight=ft.FontWeight.BOLD,
color="#00FF00")
)
self.steps_left.controls.append(
ft.Container(
content=ft.Column(step_content, spacing=3),
bgcolor="#2A1A3A",
padding=8,
border_radius=5,
border=ft.border.all(1, "#4A3A5A")
)
)
self.steps_left.update()
except Exception as ex:
self.steps_left.controls.clear()
self.steps_left.controls.append(
ft.Text(f"Ошибка: {str(ex)}", color="red", size=10)
)
self.steps_left.update()
def show_steps_right(self, num1: str, num2: str, operation: Operation):
"""Отображает пошаговое решение для правой колонки (сложение)"""
try:
steps = self.solver.solve(num1, num2, operation)
self.steps_right.controls.clear()
self.steps_right.controls.append(
ft.Text("📝 Ход решения:", size=14, weight=ft.FontWeight.BOLD, color="#FFD700")
)
for i, step in enumerate(steps, 1):
step_content = []
step_content.append(
ft.Text(f"Шаг {i}: {step.title}",
size=12, weight=ft.FontWeight.BOLD, color="#00FFFF")
)
step_content.append(
ft.Text(step.description, size=10, color="#E0E0E0")
)
if step.visual:
step_content.append(
ft.Text(step.visual,
size=10,
font_family="Courier New",
color="#90EE90",
selectable=True)
)
if step.result:
step_content.append(
ft.Text(f"{step.result}",
size=11,
weight=ft.FontWeight.BOLD,
color="#00FF00")
)
self.steps_right.controls.append(
ft.Container(
content=ft.Column(step_content, spacing=3),
bgcolor="#2A1A3A",
padding=8,
border_radius=5,
border=ft.border.all(1, "#4A3A5A")
)
)
self.steps_right.update()
except Exception as ex:
self.steps_right.controls.clear()
self.steps_right.controls.append(
ft.Text(f"Ошибка: {str(ex)}", color="red", size=10)
)
self.steps_right.update()
def test_data(self, e): def test_data(self, e):
# Создаем поля ввода с валидацией # Создаем поля ввода с валидацией
@@ -123,7 +242,7 @@ class Button_calculeator(ft.CupertinoButton):
controls=[ controls=[
ft.Column( ft.Column(
expand=True, expand=True,
alignment=ft.MainAxisAlignment.CENTER, alignment=ft.MainAxisAlignment.START,
horizontal_alignment=ft.CrossAxisAlignment.CENTER, horizontal_alignment=ft.CrossAxisAlignment.CENTER,
controls=[ controls=[
self.input_left_1, self.input_left_1,
@@ -132,18 +251,24 @@ class Button_calculeator(ft.CupertinoButton):
ft.Container( ft.Container(
content=ft.Column([ content=ft.Column([
self.result_left, self.result_left,
#self.binary_left
], horizontal_alignment=ft.CrossAxisAlignment.CENTER), ], horizontal_alignment=ft.CrossAxisAlignment.CENTER),
bgcolor="#3A1E51", bgcolor="#3A1E51",
padding=10, padding=10,
border_radius=5, border_radius=5,
), ),
ft.CupertinoButton("=", on_click=self.calculate_subtraction) ft.CupertinoButton("=", on_click=self.calculate_subtraction),
ft.Container(
expand=True,
content=self.steps_left,
bgcolor="#1A0A2A",
padding=10,
border_radius=5,
)
] ]
), ),
ft.Column( ft.Column(
expand=True, expand=True,
alignment=ft.MainAxisAlignment.CENTER, alignment=ft.MainAxisAlignment.START,
horizontal_alignment=ft.CrossAxisAlignment.CENTER, horizontal_alignment=ft.CrossAxisAlignment.CENTER,
controls=[ controls=[
self.input_right_1, self.input_right_1,
@@ -152,13 +277,19 @@ class Button_calculeator(ft.CupertinoButton):
ft.Container( ft.Container(
content=ft.Column([ content=ft.Column([
self.result_right, self.result_right,
#self.binary_right
], horizontal_alignment=ft.CrossAxisAlignment.CENTER), ], horizontal_alignment=ft.CrossAxisAlignment.CENTER),
bgcolor="#3A1E51", bgcolor="#3A1E51",
padding=10, padding=10,
border_radius=5, border_radius=5,
), ),
ft.CupertinoButton("=", on_click=self.calculate_addition) ft.CupertinoButton("=", on_click=self.calculate_addition),
ft.Container(
expand=True,
content=self.steps_right,
bgcolor="#1A0A2A",
padding=10,
border_radius=5,
)
] ]
) )
] ]

View File

@@ -1,5 +1,11 @@
from designer import right_column from designer import right_column
import flet as ft 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_octogon_calculator(ft.CupertinoButton): class Button_octogon_calculator(ft.CupertinoButton):
def __init__(self, text: str = "Восьмеричный калькулятор"): def __init__(self, text: str = "Восьмеричный калькулятор"):
@@ -16,6 +22,13 @@ class Button_octogon_calculator(ft.CupertinoButton):
self.input_right_1 = None self.input_right_1 = None
self.input_right_2 = None self.input_right_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.solver = StepByStepSolver(base=8)
super().__init__( super().__init__(
bgcolor="#00000000", bgcolor="#00000000",
disabled_bgcolor="#3A1E51", disabled_bgcolor="#3A1E51",
@@ -74,6 +87,12 @@ class Button_octogon_calculator(ft.CupertinoButton):
self.decimal_left.value = f"({result}₁₀)" self.decimal_left.value = f"({result}₁₀)"
self.result_left.update() self.result_left.update()
self.decimal_left.update() self.decimal_left.update()
# Получаем пошаговое решение (убираем знак минус для солвера)
clean_val1 = val1.lstrip('-') if val1.startswith('-') and num1 < 0 else val1
clean_val2 = val2.lstrip('-') if val2.startswith('-') and num2 < 0 else val2
self.show_steps_left(clean_val1 if num1 >= 0 else val1, clean_val2 if num2 >= 0 else val2, Operation.SUBTRACTION)
except ValueError as ex: except ValueError as ex:
self.result_left.value = "Ошибка" self.result_left.value = "Ошибка"
self.decimal_left.value = str(ex) self.decimal_left.value = str(ex)
@@ -115,12 +134,86 @@ class Button_octogon_calculator(ft.CupertinoButton):
self.decimal_right.value = f"({result}₁₀)" self.decimal_right.value = f"({result}₁₀)"
self.result_right.update() self.result_right.update()
self.decimal_right.update() self.decimal_right.update()
# Получаем пошаговое решение
clean_val1 = val1.lstrip('-') if val1.startswith('-') and num1 < 0 else val1
clean_val2 = val2.lstrip('-') if val2.startswith('-') and num2 < 0 else val2
self.show_steps_right(clean_val1 if num1 >= 0 else val1, clean_val2 if num2 >= 0 else val2, Operation.ADDITION)
except ValueError as ex: except ValueError as ex:
self.result_right.value = "Ошибка" self.result_right.value = "Ошибка"
self.decimal_right.value = str(ex) self.decimal_right.value = str(ex)
self.result_right.update() self.result_right.update()
self.decimal_right.update() self.decimal_right.update()
def show_steps_left(self, num1: str, num2: str, operation: Operation):
"""Отображает пошаговое решение для левой колонки"""
try:
steps = self.solver.solve(num1, num2, operation)
self.steps_left.controls.clear()
self.steps_left.controls.append(
ft.Text("📝 Ход решения:", size=14, weight=ft.FontWeight.BOLD, color="#FFD700")
)
for i, step in enumerate(steps, 1):
step_content = []
step_content.append(ft.Text(f"Шаг {i}: {step.title}", size=12, weight=ft.FontWeight.BOLD, color="#00FFFF"))
step_content.append(ft.Text(step.description, size=10, color="#E0E0E0"))
if step.visual:
step_content.append(ft.Text(step.visual, size=10, font_family="Courier New", color="#90EE90", selectable=True))
if step.result:
step_content.append(ft.Text(f"{step.result}", size=11, weight=ft.FontWeight.BOLD, color="#00FF00"))
self.steps_left.controls.append(
ft.Container(
content=ft.Column(step_content, spacing=3),
bgcolor="#2A1A3A",
padding=8,
border_radius=5,
border=ft.border.all(1, "#4A3A5A")
)
)
self.steps_left.update()
except Exception as ex:
self.steps_left.controls.clear()
self.steps_left.controls.append(ft.Text(f"Ошибка: {str(ex)}", color="red", size=10))
self.steps_left.update()
def show_steps_right(self, num1: str, num2: str, operation: Operation):
"""Отображает пошаговое решение для правой колонки"""
try:
steps = self.solver.solve(num1, num2, operation)
self.steps_right.controls.clear()
self.steps_right.controls.append(
ft.Text("📝 Ход решения:", size=14, weight=ft.FontWeight.BOLD, color="#FFD700")
)
for i, step in enumerate(steps, 1):
step_content = []
step_content.append(ft.Text(f"Шаг {i}: {step.title}", size=12, weight=ft.FontWeight.BOLD, color="#00FFFF"))
step_content.append(ft.Text(step.description, size=10, color="#E0E0E0"))
if step.visual:
step_content.append(ft.Text(step.visual, size=10, font_family="Courier New", color="#90EE90", selectable=True))
if step.result:
step_content.append(ft.Text(f"{step.result}", size=11, weight=ft.FontWeight.BOLD, color="#00FF00"))
self.steps_right.controls.append(
ft.Container(
content=ft.Column(step_content, spacing=3),
bgcolor="#2A1A3A",
padding=8,
border_radius=5,
border=ft.border.all(1, "#4A3A5A")
)
)
self.steps_right.update()
except Exception as ex:
self.steps_right.controls.clear()
self.steps_right.controls.append(ft.Text(f"Ошибка: {str(ex)}", color="red", size=10))
self.steps_right.update()
def test_data(self, e): def test_data(self, e):
# Создаем поля ввода с валидацией для двоичных чисел # Создаем поля ввода с валидацией для двоичных чисел
# Поля ввода для восьмеричной системы — допускаются цифры 0..7 и опциональный знак '-' # Поля ввода для восьмеричной системы — допускаются цифры 0..7 и опциональный знак '-'
@@ -177,7 +270,7 @@ class Button_octogon_calculator(ft.CupertinoButton):
controls=[ controls=[
ft.Column( ft.Column(
expand=True, expand=True,
alignment=ft.MainAxisAlignment.CENTER, alignment=ft.MainAxisAlignment.START,
horizontal_alignment=ft.CrossAxisAlignment.CENTER, horizontal_alignment=ft.CrossAxisAlignment.CENTER,
controls=[ controls=[
self.input_left_1, self.input_left_1,
@@ -192,12 +285,19 @@ class Button_octogon_calculator(ft.CupertinoButton):
padding=10, padding=10,
border_radius=5, border_radius=5,
), ),
ft.CupertinoButton("=", on_click=self.calculate_subtraction) ft.CupertinoButton("=", on_click=self.calculate_subtraction),
ft.Container(
expand=True,
content=self.steps_left,
bgcolor="#1A0A2A",
padding=10,
border_radius=5,
)
] ]
), ),
ft.Column( ft.Column(
expand=True, expand=True,
alignment=ft.MainAxisAlignment.CENTER, alignment=ft.MainAxisAlignment.START,
horizontal_alignment=ft.CrossAxisAlignment.CENTER, horizontal_alignment=ft.CrossAxisAlignment.CENTER,
controls=[ controls=[
self.input_right_1, self.input_right_1,
@@ -212,7 +312,14 @@ class Button_octogon_calculator(ft.CupertinoButton):
padding=10, padding=10,
border_radius=5, border_radius=5,
), ),
ft.CupertinoButton("=", on_click=self.calculate_addition) ft.CupertinoButton("=", on_click=self.calculate_addition),
ft.Container(
expand=True,
content=self.steps_right,
bgcolor="#1A0A2A",
padding=10,
border_radius=5,
)
] ]
) )
] ]

View File

@@ -0,0 +1,421 @@
from designer import right_column
import flet as ft
import sys
import os
# Добавляем путь к модулю step_by_step_solver
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from step_by_step_solver import StepByStepSolver, Operation
class Button_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.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.input_left_1 = None
self.input_left_2 = None
# Поля ввода для сложения
self.input_right_1 = None
self.input_right_2 = None
# Контейнеры для пошагового решения
self.steps_left = ft.Column(scroll=ft.ScrollMode.AUTO, spacing=5)
self.steps_right = 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):
"""Отображает пошаговое решение для левой колонки (вычитание)"""
try:
# Получаем шаги решения
steps = self.solver.solve(num1, num2, operation)
# Очищаем предыдущие шаги
self.steps_left.controls.clear()
# Добавляем заголовок
self.steps_left.controls.append(
ft.Text("📝 Ход решения:", size=14, weight=ft.FontWeight.BOLD, color="#FFD700")
)
# Добавляем каждый шаг
for i, step in enumerate(steps, 1):
step_content = []
# Название шага
step_content.append(
ft.Text(f"Шаг {i}: {step.title}",
size=12, weight=ft.FontWeight.BOLD, color="#00FFFF")
)
# Описание
step_content.append(
ft.Text(step.description, size=10, color="#E0E0E0")
)
# Визуализация (если есть)
if step.visual:
step_content.append(
ft.Text(step.visual,
size=10,
font_family="Courier New",
color="#90EE90",
selectable=True)
)
# Результат (если есть)
if step.result:
step_content.append(
ft.Text(f"{step.result}",
size=11,
weight=ft.FontWeight.BOLD,
color="#00FF00")
)
# Добавляем контейнер с шагом
self.steps_left.controls.append(
ft.Container(
content=ft.Column(step_content, spacing=3),
bgcolor="#2A1A3A",
padding=8,
border_radius=5,
border=ft.border.all(1, "#4A3A5A")
)
)
self.steps_left.update()
except Exception as ex:
self.steps_left.controls.clear()
self.steps_left.controls.append(
ft.Text(f"Ошибка: {str(ex)}", color="red", size=10)
)
self.steps_left.update()
def show_steps_right(self, num1: str, num2: str, operation: Operation):
"""Отображает пошаговое решение для правой колонки (сложение)"""
try:
# Получаем шаги решения
steps = self.solver.solve(num1, num2, operation)
# Очищаем предыдущие шаги
self.steps_right.controls.clear()
# Добавляем заголовок
self.steps_right.controls.append(
ft.Text("📝 Ход решения:", size=14, weight=ft.FontWeight.BOLD, color="#FFD700")
)
# Добавляем каждый шаг
for i, step in enumerate(steps, 1):
step_content = []
# Название шага
step_content.append(
ft.Text(f"Шаг {i}: {step.title}",
size=12, weight=ft.FontWeight.BOLD, color="#00FFFF")
)
# Описание
step_content.append(
ft.Text(step.description, size=10, color="#E0E0E0")
)
# Визуализация (если есть)
if step.visual:
step_content.append(
ft.Text(step.visual,
size=10,
font_family="Courier New",
color="#90EE90",
selectable=True)
)
# Результат (если есть)
if step.result:
step_content.append(
ft.Text(f"{step.result}",
size=11,
weight=ft.FontWeight.BOLD,
color="#00FF00")
)
# Добавляем контейнер с шагом
self.steps_right.controls.append(
ft.Container(
content=ft.Column(step_content, spacing=3),
bgcolor="#2A1A3A",
padding=8,
border_radius=5,
border=ft.border.all(1, "#4A3A5A")
)
)
self.steps_right.update()
except Exception as ex:
self.steps_right.controls.clear()
self.steps_right.controls.append(
ft.Text(f"Ошибка: {str(ex)}", color="red", size=10)
)
self.steps_right.update()
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 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₁₀)"
)
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,
)
]
)
]
)
],
)
)]
e.page.update()

View File

@@ -2,7 +2,7 @@ from designer import right_column
import flet as ft import flet as ft
class Button_binary_data(ft.CupertinoButton): class Button_binary_data(ft.CupertinoButton):
def __init__(self, text: str = "Двоичная система счисления"): def __init__(self, text: str = "50-ричная система счисления"):
super().__init__( super().__init__(
bgcolor="#00000000", bgcolor="#00000000",
disabled_bgcolor="#3A1E51", disabled_bgcolor="#3A1E51",
@@ -11,136 +11,134 @@ class Button_binary_data(ft.CupertinoButton):
on_click=self.test_data on_click=self.test_data
) )
def test_data(e, self): def test_data(self, e):
md1=""" md1="""
**N-мерные системы счисления** # 50-ричная система счисления
**Расширение позиционных систем в многомерное пространство** ## Основные понятия
Основная концепция: **50-ричная система счисления** — позиционная система счисления с основанием 50.
Вместо линейной цепочки разрядов используется n-мерная решётка, где каждая ячейка имеет свои координаты и вес.
**Математическое представление:** ### Алфавит системы:
- **Цифры 0-9**: значения 0-9 (10 символов)
- **Заглавные A-Z**: значения 10-35 (26 символов)
- **Строчные a-n**: значения 36-49 (14 символов)
- **Итого**: 50 уникальных символов
Для 2D системы счисления: ### Примеры перевода:
N = ΣΣ a_ij × b₁ⁱ × b₂ʲ - `10₅₀ = 50₁₀` (одна пятидесятка)
- `A₅₀ = 10₁₀` (символ A = десять)
- `Z₅₀ = 35₁₀` (последняя заглавная буква)
- `n₅₀ = 49₁₀` (последний символ алфавита)
Для 3D системы счисления: ### Математическое представление:
N = ΣΣΣ a_ijk × b₁ⁱ × b₂ʲ × b₃ᵏ
Общая формула для n-мерной системы: Общая формула перевода из 50-ричной в десятичную:
N = Σ...Σ a_i₁...iₙ × b₁ⁱ¹ × b₂ⁱ² × ... × bₙⁱⁿ
**N₁₀ = aₙ×50ⁿ + aₙ₋₁×50ⁿ⁻¹ + ... + a₁×50¹ + a₀×50⁰**
где: где:
- a_i₁...iₙ - цифра в позиции (i₁,...,iₙ) - N₁₀ — число в десятичной системе
- b₁,...,bₙ - основания по каждому измерению - aᵢ — цифра на позиции i (значение 0-49)
- i₁,...,iₙ - координаты в n-мерном пространстве - n — количество разрядов минус 1
**Пример 2D системы:** ### Пример вычисления:
Основания: b₁ = 10 (по горизонтали), b₂ = 8 (по вертикали) Число `Ab5₅₀`:
- A = 10, b = 37, 5 = 5
- Ab5₅₀ = 10×50² + 37×50¹ + 5×50⁰
- Ab5₅₀ = 10×2500 + 37×50 + 5×1
- Ab5₅₀ = 25000 + 1850 + 5
- **Ab5₅₀ = 26855₁₀**
Числовая матрица: ### Применение:
[3 5]
[2 7]
Расчёт: • Компактное представление больших чисел
N = 3×10¹×8¹ + 5×10¹×8⁰ + 2×10⁰×8¹ + 7×10⁰×8⁰ • Кодирование данных с расширенным алфавитом
N = 3×80 + 5×10 + 2×8 + 7×1 • Учебные задачи по системам счисления
N = 240 + 50 + 16 + 7 = 313 • Альтернативные схемы нумерации
**Преимущества n-мерных систем:**
• Компактное представление многомерных данных
• Естественное отображение для изображений, матриц, тензоров
• Эффективные алгоритмы для многомерных преобразований Фурье
• Прямое соответствие структурам данных в машинном обучении
• Упрощённая работа с пространственными данными
**Применения:**
• Обработка изображений (2D системы)
• Научные вычисления с тензорами (3D+ системы)
• Сжатие многомерных данных
• Нейронные сети и глубокое обучение
• Квантовые вычисления (многомерные представления)
**Особенности:**
Каждое измерение может иметь своё основание, что позволяет оптимально кодировать различные типы данных в многомерных структурах.
""" """
md2=""" md2="""
**Сборка 60-мерной системы счисления** ## Арифметические операции в 50-ричной системе
**1. Определение структуры:** ### Сложение
- 60 независимых измерений (осей)
- Каждое измерение имеет своё основание b₁, b₂, ..., b₆₀
- Пример оснований: [2, 3, 5, 7, 11, ..., 293] (простые числа)
**2. Математическая модель:** **Правило**: Складываем разряды справа налево. Если сумма ≥ 50, переносим в старший разряд.
N = ΣΣ...Σ a_i₁i₂...i₆₀ × b₁ⁱ¹ × b₂ⁱ² × ... × b₆₀ⁱ⁶⁰
где: **Пример**: `A₅₀ + Z₅₀`
- a_i₁i₂...i₆₀ - цифра в 60-мерной позиции - A₅₀ = 10₁₀
- i₁,...,i₆₀ - координаты от 0 до k (зависит от основания) - Z₅₀ = 35₁₀
- b₁,...,b₆₀ - основания каждого измерения - Сумма: 10 + 35 = 45₁₀ = j₅₀
**3. Практическая реализация:** **Пример с переносом**: `n₅₀ + 5₅₀`
- n₅₀ = 49₁₀
- 5₅₀ = 5₁₀
- Сумма: 49 + 5 = 54₁₀ = 1×50 + 4 = **14₅₀**
**Шаг 1: Выбор оснований** ### Вычитание
b₁ = 2 (измерение 1)
b₂ = 3 (измерение 2)
b₃ = 5 (измерение 3)
...
b₆₀ = 293 (измерение 60)
**Шаг 2: Представление числа** **Правило**: Вычитаем разряды справа налево. Если не хватает, занимаем из старшего разряда (50 единиц).
Каждое число - это 60-мерный массив:
оордината_1][координата_2]...[координата_60]
**Шаг 3: Пример вычисления** **Пример**: `Z₅₀ - A₅₀`
Для упрощения возьмём маленькие координаты: - Z₅₀ = 35₁₀
- A₅₀ = 10₁₀
- Разность: 35 - 10 = 25₁₀ = P₅₀
a₁ = 1, a₂ = 0, a₃ = 2, ..., a₆₀ = 1 ### Карта символов (кратко)
09 → 09, AZ → 1035, an → 3649
N = 1×2¹ + 0×3¹ + 2×5¹ + ... + 1×293¹ ### Алгоритм перевода обратно в десятичную:
**4. Алгоритм перевода в десятичную:** ```python
def from_base50(число_50):
digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn"
результат = 0
``` for i, символ in enumerate(reversed(число_50)):
десятичное_число = 0 значение = digits.index(символ)
для каждого измерения i от 1 до 60: результат += значение × (50 ** i)
вес = произведение оснований всех предыдущих измерений
десятичное_число += цифра[i] × вес return результат
``` ```
**5. Особенности 60-мерной системы:** ### Преимущества 50-ричной системы:
- **Гиперпространство данных**: Каждая точка в 60-мерном пространстве - уникальное число ✓ Больше символов → компактнее запись
- **Гибкость**: Можно использовать разные основания для разных типов данных ✓ Легко расширяется до других оснований
- **Сжатие**: Эффективное кодирование сложных структур ✓ Учит работать с произвольными системами счисления
- **Вычисления**: Сложение и умножение происходят независимо по каждому измерению ✓ Развивает абстрактное математическое мышление
"""
**6. Области применения:** md3="""
## Практические примеры
- Квантовые вычисления (60 кубитов) ### Пример 1: Сложение `1A₅₀ + B₅₀`
- Глубокое обучение (нейросети с 60 слоями)
- Криптография (сверхбольшие пространства ключей)
- Научное моделирование (многопараметрические системы)
**7. Ограничения:** **Шаг 1**: Переводим в десятичную
- 1A₅₀ = 1×50 + 10 = 60₁₀
- B₅₀ = 11₁₀
- Визуализация невозможна (человек не может представить 60 измерений) **Шаг 2**: Складываем
- Вычисления требуют суперкомпьютеров - 60 + 11 = 71₁₀
- Сложность отладки и верификации
**Простой пример для 3 измерений вместо 60:** **Шаг 3**: Переводим обратно
Основания: [2, 3, 5] - 71 ÷ 50 = 1 (остаток 21)
Число: [1, 0, 2] - 21 → L (в алфавите)
N = 1×(3×5) + 0×(5) + 2×1 = 15 + 0 + 2 = 17 - **Ответ: 1L₅₀**
В 60-мерном случае принцип тот же, но измерений в 20 раз больше. ### Пример 2: Вычитание `Z₅₀ - 5₅₀`
**Решение**:
- Z₅₀ = 35₁₀
- 5₅₀ = 5₁₀
- 35 - 5 = 30₁₀
- 30 → U (в алфавите)
- **Ответ: U₅₀**
---
**Заключение**: 50-ричная система — мощный инструмент для понимания принципов позиционных систем счисления с любым основанием.
""" """
right_column.controls=[ ft.Container( right_column.controls=[ ft.Container(
@@ -169,13 +167,13 @@ N = 1×(3×5) + 0×(5) + 2×1 = 15 + 0 + 2 = 17
), ),
ft.Text("Перевод обратно в десятичную систему:", size=16, color="white"), ft.Text("Перевод обратно в десятичную систему:", size=16, color="white"),
ft.Container( ##ft.Container(
bgcolor="#000000", ## bgcolor="#000000",
content=ft.Image(src="./Система счисления 2.png", expand=True), ## content=ft.Image(src="./Система счисления 2.png", expand=True),
border_radius=10, ## border_radius=10,
width=580, ## width=580,
height=300, ## height=300,
), ##),
ft.Text("Работа со знаком:", size=16, color="white"), ft.Text("Работа со знаком:", size=16, color="white"),
], ],

View File

@@ -1,8 +1,14 @@
from designer import right_column from designer import right_column
import flet as ft 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_sedecim_calculator(ft.CupertinoButton): class Button_sedecim_calculator(ft.CupertinoButton):
def __init__(self, text: str = "Двоичный калькулятор"): def __init__(self, text: str = "Шеснадцатиричный калькулятор"):
self.result_left = ft.Text(value="0", size=30, width=300) self.result_left = ft.Text(value="0", size=30, width=300)
self.result_right = ft.Text(value="0", size=30, width=300) self.result_right = ft.Text(value="0", size=30, width=300)
self.decimal_left = ft.Text(value="(0₁₀)", size=14, color="#B0B0B0", width=300) self.decimal_left = ft.Text(value="(0₁₀)", size=14, color="#B0B0B0", width=300)
@@ -16,6 +22,13 @@ class Button_sedecim_calculator(ft.CupertinoButton):
self.input_right_1 = None self.input_right_1 = None
self.input_right_2 = None self.input_right_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.solver = StepByStepSolver(base=16)
# Количество бит для представления (по умолчанию 8) # Количество бит для представления (по умолчанию 8)
self.bit_width = 16 self.bit_width = 16
@@ -27,149 +40,240 @@ class Button_sedecim_calculator(ft.CupertinoButton):
on_click=self.test_data on_click=self.test_data
) )
def to_twos_complement(self, num, bit_width): def hex_to_decimal(self,hex_str):
"""Преобразует число в дополнительный код""" """
if num >= 0: Преобразование шестнадцатеричного числа в десятичное
return format(num, f'0{bit_width}b') Поддерживает отрицательные числа и дроби
"""
if not hex_str:
return 0
# Обработка знака
sign = -1 if hex_str[0] == '-' else 1
if hex_str[0] in ['-', '+']:
hex_str = hex_str[1:]
# Разделение на целую и дробную части
if '.' in hex_str:
integer_part, fractional_part = hex_str.split('.')
else: else:
# Для отрицательных чисел используем дополнительный код integer_part, fractional_part = hex_str, ""
return format((1 << bit_width) + num, f'0{bit_width}b')
def from_twos_complement(self, binary_str): # Преобразование целой части
"""Преобразует из дополнительного кода в десятичное число""" decimal_value = int(integer_part, 16) if integer_part else 0
bit_width = len(binary_str)
value = int(binary_str, 2)
# Проверяем знаковый бит (старший бит) # Преобразование дробной части
if binary_str[0] == '1': if fractional_part:
# Отрицательное число for i, digit in enumerate(fractional_part, 1):
value = value - (1 << bit_width) decimal_value += int(digit, 16) / (16 ** i)
return value return decimal_value * sign
def validate_binary(self, value): def decimal_to_hex(self,decimal_num, precision=6):
"""Проверяет, является ли строка корректным двоичным числом""" """
if not value: Перевод десятичного числа в шестнадцатеричное
return True """
# Только 0 и 1 if decimal_num == 0:
return all(c in "01" for c in value) return "0"
# Обработка знака
sign = "-" if decimal_num < 0 else ""
decimal_num = abs(decimal_num)
# Разделение на целую и дробную части
integer_part = int(decimal_num)
fractional_part = decimal_num - integer_part
# Перевод целой части
hex_integer = hex(integer_part)[2:].upper()
# Перевод дробной части
hex_fractional = ""
if fractional_part > 0:
hex_fractional = "."
temp = fractional_part
for _ in range(precision):
if temp == 0:
break
temp *= 16
digit = int(temp)
hex_fractional += hex(digit)[2:].upper()
temp -= digit
return sign + hex_integer + hex_fractional
# В классе калькулятора обновите функции расчета:
def calculate_addition(self, e):
try:
# Получаем и преобразуем числа
num1 = self.hex_to_decimal(self.input_right_1.value.upper())
num2 = self.hex_to_decimal(self.input_right_2.value.upper())
# Вычисляем сумму
result_decimal = num1 + num2
# Преобразуем обратно в hex
result_hex = self.decimal_to_hex(result_decimal)
# Обновляем результаты
self.result_right.value = f"HEX: {result_hex}"
self.decimal_right.value = f"DEC: {result_decimal}"
# Получаем пошаговое решение (только для целых чисел)
if '.' not in self.input_right_1.value and '.' not in self.input_right_2.value:
hex_val1 = self.input_right_1.value.upper().lstrip('-+') if self.input_right_1.value else "0"
hex_val2 = self.input_right_2.value.upper().lstrip('-+') if self.input_right_2.value else "0"
self.show_steps_right(hex_val1, hex_val2, Operation.ADDITION)
else:
self.steps_right.controls.clear()
self.steps_right.controls.append(
ft.Text("Пошаговое решение доступно только для целых чисел", color="#FFD700", size=12)
)
self.steps_right.update()
except Exception as ex:
self.result_right.value = f"Ошибка: {str(ex)}"
self.decimal_right.value = "DEC: ошибка"
self.page.update()
def calculate_subtraction(self, e): def calculate_subtraction(self, e):
try: try:
bin1 = self.input_left_1.value or "0" # Получаем и преобразуем числа
bin2 = self.input_left_2.value or "0" num1 = self.hex_to_decimal(self.input_left_1.value.upper())
num2 = self.hex_to_decimal(self.input_left_2.value.upper())
# Проверка корректности двоичных чисел # Вычисляем разность
if not self.validate_binary(bin1) or not self.validate_binary(bin2): result_decimal = num1 - num2
self.result_left.value = "Ошибка: неверный формат"
self.decimal_left.value = ""
self.result_left.update()
self.decimal_left.update()
return
# Преобразуем двоичные числа в десятичные # Преобразуем обратно в hex
result_hex = self.decimal_to_hex(result_decimal)
if len(bin1) > 0 and bin1[0] == '1' and len(bin1) >= 8: # Обновляем результаты
num1 = self.from_twos_complement(bin1) self.result_left.value = f"HEX: {result_hex}"
self.decimal_left.value = f"DEC: {result_decimal}"
# Получаем пошаговое решение (только для целых чисел)
if '.' not in self.input_left_1.value and '.' not in self.input_left_2.value:
hex_val1 = self.input_left_1.value.upper().lstrip('-+') if self.input_left_1.value else "0"
hex_val2 = self.input_left_2.value.upper().lstrip('-+') if self.input_left_2.value else "0"
self.show_steps_left(hex_val1, hex_val2, Operation.SUBTRACTION)
else: else:
num1 = int(bin1, 2) if bin1 else 0 self.steps_left.controls.clear()
self.steps_left.controls.append(
ft.Text("Пошаговое решение доступно только для целых чисел", color="#FFD700", size=12)
)
self.steps_left.update()
if len(bin2) > 0 and bin2[0] == '1' and len(bin2) >= 8: except Exception as ex:
num2 = self.from_twos_complement(bin2) self.result_left.value = f"Ошибка: {str(ex)}"
else: self.decimal_left.value = "DEC: ошибка"
num2 = int(bin2, 2) if bin2 else 0
# Вычисляем результат self.page.update()
result = num1 - num2
# Преобразуем обратно в двоичный формат (дополнительный код) def show_steps_left(self, num1: str, num2: str, operation: Operation):
binary_result = self.to_twos_complement(result, self.bit_width) """Отображает пошаговое решение для левой колонки"""
self.result_left.value = binary_result
self.decimal_left.value = f"({result}₁₀)"
self.result_left.update()
self.decimal_left.update()
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: try:
bin1 = self.input_right_1.value or "0" steps = self.solver.solve(num1, num2, operation)
bin2 = self.input_right_2.value or "0" self.steps_left.controls.clear()
# Проверка корректности двоичных чисел self.steps_left.controls.append(
if not self.validate_binary(bin1) or not self.validate_binary(bin2): ft.Text("📝 Ход решения:", size=14, weight=ft.FontWeight.BOLD, color="#FFD700")
self.result_right.value = "Ошибка: неверный формат" )
self.decimal_right.value = ""
self.result_right.update()
self.decimal_right.update()
return
# Преобразуем двоичные числа в десятичные for i, step in enumerate(steps, 1):
# Если введено в дополнительном коде - интерпретируем как дополнительный код step_content = []
if len(bin1) > 0 and bin1[0] == '1' and len(bin1) >= 8: step_content.append(ft.Text(f"Шаг {i}: {step.title}", size=12, weight=ft.FontWeight.BOLD, color="#00FFFF"))
num1 = self.from_twos_complement(bin1) step_content.append(ft.Text(step.description, size=10, color="#E0E0E0"))
else: if step.visual:
num1 = int(bin1, 2) if bin1 else 0 step_content.append(ft.Text(step.visual, size=10, font_family="Courier New", color="#90EE90", selectable=True))
if step.result:
step_content.append(ft.Text(f"{step.result}", size=11, weight=ft.FontWeight.BOLD, color="#00FF00"))
if len(bin2) > 0 and bin2[0] == '1' and len(bin2) >= 8: self.steps_left.controls.append(
num2 = self.from_twos_complement(bin2) ft.Container(
else: content=ft.Column(step_content, spacing=3),
num2 = int(bin2, 2) if bin2 else 0 bgcolor="#2A1A3A",
padding=8,
border_radius=5,
border=ft.border.all(1, "#4A3A5A")
)
)
self.steps_left.update()
except Exception as ex:
self.steps_left.controls.clear()
self.steps_left.controls.append(ft.Text(f"Ошибка: {str(ex)}", color="red", size=10))
self.steps_left.update()
# Вычисляем результат def show_steps_right(self, num1: str, num2: str, operation: Operation):
result = num1 + num2 """Отображает пошаговое решение для правой колонки"""
try:
steps = self.solver.solve(num1, num2, operation)
self.steps_right.controls.clear()
# Преобразуем обратно в двоичный формат (дополнительный код) self.steps_right.controls.append(
binary_result = self.to_twos_complement(result, self.bit_width) ft.Text("📝 Ход решения:", size=14, weight=ft.FontWeight.BOLD, color="#FFD700")
)
self.result_right.value = binary_result for i, step in enumerate(steps, 1):
self.decimal_right.value = f"({result}₁₀)" step_content = []
self.result_right.update() step_content.append(ft.Text(f"Шаг {i}: {step.title}", size=12, weight=ft.FontWeight.BOLD, color="#00FFFF"))
self.decimal_right.update() step_content.append(ft.Text(step.description, size=10, color="#E0E0E0"))
except ValueError as ex: if step.visual:
self.result_right.value = "Ошибка" step_content.append(ft.Text(step.visual, size=10, font_family="Courier New", color="#90EE90", selectable=True))
self.decimal_right.value = str(ex) if step.result:
self.result_right.update() step_content.append(ft.Text(f"{step.result}", size=11, weight=ft.FontWeight.BOLD, color="#00FF00"))
self.decimal_right.update()
self.steps_right.controls.append(
ft.Container(
content=ft.Column(step_content, spacing=3),
bgcolor="#2A1A3A",
padding=8,
border_radius=5,
border=ft.border.all(1, "#4A3A5A")
)
)
self.steps_right.update()
except Exception as ex:
self.steps_right.controls.clear()
self.steps_right.controls.append(ft.Text(f"Ошибка: {str(ex)}", color="red", size=10))
self.steps_right.update()
def test_data(self, e): def test_data(self, e):
# Создаем поля ввода с валидацией для двоичных чисел # Создаем поля ввода с валидацией для шестнадцатеричных чисел
self.input_left_1 = ft.TextField( self.input_left_1 = ft.TextField(
label="Двоичное число 1", label="Шестнадцатеричное число 1",
width=250, width=250,
text_align=ft.TextAlign.RIGHT, text_align=ft.TextAlign.RIGHT,
value="0", value="0",
input_filter=ft.InputFilter(regex_string=r"^[01]*$"), # только 0 и 1 input_filter=ft.InputFilter(regex_string=r"^[0-9A-Fa-f.-]*$"), # только 0-9, A-F, точка и минус
hint_text="Например: 00001010 (10) или 11110110 (-10)" hint_text="Например: A (10) или -A (-10) или 1A.C (26.75)"
) )
self.input_left_2 = ft.TextField( self.input_left_2 = ft.TextField(
label="Двоичное число 2", label="Шестнадцатеричное число 2",
width=250, width=250,
text_align=ft.TextAlign.RIGHT, text_align=ft.TextAlign.RIGHT,
value="0", value="0",
input_filter=ft.InputFilter(regex_string=r"^[01]*$"), input_filter=ft.InputFilter(regex_string=r"^[0-9A-Fa-f.-]*$"),
hint_text="Например: 00000101 (5)" hint_text="Например: 5 (5) или F.8 (15.5)"
) )
self.input_right_1 = ft.TextField( self.input_right_1 = ft.TextField(
label="Двоичное число 1", label="Шестнадцатеричное число 1",
width=250, width=250,
text_align=ft.TextAlign.RIGHT, text_align=ft.TextAlign.RIGHT,
value="0", value="0",
input_filter=ft.InputFilter(regex_string=r"^[01]*$"), input_filter=ft.InputFilter(regex_string=r"^[0-9A-Fa-f.-]*$"),
hint_text="Например: 00001010 (10)" hint_text="Например: A (10) или FF (255)"
) )
self.input_right_2 = ft.TextField( self.input_right_2 = ft.TextField(
label="Двоичное число 2", label="Шестнадцатеричное число 2",
width=250, width=250,
text_align=ft.TextAlign.RIGHT, text_align=ft.TextAlign.RIGHT,
value="0", value="0",
input_filter=ft.InputFilter(regex_string=r"^[01]*$"), input_filter=ft.InputFilter(regex_string=r"^[0-9A-Fa-f.-]*$"),
hint_text="Например: 00000101 (5)" hint_text="Например: 5 (5) или 1F (31)"
) )
right_column.controls = [ft.Container( right_column.controls = [ft.Container(
@@ -181,9 +285,9 @@ class Button_sedecim_calculator(ft.CupertinoButton):
scroll=ft.ScrollMode.AUTO, scroll=ft.ScrollMode.AUTO,
expand=True, expand=True,
controls=[ controls=[
ft.Text("Двоичный калькулятор (дополнительный код)", size=20, color="white", weight=ft.FontWeight.BOLD), ft.Text("Шестнадцатеричный калькулятор", size=20, color="white", weight=ft.FontWeight.BOLD),
ft.Text("Отрицательные числа в дополнительном коде (старший бит = 1)", size=11, color="#B0B0B0", italic=True), ft.Text("Поддерживает отрицательные числа и дроби", size=11, color="#B0B0B0", italic=True),
ft.Text(f"Разрядность: {self.bit_width} бит. Диапазон: {-(1 << (self.bit_width-1))} .. {(1 << (self.bit_width-1))-1}", size=11, color="#B0B0B0"), ft.Text("Используйте A-F для цифр 10-15, точку для дробей, минус для отрицательных", size=11, color="#B0B0B0"),
ft.Row( ft.Row(
expand=True, expand=True,
alignment=ft.MainAxisAlignment.CENTER, alignment=ft.MainAxisAlignment.CENTER,
@@ -191,7 +295,7 @@ class Button_sedecim_calculator(ft.CupertinoButton):
controls=[ controls=[
ft.Column( ft.Column(
expand=True, expand=True,
alignment=ft.MainAxisAlignment.CENTER, alignment=ft.MainAxisAlignment.START,
horizontal_alignment=ft.CrossAxisAlignment.CENTER, horizontal_alignment=ft.CrossAxisAlignment.CENTER,
controls=[ controls=[
self.input_left_1, self.input_left_1,
@@ -206,12 +310,19 @@ class Button_sedecim_calculator(ft.CupertinoButton):
padding=10, padding=10,
border_radius=5, border_radius=5,
), ),
ft.CupertinoButton("=", on_click=self.calculate_subtraction) ft.CupertinoButton("=", on_click=self.calculate_subtraction),
ft.Container(
expand=True,
content=self.steps_left,
bgcolor="#1A0A2A",
padding=10,
border_radius=5,
)
] ]
), ),
ft.Column( ft.Column(
expand=True, expand=True,
alignment=ft.MainAxisAlignment.CENTER, alignment=ft.MainAxisAlignment.START,
horizontal_alignment=ft.CrossAxisAlignment.CENTER, horizontal_alignment=ft.CrossAxisAlignment.CENTER,
controls=[ controls=[
self.input_right_1, self.input_right_1,
@@ -226,7 +337,14 @@ class Button_sedecim_calculator(ft.CupertinoButton):
padding=10, padding=10,
border_radius=5, border_radius=5,
), ),
ft.CupertinoButton("=", on_click=self.calculate_addition) ft.CupertinoButton("=", on_click=self.calculate_addition),
ft.Container(
expand=True,
content=self.steps_right,
bgcolor="#1A0A2A",
padding=10,
border_radius=5,
)
] ]
) )
] ]

View File

@@ -0,0 +1,537 @@
"""
Модуль для пошагового решения задач с системами счисления (2, 8, 16, n-ричные)
Алгоритм работает аналогично Photomath - показывает каждый шаг решения
"""
from typing import List, Tuple, Dict
from enum import Enum
class Operation(Enum):
"""Типы операций"""
ADDITION = "сложение"
SUBTRACTION = "вычитание"
class NumberSystem(Enum):
"""Поддерживаемые системы счисления"""
BINARY = 2
OCTAL = 8
DECIMAL = 10
HEXADECIMAL = 16
class Step:
"""Класс для представления одного шага решения"""
def __init__(self, title: str, description: str, visual: str = "", result: str = ""):
self.title = title # Название шага
self.description = description # Описание что делается
self.visual = visual # Визуальное представление
self.result = result # Результат этого шага
def __str__(self):
output = f"\n{'='*60}\n"
output += f"ШАГ: {self.title}\n"
output += f"{'='*60}\n"
output += f"{self.description}\n"
if self.visual:
output += f"\n{self.visual}\n"
if self.result:
output += f"\n➤ Результат: {self.result}\n"
return output
class StepByStepSolver:
"""
Класс для пошагового решения задач с системами счисления
"""
def __init__(self, base: int = 10, digits: str = None):
"""
Инициализация решателя
Args:
base: основание системы счисления (2, 8, 10, 16 или любое n)
digits: строка с символами для представления цифр (по умолчанию 0-9A-Z)
"""
self.base = base
self.steps: List[Step] = []
# Используем пользовательский набор символов или стандартный
if digits is not None:
self.digits = digits
else:
self.digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def clear_steps(self):
"""Очистить все шаги решения"""
self.steps = []
def get_system_name(self) -> str:
"""Получить название системы счисления"""
names = {
2: "двоичная",
8: "восьмеричная",
10: "десятичная",
16: "шестнадцатеричная"
}
return names.get(self.base, f"{self.base}-ричная")
def validate_number(self, number: str) -> bool:
"""
Проверка корректности числа в данной системе счисления
Args:
number: строка с числом
Returns:
True если число корректно, False иначе
"""
number = number.upper().replace('-', '')
valid_digits = self.digits[:self.base]
return all(c in valid_digits for c in number)
def to_decimal(self, number: str) -> int:
"""
Преобразование числа из n-ричной системы в десятичную
Args:
number: число в n-ричной системе
Returns:
число в десятичной системе
"""
is_negative = number.startswith('-')
number = number.replace('-', '').upper()
result = 0
for i, digit in enumerate(reversed(number)):
digit_value = self.digits.index(digit)
result += digit_value * (self.base ** i)
return -result if is_negative else result
def from_decimal(self, number: int) -> str:
"""
Преобразование из десятичной системы в n-ричную
Args:
number: число в десятичной системе
Returns:
число в n-ричной системе
"""
if number == 0:
return "0"
is_negative = number < 0
number = abs(number)
result = ""
while number > 0:
result = self.digits[number % self.base] + result
number //= self.base
return ("-" + result) if is_negative else result
def convert_with_steps(self, number: str, target_base: int) -> List[Step]:
"""
Преобразование числа в другую систему счисления с пошаговым объяснением
Args:
number: исходное число
target_base: целевая система счисления
Returns:
список шагов решения
"""
steps = []
is_negative = number.startswith('-')
number = number.replace('-', '').upper()
# Шаг 1: Исходные данные
step1 = Step(
"Исходные данные",
f"Необходимо преобразовать число {number} из {self.get_system_name()} " +
f"({self.base}-ричной) системы в {target_base}-ричную систему",
f"Исходное число: {'-' if is_negative else ''}{number}{self.base}"
)
steps.append(step1)
# Шаг 2: Перевод в десятичную систему (если нужно)
if self.base != 10:
decimal_value = 0
calculation = []
for i, digit in enumerate(reversed(number)):
digit_value = self.digits.index(digit)
power = self.base ** i
term_value = digit_value * power
decimal_value += term_value
calculation.append(f"{digit}×{self.base}^{i} = {digit_value}×{power} = {term_value}")
visual = "\n".join(calculation)
visual += f"\n\nСумма: {' + '.join([str(digit_value * (self.base ** i)) for i, digit in enumerate(reversed(number)) for digit_value in [self.digits.index(digit)]])} = {decimal_value}"
step2 = Step(
"Перевод в десятичную систему",
f"Каждую цифру умножаем на {self.base} в степени её позиции (справа налево, начиная с 0)",
visual,
f"{decimal_value}₍₁₀₎"
)
steps.append(step2)
else:
decimal_value = int(number)
# Шаг 3: Перевод из десятичной в целевую систему (если нужно)
if target_base != 10:
divisions = []
temp = decimal_value
result_digits = []
while temp > 0:
remainder = temp % target_base
quotient = temp // target_base
result_digits.insert(0, self.digits[remainder])
divisions.append(f"{temp} ÷ {target_base} = {quotient}, остаток: {remainder} ({self.digits[remainder]})")
temp = quotient
result_number = ''.join(result_digits) if result_digits else "0"
visual = "\n".join(divisions)
visual += f"\n\nЧитаем остатки снизу вверх: {result_number}"
step3 = Step(
f"Перевод в {target_base}-ричную систему",
f"Делим число на {target_base} и записываем остатки. " +
"Читаем остатки снизу вверх",
visual,
f"{'-' if is_negative else ''}{result_number}{target_base}"
)
steps.append(step3)
final_result = ('-' if is_negative else '') + result_number
else:
final_result = str(decimal_value)
# Финальный шаг
final_step = Step(
"Итоговый результат",
f"Число {'-' if is_negative else ''}{number}{self.base}₎ = {final_result}{target_base}",
"",
f"{final_result}{target_base}"
)
steps.append(final_step)
return steps
def add_with_steps(self, num1: str, num2: str) -> List[Step]:
"""
Сложение двух чисел в n-ричной системе с пошаговым объяснением
Args:
num1: первое число
num2: второе число
Returns:
список шагов решения
"""
steps = []
# Шаг 1: Исходные данные
step1 = Step(
"Условие задачи",
f"Необходимо сложить два числа в {self.get_system_name()} ({self.base}-ричной) системе счисления",
f"{num1}{self.base}₎ + {num2}{self.base}₎ = ?",
""
)
steps.append(step1)
# Проверка на отрицательные числа
is_neg1 = num1.startswith('-')
is_neg2 = num2.startswith('-')
num1_clean = num1.replace('-', '').upper()
num2_clean = num2.replace('-', '').upper()
# Шаг 2: Выравнивание разрядов
max_len = max(len(num1_clean), len(num2_clean))
num1_aligned = num1_clean.zfill(max_len)
num2_aligned = num2_clean.zfill(max_len)
visual = f" {num1_aligned}\n+ {num2_aligned}\n" + "-" * (max_len + 2)
step2 = Step(
"Выравнивание чисел",
f"Дополняем числа нулями слева до одинаковой длины ({max_len} разрядов)",
visual,
""
)
steps.append(step2)
# Шаг 3: Сложение в столбик
result = []
carry = 0
detailed_calc = []
for i in range(max_len - 1, -1, -1):
d1 = self.digits.index(num1_aligned[i])
d2 = self.digits.index(num2_aligned[i])
total = d1 + d2 + carry
digit_result = total % self.base
new_carry = total // self.base
result.insert(0, self.digits[digit_result])
position = max_len - i - 1
explanation = f"Позиция {position}: {num1_aligned[i]}({d1}) + {num2_aligned[i]}({d2})"
if carry > 0:
explanation += f" + перенос({carry})"
explanation += f" = {total}"
if new_carry > 0:
explanation += f" = {digit_result} (перенос {new_carry})"
else:
explanation += f" = {digit_result}"
detailed_calc.insert(0, explanation)
carry = new_carry
if carry > 0:
result.insert(0, self.digits[carry])
detailed_calc.insert(0, f"Финальный перенос: {carry}")
result_str = ''.join(result)
visual = "\n".join(detailed_calc)
visual += f"\n\nВизуализация:\n {num1_aligned}\n+ {num2_aligned}\n" + "-" * (max_len + 2) + f"\n {result_str}"
step3 = Step(
"Сложение в столбик",
f"Складываем числа справа налево, учитывая переносы. " +
f"При сумме ≥ {self.base} делим на {self.base}: остаток - результат, частное - перенос",
visual,
f"{result_str}{self.base}"
)
steps.append(step3)
# Шаг 4: Проверка через десятичную систему
dec1 = self.to_decimal(num1)
dec2 = self.to_decimal(num2)
dec_result = dec1 + dec2
step4 = Step(
"Проверка результата",
"Проверим правильность через перевод в десятичную систему",
f"{num1}{self.base}₎ = {dec1}₍₁₀₎\n" +
f"{num2}{self.base}₎ = {dec2}₍₁₀₎\n" +
f"{dec1} + {dec2} = {dec_result}\n" +
f"{dec_result}₍₁₀₎ = {result_str}{self.base}",
f"✓ Ответ верен: {result_str}{self.base}"
)
steps.append(step4)
return steps
def subtract_with_steps(self, num1: str, num2: str) -> List[Step]:
"""
Вычитание двух чисел в n-ричной системе с пошаговым объяснением
Args:
num1: уменьшаемое
num2: вычитаемое
Returns:
список шагов решения
"""
steps = []
# Шаг 1: Исходные данные
step1 = Step(
"Условие задачи",
f"Необходимо вычесть два числа в {self.get_system_name()} ({self.base}-ричной) системе счисления",
f"{num1}{self.base}₎ - {num2}{self.base}₎ = ?",
""
)
steps.append(step1)
# Определяем знак результата
dec1 = self.to_decimal(num1)
dec2 = self.to_decimal(num2)
is_negative = dec1 < dec2
# Работаем с абсолютными значениями
if is_negative:
num1, num2 = num2, num1
num1 = num1.replace('-', '')
num2 = num2.replace('-', '')
num1_clean = num1.replace('-', '').upper()
num2_clean = num2.replace('-', '').upper()
# Шаг 2: Выравнивание разрядов
max_len = max(len(num1_clean), len(num2_clean))
num1_aligned = num1_clean.zfill(max_len)
num2_aligned = num2_clean.zfill(max_len)
visual = f" {num1_aligned}\n- {num2_aligned}\n" + "-" * (max_len + 2)
step2 = Step(
"Выравнивание чисел",
f"Дополняем числа нулями слева до одинаковой длины ({max_len} разрядов)",
visual,
""
)
steps.append(step2)
# Шаг 3: Вычитание в столбик
result = []
borrow = 0
detailed_calc = []
num1_list = list(num1_aligned)
for i in range(max_len - 1, -1, -1):
d1 = self.digits.index(num1_list[i])
d2 = self.digits.index(num2_aligned[i])
# Учитываем заем
d1 -= borrow
position = max_len - i - 1
explanation = f"Позиция {position}: {num1_list[i]}({self.digits.index(num1_list[i])})"
if borrow > 0:
explanation += f" - заем({borrow})"
explanation += f" = {d1}"
explanation += f" - {num2_aligned[i]}({d2})"
if d1 < d2:
# Нужен заем
d1 += self.base
borrow = 1
explanation += f" → занимаем {self.base}, получаем {d1} - {d2} = {d1 - d2}"
else:
borrow = 0
explanation += f" = {d1 - d2}"
digit_result = d1 - d2
result.insert(0, self.digits[digit_result])
detailed_calc.insert(0, explanation)
# Убираем ведущие нули
result_str = ''.join(result).lstrip('0') or '0'
visual = "\n".join(detailed_calc)
visual += f"\n\nВизуализация:\n {num1_aligned}\n- {num2_aligned}\n" + "-" * (max_len + 2)
visual += f"\n {result_str.zfill(max_len)}"
if is_negative:
result_str = '-' + result_str
step3 = Step(
"Вычитание в столбик",
f"Вычитаем числа справа налево. " +
f"Если цифра уменьшаемого меньше вычитаемого, занимаем {self.base} из следующего разряда",
visual,
f"{result_str}{self.base}"
)
steps.append(step3)
# Шаг 4: Проверка
dec_result = dec1 - dec2
step4 = Step(
"Проверка результата",
"Проверим правильность через перевод в десятичную систему",
f"{num1}{self.base}₎ = {dec1}₍₁₀₎\n" +
f"{num2}{self.base}₎ = {dec2}₍₁₀₎\n" +
f"{dec1} - {dec2} = {dec_result}\n" +
f"{dec_result}₍₁₀₎ = {result_str}{self.base}",
f"✓ Ответ верен: {result_str}{self.base}"
)
steps.append(step4)
return steps
def solve(self, num1: str, num2: str, operation: Operation) -> List[Step]:
"""
Решить задачу с пошаговым объяснением
Args:
num1: первое число
num2: второе число
operation: тип операции (сложение/вычитание)
Returns:
список шагов решения
"""
if operation == Operation.ADDITION:
return self.add_with_steps(num1, num2)
elif operation == Operation.SUBTRACTION:
return self.subtract_with_steps(num1, num2)
else:
raise ValueError(f"Неподдерживаемая операция: {operation}")
def print_solution(self, steps: List[Step]):
"""
Вывести решение в консоль
Args:
steps: список шагов решения
"""
print("\n" + "="*60)
print("ПОШАГОВОЕ РЕШЕНИЕ")
print("="*60)
for i, step in enumerate(steps, 1):
print(f"\n{''*60}")
print(f"ШАГ {i}: {step.title}")
print(f"{''*60}")
print(f"\n{step.description}")
if step.visual:
print(f"\n{step.visual}")
if step.result:
print(f"\n➤ Результат: {step.result}")
print("\n" + "="*60)
print("РЕШЕНИЕ ЗАВЕРШЕНО")
print("="*60 + "\n")
# Пример использования
if __name__ == "__main__":
# Пример 1: Сложение в двоичной системе
print("ПРИМЕР 1: СЛОЖЕНИЕ В ДВОИЧНОЙ СИСТЕМЕ")
print("="*60)
solver = StepByStepSolver(base=2)
steps = solver.solve("1011", "110", Operation.ADDITION)
solver.print_solution(steps)
# Пример 2: Вычитание в восьмеричной системе
print("\n\nПРИМЕР 2: ВЫЧИТАНИЕ В ВОСЬМЕРИЧНОЙ СИСТЕМЕ")
print("="*60)
solver = StepByStepSolver(base=8)
steps = solver.solve("756", "237", Operation.SUBTRACTION)
solver.print_solution(steps)
# Пример 3: Сложение в шестнадцатеричной системе
print("\n\nПРИМЕР 3: СЛОЖЕНИЕ В ШЕСТНАДЦАТЕРИЧНОЙ СИСТЕМЕ")
print("="*60)
solver = StepByStepSolver(base=16)
steps = solver.solve("A5", "3F", Operation.ADDITION)
solver.print_solution(steps)
# Пример 4: Сложение в пятеричной системе
print("\n\nПРИМЕР 4: СЛОЖЕНИЕ В ПЯТЕРИЧНОЙ СИСТЕМЕ")
print("="*60)
solver = StepByStepSolver(base=5)
steps = solver.solve("234", "142", Operation.ADDITION)
solver.print_solution(steps)

14
app/src/test.py Normal file
View File

@@ -0,0 +1,14 @@
import math
v=20#скорость
p=21.5#необходимы путь
g=10#ускорение свободного падения
t_par=v/g
h_pod=(v**2)/(2*g)
h_main=p-h_pod
t_pod1=g/2
t_pod2=math.sqrt(h_main/t_pod1)
t=t_pod2-t_par
pass

67
app/src/test_base50.py Normal file
View File

@@ -0,0 +1,67 @@
"""
Тестирование 50-ричного калькулятора
"""
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from step_by_step_solver import StepByStepSolver, Operation
# Тест 50-ричной системы
print("="*60)
print("ТЕСТИРОВАНИЕ 50-РИЧНОЙ СИСТЕМЫ СЧИСЛЕНИЯ")
print("="*60)
solver = StepByStepSolver(base=50)
# Пример 1: Простое сложение
print("\n\nПРИМЕР 1: Сложение A + B в 50-ричной системе")
print("="*60)
print("A₍₅₀₎ = 10₍₁₀₎")
print("B₍₅₀₎ = 11₍₁₀₎")
print("Ожидаемый результат: V₍₅₀₎ = 21₍₁₀₎")
print()
steps = solver.solve("A", "B", Operation.ADDITION)
solver.print_solution(steps)
# Пример 2: Сложение с переносом
print("\n\nПРИМЕР 2: Сложение N + 1 в 50-ричной системе")
print("="*60)
print("N₍₅₀₎ = 49₍₁₀₎")
print("1₍₅₀₎ = 1₍₁₀₎")
print("Ожидаемый результат: 10₍₅₀₎ = 50₍₁₀₎")
print()
steps = solver.solve("N", "1", Operation.ADDITION)
solver.print_solution(steps)
# Пример 3: Большие числа
print("\n\nПРИМЕР 3: Сложение 1A + 2B в 50-ричной системе")
print("="*60)
print("1A₍₅₀₎ = 1×50 + 10 = 60₍₁₀₎")
print("2B₍₅₀₎ = 2×50 + 11 = 111₍₁₀₎")
print("Ожидаемый результат: 3V₍₅₀₎ = 171₍₁₀₎")
print()
steps = solver.solve("1A", "2B", Operation.ADDITION)
solver.print_solution(steps)
# Пример 4: Вычитание
print("\n\nПРИМЕР 4: Вычитание 2A - B в 50-ричной системе")
print("="*60)
print("2A₍₅₀₎ = 2×50 + 10 = 110₍₁₀₎")
print("B₍₅₀₎ = 11₍₁₀₎")
print("Ожидаемый результат: 1N₍₅₀₎ = 99₍₁₀₎")
print()
steps = solver.solve("2A", "B", Operation.SUBTRACTION)
solver.print_solution(steps)
# Проверка правильности конвертации
print("\n\nПРОВЕРКА ТАБЛИЦЫ СООТВЕТСТВИЙ (50-ричная → десятичная)")
print("="*60)
digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
print("Первые 50 символов:")
for i in range(50):
if i % 10 == 0:
print()
print(f"{digits[i]}={i:2d}", end=" ")
print("\n")

28
main.py
View File

@@ -0,0 +1,28 @@
import math as m
def decimal_to_base50(n):
if n == 0:
return "0"
# Символы для 50-ичной системы: 0-9, A-Z, a-m (всего 10+26+14=50)
digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklm"
result = ""
while n > 0:
remainder = n % 50
result = digits[remainder] + result
n = n // 50
return result
def base50_to_decimal(s):
# Словарь для преобразования символов в числа
digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklm"
char_to_value = {char: i for i, char in enumerate(digits)}
result = 0
for char in s:
result = result * 50 + char_to_value[char]
return result