Загрузка данных
import string
import kivy
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
DIGITS = string.digits + string.ascii_uppercase
class BaseConverterApp(App):
def build(self):
self.title = "Конвертер систем счисления с арифметикой"
# ТД-1: Хранилище состояния в оперативной памяти
self.state = {
"base": 10,
"operand1": "",
"operand2": "",
"result": "",
"last_error": ""
}
root = BoxLayout(orientation='vertical', padding=15, spacing=10)
# Сетка полей ввода (ТИ-1)
grid = GridLayout(cols=2, spacing=8, size_hint_y=None)
grid.bind(minimum_height=grid.setter('height'))
grid.add_widget(Label(text="Основание (2–36):", size_hint_y=None, height=35, halign='left'))
self.input_base = TextInput(text="10", multiline=False, size_hint_y=None, height=35)
grid.add_widget(self.input_base)
grid.add_widget(Label(text="Операнд 1:", size_hint_y=None, height=35))
self.input_op1 = TextInput(multiline=False, size_hint_y=None, height=35)
grid.add_widget(self.input_op1)
grid.add_widget(Label(text="Операнд 2:", size_hint_y=None, height=35))
self.input_op2 = TextInput(multiline=False, size_hint_y=None, height=35)
grid.add_widget(self.input_op2)
grid.add_widget(Label(text="Десятичное число:", size_hint_y=None, height=35))
self.input_dec = TextInput(multiline=False, size_hint_y=None, height=35)
grid.add_widget(self.input_dec)
root.add_widget(grid)
# Панель кнопок с точными названиями по ТИ-1 и ТИ-4
btn_layout = GridLayout(cols=4, spacing=8, size_hint_y=None, height=45)
self.btn_convert = Button(text="Перевести")
self.btn_convert.bind(on_press=self.handle_convert)
btn_layout.add_widget(self.btn_convert)
self.btn_add = Button(text="Сложить")
self.btn_add.bind(on_press=self.handle_add)
btn_layout.add_widget(self.btn_add)
self.btn_multiply = Button(text="Умножить")
self.btn_multiply.bind(on_press=self.handle_multiply)
btn_layout.add_widget(self.btn_multiply)
self.btn_from_dec = Button(text="Из десятичной")
self.btn_from_dec.bind(on_press=self.handle_from_dec)
btn_layout.add_widget(self.btn_from_dec)
root.add_widget(btn_layout)
# Поле вывода результата (ТИ-1, ТИ-2)
root.add_widget(Label(text="Результат:", size_hint_y=None, height=25, halign='left'))
self.txt_result = TextInput(
readonly=True,
multiline=True,
size_hint_y=0.4,
background_color=(0.95, 0.95, 0.95, 1)
)
root.add_widget(self.txt_result)
# Текстовое поле сообщений об ошибках (ТИ-1, ТИ-3, НТ-2)
root.add_widget(Label(text="Сообщения об ошибках:", size_hint_y=None, height=25, halign='left'))
self.txt_error = TextInput(
readonly=True,
multiline=True,
size_hint_y=0.3,
foreground_color=(0.85, 0.1, 0.1, 1),
background_color=(0.98, 0.95, 0.95, 1)
)
root.add_widget(self.txt_error)
return root
def set_error(self, err_msg):
"""Регистрирует ошибку и обновляет интерфейс согласно ТД-1 и ТИ-3."""
self.state["last_error"] = err_msg
self.txt_error.text = err_msg
def set_success(self, result_text):
"""Фиксирует успешный результат согласно ТД-1 и ТИ-2."""
self.state["result"] = result_text
self.state["last_error"] = ""
self.txt_result.text = result_text
self.txt_error.text = ""
def validate_and_get_base(self):
"""Проверка основания по БП-1 и ФТ-8."""
raw_base = self.input_base.text.strip()
if not raw_base:
self.set_error("Ошибка 3: основание должно быть целым числом от 2 до 36")
return None
try:
base_val = int(raw_base)
if not (2 <= base_val <= 36):
self.set_error("Ошибка 3: основание должно быть целым числом от 2 до 36")
return None
return base_val
except ValueError:
self.set_error("Ошибка 3: основание должно быть целым числом от 2 до 36")
return None
def validate_operand(self, op_text, base_val):
"""Проверка операнда по БП-2, БП-3, ФТ-2 и ФТ-7."""
cleaned = op_text.strip().upper()
if not cleaned:
# Пустая строка — ошибка допустимости цифр/ввода
max_char = DIGITS[base_val - 1]
self.set_error(f"Ошибка 2: цифра недопустима для основания {base_val}. Допустимый диапазон: 0–{max_char}")
return None
allowed = DIGITS[:base_val]
for ch in cleaned:
if ch not in allowed:
max_char = DIGITS[base_val - 1]
self.set_error(
f"Ошибка 2: цифра {ch} недопустима для основания {base_val}. Допустимый диапазон: 0–{max_char}")
return None
return cleaned
def int_to_base(self, num, base):
"""Перевод целого неотрицательного числа в целевое основание."""
if num == 0:
return "0"
digits = []
while num > 0:
digits.append(DIGITS[num % base])
num //= base
return "".join(reversed(digits))
def update_operands_state(self):
"""Сохраняет операнды как есть при выполнении операций (ТД-1)."""
self.state["operand1"] = self.input_op1.text
self.state["operand2"] = self.input_op2.text
def handle_convert(self, instance):
"""Операция перевода операндов в десятичную систему (ФТ-3, ТИ-2)."""
self.update_operands_state()
base = self.validate_and_get_base()
if base is None:
return
self.state["base"] = base
op1 = self.validate_operand(self.input_op1.text, base)
if op1 is None:
return
dec1 = int(op1, base)
res_str = f"Операнд 1: {dec1} (основание 10)"
op2_raw = self.input_op2.text.strip()
if op2_raw:
op2 = self.validate_operand(op2_raw, base)
if op2 is None:
return
dec2 = int(op2, base)
res_str += f"\nОперанд 2: {dec2} (основание 10)"
self.set_success(res_str)
def handle_add(self, instance):
"""Операция сложения операндов (ФТ-4, БП-4, ТИ-2)."""
self.update_operands_state()
base = self.validate_and_get_base()
if base is None:
return
self.state["base"] = base
op1 = self.validate_operand(self.input_op1.text, base)
if op1 is None:
return
op2 = self.validate_operand(self.input_op2.text, base)
if op2 is None:
return
sum_dec = int(op1, base) + int(op2, base)
result_in_base = self.int_to_base(sum_dec, base)
self.set_success(f"{result_in_base} (основание {base})")
def handle_multiply(self, instance):
"""Операция умножения операндов (ФТ-5, БП-4, ТИ-2)."""
self.update_operands_state()
base = self.validate_and_get_base()
if base is None:
return
self.state["base"] = base
op1 = self.validate_operand(self.input_op1.text, base)
if op1 is None:
return
op2 = self.validate_operand(self.input_op2.text, base)
if op2 is None:
return
prod_dec = int(op1, base) * int(op2, base)
result_in_base = self.int_to_base(prod_dec, base)
self.set_success(f"{result_in_base} (основание {base})")
def handle_from_dec(self, instance):
"""Обратный перевод из десятичной системы (ФТ-6, ТИ-2)."""
base = self.validate_and_get_base()
if base is None:
return
self.state["base"] = base
raw_dec = self.input_dec.text.strip()
if not raw_dec or not raw_dec.isdigit():
self.set_error("Ошибка 1: введите целое неотрицательное число")
return
dec_val = int(raw_dec)
res_in_base = self.int_to_base(dec_val, base)
self.set_success(f"{res_in_base} (основание {base})")
if __name__ == '__main__':
BaseConverterApp().run()