|
|
% ===============================================
|
|
|
% АКИНАТОР - ЗАДАНИЕ 4
|
|
|
% Модификация акинатора с добавлением объектов
|
|
|
% ===============================================
|
|
|
|
|
|
% Объекты без дополнительных вопросов (определяются существующими)
|
|
|
object(собака).
|
|
|
object(кошка).
|
|
|
object(рыбка).
|
|
|
object(попугай).
|
|
|
|
|
|
% Новые объекты, требующие дополнительных вопросов
|
|
|
object(хомяк).
|
|
|
object(черепаха).
|
|
|
object(игуана).
|
|
|
object(канарейка).
|
|
|
|
|
|
% ===============================================
|
|
|
% БАЗОВЫЕ ВОПРОСЫ
|
|
|
% ===============================================
|
|
|
|
|
|
% Основные характеристики
|
|
|
question(has_fur, 'Есть ли у животного шерсть?').
|
|
|
question(can_fly, 'Умеет ли животное летать?').
|
|
|
question(lives_in_water, 'Живет ли животное в воде?').
|
|
|
question(makes_sound, 'Издает ли животное звуки?').
|
|
|
|
|
|
% Дополнительные вопросы для новых объектов
|
|
|
question(is_small, 'Это маленькое животное (помещается в ладонь)?').
|
|
|
question(has_shell, 'Есть ли у животного панцирь?').
|
|
|
question(is_reptile, 'Это рептилия?').
|
|
|
question(can_sing, 'Умеет ли животное петь?').
|
|
|
|
|
|
% ===============================================
|
|
|
% ПРАВИЛА ДЛЯ ОПРЕДЕЛЕНИЯ ОБЪЕКТОВ
|
|
|
% ===============================================
|
|
|
|
|
|
% Объекты без дополнительных вопросов
|
|
|
knows(собака) :-
|
|
|
answer(has_fur, yes),
|
|
|
answer(can_fly, no),
|
|
|
answer(lives_in_water, no),
|
|
|
answer(makes_sound, yes).
|
|
|
|
|
|
knows(кошка) :-
|
|
|
answer(has_fur, yes),
|
|
|
answer(can_fly, no),
|
|
|
answer(lives_in_water, no),
|
|
|
answer(makes_sound, yes),
|
|
|
\+ answer(is_small, yes). % Не маленькая
|
|
|
|
|
|
knows(рыбка) :-
|
|
|
answer(has_fur, no),
|
|
|
answer(can_fly, no),
|
|
|
answer(lives_in_water, yes).
|
|
|
|
|
|
knows(попугай) :-
|
|
|
answer(has_fur, no),
|
|
|
answer(can_fly, yes),
|
|
|
answer(makes_sound, yes),
|
|
|
\+ answer(can_sing, yes). % Не поет специально
|
|
|
|
|
|
% Новые объекты с дополнительными вопросами
|
|
|
knows(хомяк) :-
|
|
|
answer(has_fur, yes),
|
|
|
answer(can_fly, no),
|
|
|
answer(lives_in_water, no),
|
|
|
answer(is_small, yes),
|
|
|
answer(makes_sound, no).
|
|
|
|
|
|
knows(черепаха) :-
|
|
|
answer(has_fur, no),
|
|
|
answer(can_fly, no),
|
|
|
answer(has_shell, yes),
|
|
|
answer(is_reptile, yes).
|
|
|
|
|
|
knows(игуана) :-
|
|
|
answer(has_fur, no),
|
|
|
answer(can_fly, no),
|
|
|
answer(lives_in_water, no),
|
|
|
answer(is_reptile, yes),
|
|
|
answer(has_shell, no).
|
|
|
|
|
|
knows(канарейка) :-
|
|
|
answer(has_fur, no),
|
|
|
answer(can_fly, yes),
|
|
|
answer(makes_sound, yes),
|
|
|
answer(can_sing, yes),
|
|
|
answer(is_small, yes).
|
|
|
|
|
|
% ===============================================
|
|
|
% СИСТЕМА АКИНАТОРА
|
|
|
% ===============================================
|
|
|
|
|
|
% Запуск акинатора
|
|
|
start_akinator :-
|
|
|
write('=== АКИНАТОР ЗАДАНИЕ 4 ==='), nl,
|
|
|
write('Загадайте животное из списка:'), nl,
|
|
|
show_objects,
|
|
|
nl,
|
|
|
write('Отвечайте на вопросы yes/no'), nl,
|
|
|
write('Для выхода введите quit'), nl,
|
|
|
nl,
|
|
|
retractall(answer(_, _)),
|
|
|
ask_questions.
|
|
|
|
|
|
% Основной цикл вопросов
|
|
|
ask_questions :-
|
|
|
% Попробуем определить объект с текущими ответами
|
|
|
( find_object(Object) ->
|
|
|
write('Вы загадали: '), write(Object), write('!'), nl,
|
|
|
write('Правильно? (yes/no): '),
|
|
|
read(Response),
|
|
|
handle_guess_response(Response, Object)
|
|
|
; % Если не можем определить, задаем следующий вопрос
|
|
|
find_next_question(Question),
|
|
|
ask_question(Question),
|
|
|
ask_questions
|
|
|
).
|
|
|
|
|
|
% Найти объект, который соответствует текущим ответам
|
|
|
find_object(Object) :-
|
|
|
object(Object),
|
|
|
knows(Object),
|
|
|
!.
|
|
|
|
|
|
% Найти следующий вопрос для задавания
|
|
|
find_next_question(Question) :-
|
|
|
question(Question, _),
|
|
|
\+ answer(Question, _),
|
|
|
!.
|
|
|
|
|
|
% Задать вопрос пользователю
|
|
|
ask_question(Question) :-
|
|
|
question(Question, Text),
|
|
|
write(Text), write(' (yes/no/quit): '),
|
|
|
read(Response),
|
|
|
handle_response(Question, Response).
|
|
|
|
|
|
% Обработка ответа на вопрос
|
|
|
handle_response(_, quit) :-
|
|
|
write('До свидания!'), nl, !.
|
|
|
|
|
|
handle_response(Question, yes) :-
|
|
|
assert(answer(Question, yes)).
|
|
|
|
|
|
handle_response(Question, no) :-
|
|
|
assert(answer(Question, no)).
|
|
|
|
|
|
handle_response(Question, _) :-
|
|
|
write('Пожалуйста, ответьте yes, no или quit'), nl,
|
|
|
ask_question(Question).
|
|
|
|
|
|
% Обработка ответа на догадку
|
|
|
handle_guess_response(yes, Object) :-
|
|
|
write('Отлично! Я угадал '), write(Object), write('!'), nl,
|
|
|
write('Хотите играть еще? (yes/no): '),
|
|
|
read(Again),
|
|
|
( Again = yes ->
|
|
|
start_akinator
|
|
|
; write('Спасибо за игру!'), nl
|
|
|
).
|
|
|
|
|
|
handle_guess_response(no, Object) :-
|
|
|
write('Я ошибся с '), write(Object), write('.'), nl,
|
|
|
write('Какое животное вы загадали? '),
|
|
|
read(CorrectObject),
|
|
|
write('Спасибо! В следующий раз я буду умнее.'), nl,
|
|
|
learn_new_object(CorrectObject),
|
|
|
write('Хотите играть еще? (yes/no): '),
|
|
|
read(Again),
|
|
|
( Again = yes ->
|
|
|
start_akinator
|
|
|
; write('Спасибо за игру!'), nl
|
|
|
).
|
|
|
|
|
|
handle_guess_response(quit, _) :-
|
|
|
write('До свидания!'), nl.
|
|
|
|
|
|
handle_guess_response(_, Object) :-
|
|
|
write('Пожалуйста, ответьте yes, no или quit'), nl,
|
|
|
write('Я думаю это '), write(Object), write('. Правильно? '),
|
|
|
read(Response),
|
|
|
handle_guess_response(Response, Object).
|
|
|
|
|
|
% Обучение новому объекту (упрощенная версия)
|
|
|
learn_new_object(Object) :-
|
|
|
write('Добавляю '), write(Object), write(' в базу знаний...'), nl.
|
|
|
|
|
|
% ===============================================
|
|
|
% ДЕМОНСТРАЦИОННЫЕ ФУНКЦИИ
|
|
|
% ===============================================
|
|
|
|
|
|
% Показать все объекты
|
|
|
show_objects :-
|
|
|
write('Доступные объекты:'), nl,
|
|
|
forall(object(Obj), (write(' - '), write(Obj), nl)).
|
|
|
|
|
|
% Показать все вопросы
|
|
|
show_questions :-
|
|
|
write('Доступные вопросы:'), nl,
|
|
|
forall(question(Q, Text),
|
|
|
(write(' '), write(Q), write(': '), write(Text), nl)).
|
|
|
|
|
|
% Показать правила для объекта
|
|
|
show_rules(Object) :-
|
|
|
write('Правила для '), write(Object), write(':'), nl,
|
|
|
( knows(Object) ->
|
|
|
write(' Объект определяется существующими правилами'), nl
|
|
|
; write(' Правила не найдены'), nl
|
|
|
).
|
|
|
|
|
|
% Демонстрация объектов без дополнительных вопросов
|
|
|
demo_simple_objects :-
|
|
|
write('=== ОБЪЕКТЫ БЕЗ ДОПОЛНИТЕЛЬНЫХ ВОПРОСОВ ==='), nl,
|
|
|
SimpleObjects = [собака, кошка, рыбка, попугай],
|
|
|
forall(member(Obj, SimpleObjects),
|
|
|
(write('- '), write(Obj), nl)).
|
|
|
|
|
|
% Демонстрация объектов с дополнительными вопросами
|
|
|
demo_complex_objects :-
|
|
|
write('=== ОБЪЕКТЫ С ДОПОЛНИТЕЛЬНЫМИ ВОПРОСАМИ ==='), nl,
|
|
|
ComplexObjects = [хомяк, черепаха, игуана, канарейка],
|
|
|
forall(member(Obj, ComplexObjects),
|
|
|
(write('- '), write(Obj), write(' (требует: '),
|
|
|
show_additional_questions(Obj), write(')'), nl)).
|
|
|
|
|
|
% Показать дополнительные вопросы для объекта
|
|
|
show_additional_questions(хомяк) :- write('is_small').
|
|
|
show_additional_questions(черепаха) :- write('has_shell, is_reptile').
|
|
|
show_additional_questions(игуана) :- write('is_reptile').
|
|
|
show_additional_questions(канарейка) :- write('can_sing, is_small').
|
|
|
show_additional_questions(_) :- write('нет').
|
|
|
|
|
|
% Тестирование определения объектов
|
|
|
test_object_recognition :-
|
|
|
write('=== ТЕСТИРОВАНИЕ РАСПОЗНАВАНИЯ ОБЪЕКТОВ ==='), nl,
|
|
|
|
|
|
% Тест 1: Собака (без дополнительных вопросов)
|
|
|
write('Тест 1: Собака'), nl,
|
|
|
retractall(answer(_, _)),
|
|
|
assert(answer(has_fur, yes)),
|
|
|
assert(answer(can_fly, no)),
|
|
|
assert(answer(lives_in_water, no)),
|
|
|
assert(answer(makes_sound, yes)),
|
|
|
( knows(собака) ->
|
|
|
write(' ✓ Собака определена правильно'), nl
|
|
|
; write(' ✗ Ошибка определения собаки'), nl
|
|
|
),
|
|
|
|
|
|
% Тест 2: Хомяк (с дополнительными вопросами)
|
|
|
write('Тест 2: Хомяк'), nl,
|
|
|
retractall(answer(_, _)),
|
|
|
assert(answer(has_fur, yes)),
|
|
|
assert(answer(can_fly, no)),
|
|
|
assert(answer(lives_in_water, no)),
|
|
|
assert(answer(is_small, yes)),
|
|
|
assert(answer(makes_sound, no)),
|
|
|
( knows(хомяк) ->
|
|
|
write(' ✓ Хомяк определен правильно'), nl
|
|
|
; write(' ✗ Ошибка определения хомяка'), nl
|
|
|
),
|
|
|
|
|
|
% Тест 3: Черепаха (с дополнительными вопросами)
|
|
|
write('Тест 3: Черепаха'), nl,
|
|
|
retractall(answer(_, _)),
|
|
|
assert(answer(has_fur, no)),
|
|
|
assert(answer(can_fly, no)),
|
|
|
assert(answer(has_shell, yes)),
|
|
|
assert(answer(is_reptile, yes)),
|
|
|
( knows(черепаха) ->
|
|
|
write(' ✓ Черепаха определена правильно'), nl
|
|
|
; write(' ✗ Ошибка определения черепахи'), nl
|
|
|
),
|
|
|
|
|
|
retractall(answer(_, _)),
|
|
|
nl.
|
|
|
|
|
|
% Интерактивная демонстрация
|
|
|
demo :-
|
|
|
write('=== ДЕМОНСТРАЦИЯ АКИНАТОРА ЗАДАНИЕ 4 ==='), nl, nl,
|
|
|
|
|
|
write('1. ПОКАЗАТЬ ВСЕ ОБЪЕКТЫ'), nl,
|
|
|
write('========================'), nl,
|
|
|
show_objects,
|
|
|
nl,
|
|
|
|
|
|
write('2. ПОКАЗАТЬ ВСЕ ВОПРОСЫ'), nl,
|
|
|
write('========================'), nl,
|
|
|
show_questions,
|
|
|
nl,
|
|
|
|
|
|
write('3. ОБЪЕКТЫ БЕЗ ДОПОЛНИТЕЛЬНЫХ ВОПРОСОВ'), nl,
|
|
|
write('======================================'), nl,
|
|
|
demo_simple_objects,
|
|
|
nl,
|
|
|
|
|
|
write('4. ОБЪЕКТЫ С ДОПОЛНИТЕЛЬНЫМИ ВОПРОСАМИ'), nl,
|
|
|
write('====================================='), nl,
|
|
|
demo_complex_objects,
|
|
|
nl,
|
|
|
|
|
|
write('5. ТЕСТИРОВАНИЕ РАСПОЗНАВАНИЯ'), nl,
|
|
|
write('============================'), nl,
|
|
|
test_object_recognition,
|
|
|
|
|
|
write('6. ЗАПУСК ИНТЕРАКТИВНОГО АКИНАТОРА'), nl,
|
|
|
write('=================================='), nl,
|
|
|
write('Для запуска интерактивной игры используйте: ?- start_akinator.'), nl,
|
|
|
nl,
|
|
|
|
|
|
write('=== ДЕМОНСТРАЦИЯ ЗАВЕРШЕНА ==='), nl.
|
|
|
|
|
|
% ===============================================
|
|
|
% ВСПОМОГАТЕЛЬНЫЕ ПРЕДИКАТЫ
|
|
|
% ===============================================
|
|
|
|
|
|
% Подсчет количества объектов
|
|
|
count_objects(Count) :-
|
|
|
findall(Obj, object(Obj), Objects),
|
|
|
length(Objects, Count).
|
|
|
|
|
|
% Подсчет количества вопросов
|
|
|
count_questions(Count) :-
|
|
|
findall(Q, question(Q, _), Questions),
|
|
|
length(Questions, Count).
|
|
|
|
|
|
% Проверка, является ли объект простым (без дополнительных вопросов)
|
|
|
is_simple_object(Object) :-
|
|
|
member(Object, [собака, кошка, рыбка, попугай]).
|
|
|
|
|
|
% Проверка, является ли объект сложным (с дополнительными вопросами)
|
|
|
is_complex_object(Object) :-
|
|
|
member(Object, [хомяк, черепаха, игуана, канарейка]).
|
|
|
|
|
|
% Получить статистику
|
|
|
akinator_stats :-
|
|
|
count_objects(ObjCount),
|
|
|
count_questions(QCount),
|
|
|
findall(O, is_simple_object(O), Simple),
|
|
|
findall(C, is_complex_object(C), Complex),
|
|
|
length(Simple, SimpleCount),
|
|
|
length(Complex, ComplexCount),
|
|
|
|
|
|
write('=== СТАТИСТИКА АКИНАТОРА ==='), nl,
|
|
|
write('Всего объектов: '), write(ObjCount), nl,
|
|
|
write('Всего вопросов: '), write(QCount), nl,
|
|
|
write('Простых объектов: '), write(SimpleCount), nl,
|
|
|
write('Сложных объектов: '), write(ComplexCount), nl,
|
|
|
nl. |