151 lines
6.0 KiB
Python
151 lines
6.0 KiB
Python
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() |