113 lines
4.5 KiB
Python
113 lines
4.5 KiB
Python
class Node:
|
||
# класс решений (вопрос или конечный ответ)
|
||
def __init__(self, text: str):
|
||
self.text = text
|
||
self.is_question = text.endswith('?')
|
||
self.left = None # Ссылка на левого потомка (выбор t да)
|
||
self.right = None # Ссылка на правого потомка (выбор f нет)
|
||
|
||
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 = ([]) # Строки с ответами пользователя (t или f)
|
||
|
||
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
|
||
|
||
# Читаем оставшиеся строки с ответами пользователя (t / f)
|
||
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
|
||
|
||
if __name__ == "__main__":
|
||
system = ZooExpertSystem()
|
||
system.run()
|