avp26/u8/program.py
2026-11-06 01:00:26 +01:00

151 lines
6.0 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

class Node:
# класс решений (вопрос или конечный ответ)
def __init__(self, text: str):
self.text = text
self.is_question = text.endswith('?')
self.left = None # Ссылка на левого потомка (выбор a да)
self.right = None # Ссылка на правого потомка (выбор n нет)
class ZooExpertSystem:
# Класс для управления системой зоопарка
# Отвечает за 1чтение данных, 2построение бинарного дерева решений
# 3валидацию структуры и 4проведение взаимодействия с пользователем
def __init__(self):
# Корень построенного бинарного дерева
self.root = None
# Счетчики элементов всей базы знаний
self.q_count = 0 # Количество вопросов
self.a_count = 0 # Количество ответов (животных)
# Списки для разделенных строк входа
self.db_lines = [] # Строки относящиеся к базе знаний (дереву)
self.user_choices = [] # Строки с ответами пользователя (a или n)
def run(self):
# контроллер запускает программу в строгом соответствии с жизненным циклом.
print("Expert zo zoo to vie.")
# Считываем весь поток ввода и разделяем его
if not self._parse_input(): # _parse_input говорит нам что метод приватый
print("Chybna databaza")
return
# Строим дерево решений из прочитанных строк
if not self._build_tree(): # _build_tree создает цыпочку из вопросов которые приводят к ответу да или нет
print("Chybna databaza")
return
# Выводим информацию о базе знаний
self._print_stats()
# Запускаем интерактивный опрос пользователя
self._run_quiz()
def _read_tree_lines(self) -> list[str]:
# Считывает строки базы знаний из input() до первой пустой строки
tree_lines = []
try:
text = input().rstrip("\r")
while text != "":
tree_lines.append(text)
text = input().rstrip("\r")
except EOFError:
pass
return tree_lines
def _parse_input(self) -> bool:
# Читаем базу знаний до пустой строки
self.db_lines = self._read_tree_lines()
if not self.db_lines:
return False
# Читаем оставшиеся строки с ответами пользователя (a / n)
try:
while True:
choice = input().rstrip("\r")
self.user_choices.append(choice)
except EOFError:
pass
return True
def _build_tree(self) -> bool:
# Рекурсивная сборка бинарного дерева из db_lines в формате Preorder
idx = 0
def parse_node():
nonlocal idx
if idx >= len(self.db_lines):
return None
text = self.db_lines[idx]
idx += 1
node = Node(text)
if node.is_question:
self.q_count += 1
# Сначала собираем левую ветку (да a), затем правую (нет n)
node.left = parse_node()
node.right = parse_node()
# У каждого вопроса обязательно должны быть оба потомка
if node.left is None or node.right is None:
return None
else:
self.a_count += 1
return node
self.root = parse_node()
# Если структура ломается или в базе остались лишние неиспользованные строки
if self.root is None or idx != len(self.db_lines):
return False
return True
def _print_stats(self):
# Вывод количества вопросов, ответов и подсказки пользователю
print(f"Pocet otazok: {self.q_count}")
print(f"Pocet odpovedi: {self.a_count}")
print("Odpovedajte 'a' pre prvu moznost alebo 'n' pre druhu moznost.")
def _run_quiz(self):
# Пошаговый спуск по дереву от корня к животному
curr = self.root
choice_idx = 0
while True:
# Выводим текущий вопрос или название животного
print(curr.text)
# Дошли до конечной точки (листа с животным)
if not curr.is_question:
print("Koniec")
return
# Если для дальнейшего вопроса у пользователя не осталось ответа
if choice_idx >= len(self.user_choices):
print("Koniec vstupu")
return
choice = self.user_choices[choice_idx]
choice_idx += 1
if choice == "a":
curr = curr.left
elif choice == "n":
curr = curr.right
else:
# Введен неверный символ (не a и не n)
print("Nerozumiem")
return
if __name__ == "__main__":
system = ZooExpertSystem()
system.run()