|
|
% ===============================================
|
|
|
% ПОЛНЫЙ АКИНАТОР - ЗАДАНИЕ 6
|
|
|
% Реализация полной системы акинатора
|
|
|
% ===============================================
|
|
|
|
|
|
% ===============================================
|
|
|
% БАЗА ЗНАНИЙ: ОБЪЕКТЫ И ХАРАКТЕРИСТИКИ
|
|
|
% ===============================================
|
|
|
|
|
|
% Животные (30 объектов)
|
|
|
object(собака).
|
|
|
object(кошка).
|
|
|
object(попугай).
|
|
|
object(хомяк).
|
|
|
object(рыбка).
|
|
|
object(черепаха).
|
|
|
object(канарейка).
|
|
|
object(кролик).
|
|
|
object(лев).
|
|
|
object(тигр).
|
|
|
object(слон).
|
|
|
object(жираф).
|
|
|
object(зебра).
|
|
|
object(волк).
|
|
|
object(медведь).
|
|
|
object(лиса).
|
|
|
object(олень).
|
|
|
object(заяц).
|
|
|
object(орел).
|
|
|
object(сова).
|
|
|
object(ворон).
|
|
|
object(голубь).
|
|
|
object(ласточка).
|
|
|
object(игуана).
|
|
|
object(змея).
|
|
|
object(лягушка).
|
|
|
object(крокодил).
|
|
|
object(бабочка).
|
|
|
object(пчела).
|
|
|
object(муравей).
|
|
|
|
|
|
% Вопросы для классификации
|
|
|
question(is_domestic, 'Это домашнее животное?').
|
|
|
question(has_fur, 'Есть ли у животного шерсть или мех?').
|
|
|
question(can_fly, 'Умеет ли животное летать?').
|
|
|
question(is_large, 'Это крупное животное (больше кошки)?').
|
|
|
question(is_predator, 'Это хищник?').
|
|
|
question(lives_in_water, 'Живет ли животное в воде?').
|
|
|
question(is_mammal, 'Это млекопитающее?').
|
|
|
question(has_stripes, 'Есть ли у животного полосы?').
|
|
|
question(is_nocturnal, 'Это ночное животное?').
|
|
|
question(can_swim, 'Умеет ли животное плавать?').
|
|
|
|
|
|
% Характеристики объектов (расширенная база знаний)
|
|
|
% Домашние животные
|
|
|
characteristic(собака, is_domestic, yes).
|
|
|
characteristic(собака, has_fur, yes).
|
|
|
characteristic(собака, can_fly, no).
|
|
|
characteristic(собака, is_large, yes).
|
|
|
characteristic(собака, is_predator, no).
|
|
|
characteristic(собака, lives_in_water, no).
|
|
|
characteristic(собака, is_mammal, yes).
|
|
|
characteristic(собака, has_stripes, no).
|
|
|
characteristic(собака, is_nocturnal, no).
|
|
|
characteristic(собака, can_swim, yes).
|
|
|
|
|
|
characteristic(кошка, is_domestic, yes).
|
|
|
characteristic(кошка, has_fur, yes).
|
|
|
characteristic(кошка, can_fly, no).
|
|
|
characteristic(кошка, is_large, no).
|
|
|
characteristic(кошка, is_predator, yes).
|
|
|
characteristic(кошка, lives_in_water, no).
|
|
|
characteristic(кошка, is_mammal, yes).
|
|
|
characteristic(кошка, has_stripes, no).
|
|
|
characteristic(кошка, is_nocturnal, yes).
|
|
|
characteristic(кошка, can_swim, no).
|
|
|
|
|
|
characteristic(попугай, is_domestic, yes).
|
|
|
characteristic(попугай, has_fur, no).
|
|
|
characteristic(попугай, can_fly, yes).
|
|
|
characteristic(попугай, is_large, no).
|
|
|
characteristic(попугай, is_predator, no).
|
|
|
characteristic(попугай, lives_in_water, no).
|
|
|
characteristic(попугай, is_mammal, no).
|
|
|
characteristic(попугай, has_stripes, no).
|
|
|
characteristic(попугай, is_nocturnal, no).
|
|
|
characteristic(попугай, can_swim, no).
|
|
|
|
|
|
characteristic(хомяк, is_domestic, yes).
|
|
|
characteristic(хомяк, has_fur, yes).
|
|
|
characteristic(хомяк, can_fly, no).
|
|
|
characteristic(хомяк, is_large, no).
|
|
|
characteristic(хомяк, is_predator, no).
|
|
|
characteristic(хомяк, lives_in_water, no).
|
|
|
characteristic(хомяк, is_mammal, yes).
|
|
|
characteristic(хомяк, has_stripes, no).
|
|
|
characteristic(хомяк, is_nocturnal, yes).
|
|
|
characteristic(хомяк, can_swim, no).
|
|
|
|
|
|
characteristic(рыбка, is_domestic, yes).
|
|
|
characteristic(рыбка, has_fur, no).
|
|
|
characteristic(рыбка, can_fly, no).
|
|
|
characteristic(рыбка, is_large, no).
|
|
|
characteristic(рыбка, is_predator, no).
|
|
|
characteristic(рыбка, lives_in_water, yes).
|
|
|
characteristic(рыбка, is_mammal, no).
|
|
|
characteristic(рыбка, has_stripes, no).
|
|
|
characteristic(рыбка, is_nocturnal, no).
|
|
|
characteristic(рыбка, can_swim, yes).
|
|
|
|
|
|
characteristic(черепаха, is_domestic, yes).
|
|
|
characteristic(черепаха, has_fur, no).
|
|
|
characteristic(черепаха, can_fly, no).
|
|
|
characteristic(черепаха, is_large, no).
|
|
|
characteristic(черепаха, is_predator, no).
|
|
|
characteristic(черепаха, lives_in_water, no).
|
|
|
characteristic(черепаха, is_mammal, no).
|
|
|
characteristic(черепаха, has_stripes, no).
|
|
|
characteristic(черепаха, is_nocturnal, no).
|
|
|
characteristic(черепаха, can_swim, yes).
|
|
|
|
|
|
characteristic(канарейка, is_domestic, yes).
|
|
|
characteristic(канарейка, has_fur, no).
|
|
|
characteristic(канарейка, can_fly, yes).
|
|
|
characteristic(канарейка, is_large, no).
|
|
|
characteristic(канарейка, is_predator, no).
|
|
|
characteristic(канарейка, lives_in_water, no).
|
|
|
characteristic(канарейка, is_mammal, no).
|
|
|
characteristic(канарейка, has_stripes, no).
|
|
|
characteristic(канарейка, is_nocturnal, no).
|
|
|
characteristic(канарейка, can_swim, no).
|
|
|
|
|
|
characteristic(кролик, is_domestic, yes).
|
|
|
characteristic(кролик, has_fur, yes).
|
|
|
characteristic(кролик, can_fly, no).
|
|
|
characteristic(кролик, is_large, no).
|
|
|
characteristic(кролик, is_predator, no).
|
|
|
characteristic(кролик, lives_in_water, no).
|
|
|
characteristic(кролик, is_mammal, yes).
|
|
|
characteristic(кролик, has_stripes, no).
|
|
|
characteristic(кролик, is_nocturnal, no).
|
|
|
characteristic(кролик, can_swim, no).
|
|
|
|
|
|
% Дикие хищники
|
|
|
characteristic(лев, is_domestic, no).
|
|
|
characteristic(лев, has_fur, yes).
|
|
|
characteristic(лев, can_fly, no).
|
|
|
characteristic(лев, is_large, yes).
|
|
|
characteristic(лев, is_predator, yes).
|
|
|
characteristic(лев, lives_in_water, no).
|
|
|
characteristic(лев, is_mammal, yes).
|
|
|
characteristic(лев, has_stripes, no).
|
|
|
characteristic(лев, is_nocturnal, yes).
|
|
|
characteristic(лев, can_swim, no).
|
|
|
|
|
|
characteristic(тигр, is_domestic, no).
|
|
|
characteristic(тигр, has_fur, yes).
|
|
|
characteristic(тигр, can_fly, no).
|
|
|
characteristic(тигр, is_large, yes).
|
|
|
characteristic(тигр, is_predator, yes).
|
|
|
characteristic(тигр, lives_in_water, no).
|
|
|
characteristic(тигр, is_mammal, yes).
|
|
|
characteristic(тигр, has_stripes, yes).
|
|
|
characteristic(тигр, is_nocturnal, yes).
|
|
|
characteristic(тигр, can_swim, yes).
|
|
|
|
|
|
characteristic(волк, is_domestic, no).
|
|
|
characteristic(волк, has_fur, yes).
|
|
|
characteristic(волк, can_fly, no).
|
|
|
characteristic(волк, is_large, yes).
|
|
|
characteristic(волк, is_predator, yes).
|
|
|
characteristic(волк, lives_in_water, no).
|
|
|
characteristic(волк, is_mammal, yes).
|
|
|
characteristic(волк, has_stripes, no).
|
|
|
characteristic(волк, is_nocturnal, yes).
|
|
|
characteristic(волк, can_swim, no).
|
|
|
|
|
|
characteristic(медведь, is_domestic, no).
|
|
|
characteristic(медведь, has_fur, yes).
|
|
|
characteristic(медведь, can_fly, no).
|
|
|
characteristic(медведь, is_large, yes).
|
|
|
characteristic(медведь, is_predator, yes).
|
|
|
characteristic(медведь, lives_in_water, no).
|
|
|
characteristic(медведь, is_mammal, yes).
|
|
|
characteristic(медведь, has_stripes, no).
|
|
|
characteristic(медведь, is_nocturnal, no).
|
|
|
characteristic(медведь, can_swim, yes).
|
|
|
|
|
|
characteristic(лиса, is_domestic, no).
|
|
|
characteristic(лиса, has_fur, yes).
|
|
|
characteristic(лиса, can_fly, no).
|
|
|
characteristic(лиса, is_large, no).
|
|
|
characteristic(лиса, is_predator, yes).
|
|
|
characteristic(лиса, lives_in_water, no).
|
|
|
characteristic(лиса, is_mammal, yes).
|
|
|
characteristic(лиса, has_stripes, no).
|
|
|
characteristic(лиса, is_nocturnal, yes).
|
|
|
characteristic(лиса, can_swim, no).
|
|
|
|
|
|
% Дикие травоядные
|
|
|
characteristic(слон, is_domestic, no).
|
|
|
characteristic(слон, has_fur, no).
|
|
|
characteristic(слон, can_fly, no).
|
|
|
characteristic(слон, is_large, yes).
|
|
|
characteristic(слон, is_predator, no).
|
|
|
characteristic(слон, lives_in_water, no).
|
|
|
characteristic(слон, is_mammal, yes).
|
|
|
characteristic(слон, has_stripes, no).
|
|
|
characteristic(слон, is_nocturnal, no).
|
|
|
characteristic(слон, can_swim, yes).
|
|
|
|
|
|
characteristic(жираф, is_domestic, no).
|
|
|
characteristic(жираф, has_fur, no).
|
|
|
characteristic(жираф, can_fly, no).
|
|
|
characteristic(жираф, is_large, yes).
|
|
|
characteristic(жираф, is_predator, no).
|
|
|
characteristic(жираф, lives_in_water, no).
|
|
|
characteristic(жираф, is_mammal, yes).
|
|
|
characteristic(жираф, has_stripes, no).
|
|
|
characteristic(жираф, is_nocturnal, no).
|
|
|
characteristic(жираф, can_swim, no).
|
|
|
|
|
|
characteristic(зебра, is_domestic, no).
|
|
|
characteristic(зебра, has_fur, no).
|
|
|
characteristic(зебра, can_fly, no).
|
|
|
characteristic(зебра, is_large, yes).
|
|
|
characteristic(зебра, is_predator, no).
|
|
|
characteristic(зебра, lives_in_water, no).
|
|
|
characteristic(зебра, is_mammal, yes).
|
|
|
characteristic(зебра, has_stripes, yes).
|
|
|
characteristic(зебра, is_nocturnal, no).
|
|
|
characteristic(зебра, can_swim, no).
|
|
|
|
|
|
characteristic(олень, is_domestic, no).
|
|
|
characteristic(олень, has_fur, yes).
|
|
|
characteristic(олень, can_fly, no).
|
|
|
characteristic(олень, is_large, yes).
|
|
|
characteristic(олень, is_predator, no).
|
|
|
characteristic(олень, lives_in_water, no).
|
|
|
characteristic(олень, is_mammal, yes).
|
|
|
characteristic(олень, has_stripes, no).
|
|
|
characteristic(олень, is_nocturnal, no).
|
|
|
characteristic(олень, can_swim, yes).
|
|
|
|
|
|
characteristic(заяц, is_domestic, no).
|
|
|
characteristic(заяц, has_fur, yes).
|
|
|
characteristic(заяц, can_fly, no).
|
|
|
characteristic(заяц, is_large, no).
|
|
|
characteristic(заяц, is_predator, no).
|
|
|
characteristic(заяц, lives_in_water, no).
|
|
|
characteristic(заяц, is_mammal, yes).
|
|
|
characteristic(заяц, has_stripes, no).
|
|
|
characteristic(заяц, is_nocturnal, no).
|
|
|
characteristic(заяц, can_swim, no).
|
|
|
|
|
|
% Птицы
|
|
|
characteristic(орел, is_domestic, no).
|
|
|
characteristic(орел, has_fur, no).
|
|
|
characteristic(орел, can_fly, yes).
|
|
|
characteristic(орел, is_large, yes).
|
|
|
characteristic(орел, is_predator, yes).
|
|
|
characteristic(орел, lives_in_water, no).
|
|
|
characteristic(орел, is_mammal, no).
|
|
|
characteristic(орел, has_stripes, no).
|
|
|
characteristic(орел, is_nocturnal, no).
|
|
|
characteristic(орел, can_swim, no).
|
|
|
|
|
|
characteristic(сова, is_domestic, no).
|
|
|
characteristic(сова, has_fur, no).
|
|
|
characteristic(сова, can_fly, yes).
|
|
|
characteristic(сова, is_large, no).
|
|
|
characteristic(сова, is_predator, yes).
|
|
|
characteristic(сова, lives_in_water, no).
|
|
|
characteristic(сова, is_mammal, no).
|
|
|
characteristic(сова, has_stripes, no).
|
|
|
characteristic(сова, is_nocturnal, yes).
|
|
|
characteristic(сова, can_swim, no).
|
|
|
|
|
|
characteristic(ворон, is_domestic, no).
|
|
|
characteristic(ворон, has_fur, no).
|
|
|
characteristic(ворон, can_fly, yes).
|
|
|
characteristic(ворон, is_large, no).
|
|
|
characteristic(ворон, is_predator, no).
|
|
|
characteristic(ворон, lives_in_water, no).
|
|
|
characteristic(ворон, is_mammal, no).
|
|
|
characteristic(ворон, has_stripes, no).
|
|
|
characteristic(ворон, is_nocturnal, no).
|
|
|
characteristic(ворон, can_swim, no).
|
|
|
|
|
|
characteristic(голубь, is_domestic, no).
|
|
|
characteristic(голубь, has_fur, no).
|
|
|
characteristic(голубь, can_fly, yes).
|
|
|
characteristic(голубь, is_large, no).
|
|
|
characteristic(голубь, is_predator, no).
|
|
|
characteristic(голубь, lives_in_water, no).
|
|
|
characteristic(голубь, is_mammal, no).
|
|
|
characteristic(голубь, has_stripes, no).
|
|
|
characteristic(голубь, is_nocturnal, no).
|
|
|
characteristic(голубь, can_swim, no).
|
|
|
|
|
|
characteristic(ласточка, is_domestic, no).
|
|
|
characteristic(ласточка, has_fur, no).
|
|
|
characteristic(ласточка, can_fly, yes).
|
|
|
characteristic(ласточка, is_large, no).
|
|
|
characteristic(ласточка, is_predator, no).
|
|
|
characteristic(ласточка, lives_in_water, no).
|
|
|
characteristic(ласточка, is_mammal, no).
|
|
|
characteristic(ласточка, has_stripes, no).
|
|
|
characteristic(ласточка, is_nocturnal, no).
|
|
|
characteristic(ласточка, can_swim, no).
|
|
|
|
|
|
% Рептилии и земноводные
|
|
|
characteristic(игуана, is_domestic, no).
|
|
|
characteristic(игуана, has_fur, no).
|
|
|
characteristic(игуана, can_fly, no).
|
|
|
characteristic(игуана, is_large, no).
|
|
|
characteristic(игуана, is_predator, no).
|
|
|
characteristic(игуана, lives_in_water, no).
|
|
|
characteristic(игуана, is_mammal, no).
|
|
|
characteristic(игуана, has_stripes, no).
|
|
|
characteristic(игуана, is_nocturnal, no).
|
|
|
characteristic(игуана, can_swim, yes).
|
|
|
|
|
|
characteristic(змея, is_domestic, no).
|
|
|
characteristic(змея, has_fur, no).
|
|
|
characteristic(змея, can_fly, no).
|
|
|
characteristic(змея, is_large, no).
|
|
|
characteristic(змея, is_predator, yes).
|
|
|
characteristic(змея, lives_in_water, no).
|
|
|
characteristic(змея, is_mammal, no).
|
|
|
characteristic(змея, has_stripes, no).
|
|
|
characteristic(змея, is_nocturnal, yes).
|
|
|
characteristic(змея, can_swim, yes).
|
|
|
|
|
|
characteristic(лягушка, is_domestic, no).
|
|
|
characteristic(лягушка, has_fur, no).
|
|
|
characteristic(лягушка, can_fly, no).
|
|
|
characteristic(лягушка, is_large, no).
|
|
|
characteristic(лягушка, is_predator, no).
|
|
|
characteristic(лягушка, lives_in_water, yes).
|
|
|
characteristic(лягушка, is_mammal, no).
|
|
|
characteristic(лягушка, has_stripes, no).
|
|
|
characteristic(лягушка, is_nocturnal, no).
|
|
|
characteristic(лягушка, can_swim, yes).
|
|
|
|
|
|
characteristic(крокодил, is_domestic, no).
|
|
|
characteristic(крокодил, has_fur, no).
|
|
|
characteristic(крокодил, can_fly, no).
|
|
|
characteristic(крокодил, is_large, yes).
|
|
|
characteristic(крокодил, is_predator, yes).
|
|
|
characteristic(крокодил, lives_in_water, yes).
|
|
|
characteristic(крокодил, is_mammal, no).
|
|
|
characteristic(крокодил, has_stripes, no).
|
|
|
characteristic(крокодил, is_nocturnal, no).
|
|
|
characteristic(крокодил, can_swim, yes).
|
|
|
|
|
|
% Насекомые
|
|
|
characteristic(бабочка, is_domestic, no).
|
|
|
characteristic(бабочка, has_fur, no).
|
|
|
characteristic(бабочка, can_fly, yes).
|
|
|
characteristic(бабочка, is_large, no).
|
|
|
characteristic(бабочка, is_predator, no).
|
|
|
characteristic(бабочка, lives_in_water, no).
|
|
|
characteristic(бабочка, is_mammal, no).
|
|
|
characteristic(бабочка, has_stripes, no).
|
|
|
characteristic(бабочка, is_nocturnal, no).
|
|
|
characteristic(бабочка, can_swim, no).
|
|
|
|
|
|
characteristic(пчела, is_domestic, no).
|
|
|
characteristic(пчела, has_fur, no).
|
|
|
characteristic(пчела, can_fly, yes).
|
|
|
characteristic(пчела, is_large, no).
|
|
|
characteristic(пчела, is_predator, no).
|
|
|
characteristic(пчела, lives_in_water, no).
|
|
|
characteristic(пчела, is_mammal, no).
|
|
|
characteristic(пчела, has_stripes, yes).
|
|
|
characteristic(пчела, is_nocturnal, no).
|
|
|
characteristic(пчела, can_swim, no).
|
|
|
|
|
|
characteristic(муравей, is_domestic, no).
|
|
|
characteristic(муравей, has_fur, no).
|
|
|
characteristic(муравей, can_fly, no).
|
|
|
characteristic(муравей, is_large, no).
|
|
|
characteristic(муравей, is_predator, no).
|
|
|
characteristic(муравей, lives_in_water, no).
|
|
|
characteristic(муравей, is_mammal, no).
|
|
|
characteristic(муравей, has_stripes, no).
|
|
|
characteristic(муравей, is_nocturnal, no).
|
|
|
characteristic(муравей, can_swim, no).
|
|
|
|
|
|
% ===============================================
|
|
|
% ОСНОВНАЯ ЛОГИКА АКИНАТОРА
|
|
|
% ===============================================
|
|
|
|
|
|
% Глобальные переменные для подсчета статистики
|
|
|
:- dynamic(questions_asked/1).
|
|
|
:- dynamic(session_stats/3). % session_stats(correct_guesses, wrong_guesses, total_questions)
|
|
|
|
|
|
% Инициализация статистики
|
|
|
init_stats :-
|
|
|
retractall(questions_asked(_)),
|
|
|
retractall(session_stats(_, _, _)),
|
|
|
assert(questions_asked(0)),
|
|
|
assert(session_stats(0, 0, 0)).
|
|
|
|
|
|
% Запуск акинатора
|
|
|
start_akinator :-
|
|
|
write('========================================'), nl,
|
|
|
write(' ДОБРО ПОЖАЛОВАТЬ В АКИНАТОР!'), nl,
|
|
|
write('========================================'), nl, nl,
|
|
|
write('Я попытаюсь угадать животное, которое вы загадали.'), nl,
|
|
|
write('Отвечайте на вопросы словами "yes", "no" или "quit".'), nl, nl,
|
|
|
show_available_animals,
|
|
|
nl,
|
|
|
init_stats,
|
|
|
main_game_loop.
|
|
|
|
|
|
% Показать доступных животных
|
|
|
show_available_animals :-
|
|
|
write('Доступные животные для загадывания:'), nl,
|
|
|
findall(Animal, object(Animal), Animals),
|
|
|
show_animals_list(Animals, 1).
|
|
|
|
|
|
show_animals_list([], _).
|
|
|
show_animals_list([Animal|Rest], N) :-
|
|
|
write(N), write('. '), write(Animal),
|
|
|
( (N mod 6 =:= 0) -> nl ; write(' ') ),
|
|
|
N1 is N + 1,
|
|
|
show_animals_list(Rest, N1).
|
|
|
|
|
|
% Основной игровой цикл
|
|
|
main_game_loop :-
|
|
|
write('Загадайте животное и нажмите Enter...'), nl,
|
|
|
read(_),
|
|
|
retractall(answer(_, _)),
|
|
|
start_questioning.
|
|
|
|
|
|
% Начало опроса
|
|
|
start_questioning :-
|
|
|
write('Начинаем игру! Отвечайте yes/no на вопросы:'), nl,
|
|
|
write('========================================='), nl,
|
|
|
ask_questions_intelligently.
|
|
|
|
|
|
% Интеллектуальный алгоритм задавания вопросов
|
|
|
ask_questions_intelligently :-
|
|
|
% Получить текущих кандидатов
|
|
|
get_current_candidates(Candidates),
|
|
|
length(Candidates, CandidateCount),
|
|
|
|
|
|
( CandidateCount =:= 0 ->
|
|
|
handle_no_candidates
|
|
|
; CandidateCount =:= 1 ->
|
|
|
handle_single_candidate(Candidates)
|
|
|
; CandidateCount =< 3 ->
|
|
|
handle_few_candidates(Candidates)
|
|
|
; % Много кандидатов - задать лучший вопрос
|
|
|
find_best_question(Candidates, BestQuestion),
|
|
|
ask_question(BestQuestion),
|
|
|
ask_questions_intelligently
|
|
|
).
|
|
|
|
|
|
% Получить текущих кандидатов на основе ответов
|
|
|
get_current_candidates(Candidates) :-
|
|
|
findall(Object,
|
|
|
(object(Object),
|
|
|
forall(answer(Question, Answer),
|
|
|
characteristic(Object, Question, Answer))),
|
|
|
Candidates).
|
|
|
|
|
|
% Найти лучший вопрос для разделения кандидатов
|
|
|
find_best_question(Candidates, BestQuestion) :-
|
|
|
findall(Question,
|
|
|
(question(Question, _),
|
|
|
\+ answer(Question, _)),
|
|
|
AvailableQuestions),
|
|
|
|
|
|
( AvailableQuestions = [] ->
|
|
|
BestQuestion = is_domestic % Запасной вариант
|
|
|
; find_most_balanced_question(AvailableQuestions, Candidates, BestQuestion)
|
|
|
).
|
|
|
|
|
|
% Найти наиболее сбалансированный вопрос
|
|
|
find_most_balanced_question([Question], _, Question) :- !.
|
|
|
find_most_balanced_question([Q1|RestQuestions], Candidates, BestQuestion) :-
|
|
|
calculate_question_balance(Q1, Candidates, Balance1),
|
|
|
find_most_balanced_question(RestQuestions, Candidates, Q2),
|
|
|
calculate_question_balance(Q2, Candidates, Balance2),
|
|
|
( Balance1 =< Balance2 ->
|
|
|
BestQuestion = Q1
|
|
|
; BestQuestion = Q2
|
|
|
).
|
|
|
|
|
|
% Вычислить сбалансированность вопроса (чем меньше, тем лучше)
|
|
|
calculate_question_balance(Question, Candidates, Balance) :-
|
|
|
findall(Obj,
|
|
|
(member(Obj, Candidates),
|
|
|
characteristic(Obj, Question, yes)),
|
|
|
YesCandidates),
|
|
|
findall(Obj,
|
|
|
(member(Obj, Candidates),
|
|
|
characteristic(Obj, Question, no)),
|
|
|
NoCandidates),
|
|
|
length(YesCandidates, YesCount),
|
|
|
length(NoCandidates, NoCount),
|
|
|
Balance is abs(YesCount - NoCount).
|
|
|
|
|
|
% Обработка случая, когда нет кандидатов
|
|
|
handle_no_candidates :-
|
|
|
write('Странно... Я не могу найти животное с такими характеристиками.'), nl,
|
|
|
write('Возможно, вы ошиблись в ответах или загадали животное, которого нет в моей базе.'), nl,
|
|
|
write('Какое животное вы загадали? '),
|
|
|
read(Mystery),
|
|
|
learn_from_failure(Mystery),
|
|
|
ask_play_again.
|
|
|
|
|
|
% Обработка случая с одним кандидатом
|
|
|
handle_single_candidate([Candidate]) :-
|
|
|
increment_questions_asked,
|
|
|
write('Я думаю, вы загадали: '), write(Candidate), write('!'), nl,
|
|
|
write('Правильно? (yes/no): '),
|
|
|
read(Response),
|
|
|
handle_guess_response(Response, Candidate).
|
|
|
|
|
|
% Обработка случая с несколькими кандидатами (2-3)
|
|
|
handle_few_candidates(Candidates) :-
|
|
|
write('У меня осталось несколько вариантов: '),
|
|
|
write_list(Candidates), nl,
|
|
|
|
|
|
% Попробуем угадать самый вероятный
|
|
|
select_most_likely(Candidates, MostLikely),
|
|
|
increment_questions_asked,
|
|
|
write('Я думаю, это: '), write(MostLikely), write('?'), nl,
|
|
|
write('Правильно? (yes/no): '),
|
|
|
read(Response),
|
|
|
|
|
|
( Response = yes ->
|
|
|
handle_correct_guess(MostLikely)
|
|
|
; Response = no ->
|
|
|
remove_candidate(MostLikely, Candidates, RemainingCandidates),
|
|
|
( RemainingCandidates = [] ->
|
|
|
handle_no_candidates
|
|
|
; RemainingCandidates = [LastCandidate] ->
|
|
|
handle_single_candidate([LastCandidate])
|
|
|
; handle_few_candidates(RemainingCandidates)
|
|
|
)
|
|
|
; write('Пожалуйста, ответьте yes или no.'), nl,
|
|
|
handle_few_candidates(Candidates)
|
|
|
).
|
|
|
|
|
|
% Выбрать наиболее вероятного кандидата
|
|
|
select_most_likely([First|_], First). % Простая стратегия - первый в списке
|
|
|
|
|
|
% Удалить кандидата из списка
|
|
|
remove_candidate(_, [], []).
|
|
|
remove_candidate(Candidate, [Candidate|Rest], Rest) :- !.
|
|
|
remove_candidate(Candidate, [Other|Rest], [Other|NewRest]) :-
|
|
|
remove_candidate(Candidate, Rest, NewRest).
|
|
|
|
|
|
% Задать вопрос пользователю
|
|
|
ask_question(Question) :-
|
|
|
increment_questions_asked,
|
|
|
question(Question, Text),
|
|
|
write('Вопрос: '), write(Text), write(' (yes/no/quit): '),
|
|
|
read(Response),
|
|
|
handle_response(Question, Response).
|
|
|
|
|
|
% Обработка ответа на вопрос
|
|
|
handle_response(_, quit) :-
|
|
|
write('Спасибо за игру! До свидания!'), nl,
|
|
|
show_session_stats, !.
|
|
|
|
|
|
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, Animal) :-
|
|
|
handle_correct_guess(Animal).
|
|
|
|
|
|
handle_guess_response(no, Animal) :-
|
|
|
handle_wrong_guess(Animal).
|
|
|
|
|
|
handle_guess_response(quit, _) :-
|
|
|
write('Спасибо за игру! До свидания!'), nl,
|
|
|
show_session_stats.
|
|
|
|
|
|
handle_guess_response(_, Animal) :-
|
|
|
write('Пожалуйста, ответьте yes, no или quit.'), nl,
|
|
|
write('Я думаю, это '), write(Animal), write('. Правильно? '),
|
|
|
read(Response),
|
|
|
handle_guess_response(Response, Animal).
|
|
|
|
|
|
% Обработка правильной догадки
|
|
|
handle_correct_guess(Animal) :-
|
|
|
write('Отлично! Я угадал '), write(Animal), write('!'), nl,
|
|
|
increment_correct_guesses,
|
|
|
questions_asked(QCount),
|
|
|
write('Мне потребовалось '), write(QCount), write(' вопросов.'), nl,
|
|
|
ask_play_again.
|
|
|
|
|
|
% Обработка неправильной догадки
|
|
|
handle_wrong_guess(Animal) :-
|
|
|
write('Я ошибся с '), write(Animal), write('.'), nl,
|
|
|
write('Какое животное вы загадали? '),
|
|
|
read(CorrectAnimal),
|
|
|
increment_wrong_guesses,
|
|
|
learn_from_mistake(CorrectAnimal, Animal),
|
|
|
ask_play_again.
|
|
|
|
|
|
% Обучение на ошибках
|
|
|
learn_from_mistake(CorrectAnimal, WrongGuess) :-
|
|
|
( object(CorrectAnimal) ->
|
|
|
write('Понятно, это был '), write(CorrectAnimal), write('.'), nl,
|
|
|
analyze_mistake(CorrectAnimal, WrongGuess)
|
|
|
; write('Спасибо! Я запомню животное '), write(CorrectAnimal), write('.'), nl,
|
|
|
write('К сожалению, его пока нет в моей базе данных.'), nl
|
|
|
).
|
|
|
|
|
|
% Анализ ошибки
|
|
|
analyze_mistake(Correct, Wrong) :-
|
|
|
write('Анализирую различия между '), write(Correct),
|
|
|
write(' и '), write(Wrong), write('...'), nl,
|
|
|
find_distinguishing_characteristics(Correct, Wrong),
|
|
|
write('Теперь я буду умнее!'), nl.
|
|
|
|
|
|
find_distinguishing_characteristics(Animal1, Animal2) :-
|
|
|
findall(Question-Value1-Value2,
|
|
|
(characteristic(Animal1, Question, Value1),
|
|
|
characteristic(Animal2, Question, Value2),
|
|
|
Value1 \= Value2),
|
|
|
Differences),
|
|
|
( Differences = [] ->
|
|
|
write('Эти животные имеют одинаковые характеристики в моей базе.'), nl
|
|
|
; write('Ключевые различия:'), nl,
|
|
|
show_differences(Differences)
|
|
|
).
|
|
|
|
|
|
show_differences([]).
|
|
|
show_differences([Question-Value1-Value2|Rest]) :-
|
|
|
question(Question, Text),
|
|
|
write(' '), write(Text), write(' -> '),
|
|
|
write(Value1), write(' vs '), write(Value2), nl,
|
|
|
show_differences(Rest).
|
|
|
|
|
|
% Обучение на неудачах
|
|
|
learn_from_failure(Mystery) :-
|
|
|
write('Буду помнить о '), write(Mystery), write('.'), nl,
|
|
|
write('Добавлю это животное в список для изучения.'), nl.
|
|
|
|
|
|
% Предложить сыграть еще раз
|
|
|
ask_play_again :-
|
|
|
nl,
|
|
|
write('Хотите сыграть еще раз? (yes/no): '),
|
|
|
read(Response),
|
|
|
( Response = yes ->
|
|
|
write('Отлично! Новая игра!'), nl, nl,
|
|
|
main_game_loop
|
|
|
; Response = no ->
|
|
|
write('Спасибо за игру! Было весело!'), nl,
|
|
|
show_session_stats
|
|
|
; write('Пожалуйста, ответьте yes или no.'), nl,
|
|
|
ask_play_again
|
|
|
).
|
|
|
|
|
|
% ===============================================
|
|
|
% СТАТИСТИКА И АНАЛИТИКА
|
|
|
% ===============================================
|
|
|
|
|
|
% Увеличить счетчик заданных вопросов
|
|
|
increment_questions_asked :-
|
|
|
retract(questions_asked(Count)),
|
|
|
NewCount is Count + 1,
|
|
|
assert(questions_asked(NewCount)).
|
|
|
|
|
|
% Увеличить счетчик правильных догадок
|
|
|
increment_correct_guesses :-
|
|
|
retract(session_stats(Correct, Wrong, Total)),
|
|
|
NewCorrect is Correct + 1,
|
|
|
NewTotal is Total + 1,
|
|
|
assert(session_stats(NewCorrect, Wrong, NewTotal)).
|
|
|
|
|
|
% Увеличить счетчик неправильных догадок
|
|
|
increment_wrong_guesses :-
|
|
|
retract(session_stats(Correct, Wrong, Total)),
|
|
|
NewWrong is Wrong + 1,
|
|
|
NewTotal is Total + 1,
|
|
|
assert(session_stats(Correct, NewWrong, NewTotal)).
|
|
|
|
|
|
% Показать статистику сессии
|
|
|
show_session_stats :-
|
|
|
session_stats(Correct, Wrong, Total),
|
|
|
write('========================================'), nl,
|
|
|
write(' СТАТИСТИКА СЕССИИ'), nl,
|
|
|
write('========================================'), nl,
|
|
|
write('Всего игр: '), write(Total), nl,
|
|
|
write('Правильных догадок: '), write(Correct), nl,
|
|
|
write('Неправильных догадок: '), write(Wrong), nl,
|
|
|
( Total > 0 ->
|
|
|
SuccessRate is (Correct * 100) // Total,
|
|
|
write('Процент успеха: '), write(SuccessRate), write('%'), nl
|
|
|
; write('Процент успеха: 0%'), nl
|
|
|
),
|
|
|
write('========================================'), nl.
|
|
|
|
|
|
% Информация об акинаторе
|
|
|
akinator_info :-
|
|
|
findall(Obj, object(Obj), Objects),
|
|
|
findall(Q, question(Q, _), Questions),
|
|
|
length(Objects, ObjCount),
|
|
|
length(Questions, QCount),
|
|
|
|
|
|
write('=== ИНФОРМАЦИЯ ОБ АКИНАТОРЕ ==='), nl,
|
|
|
write('Объектов в базе: '), write(ObjCount), nl,
|
|
|
write('Вопросов в базе: '), write(QCount), nl,
|
|
|
MaxDistinguishable is 2^QCount,
|
|
|
write('Максимум различимых объектов: '), write(MaxDistinguishable), nl,
|
|
|
|
|
|
( ObjCount =< MaxDistinguishable ->
|
|
|
write('✓ База данных сбалансирована'), nl
|
|
|
; write('⚠ Возможны проблемы с различением'), nl
|
|
|
),
|
|
|
|
|
|
nl,
|
|
|
write('КАТЕГОРИИ ЖИВОТНЫХ:'), nl,
|
|
|
show_animal_categories,
|
|
|
nl.
|
|
|
|
|
|
% Показать категории животных
|
|
|
show_animal_categories :-
|
|
|
count_by_category(is_domestic, 'Домашние/дикие'),
|
|
|
count_by_category(is_mammal, 'Млекопитающие/остальные'),
|
|
|
count_by_category(can_fly, 'Летающие/наземные'),
|
|
|
count_by_category(is_predator, 'Хищники/травоядные'),
|
|
|
count_by_category(is_large, 'Крупные/мелкие').
|
|
|
|
|
|
count_by_category(Category, Description) :-
|
|
|
findall(_, characteristic(_, Category, yes), YesList),
|
|
|
findall(_, characteristic(_, Category, no), NoList),
|
|
|
length(YesList, YesCount),
|
|
|
length(NoList, NoCount),
|
|
|
write(' '), write(Description), write(': '),
|
|
|
write(YesCount), write('/'), write(NoCount), nl.
|
|
|
|
|
|
% Статистика акинатора
|
|
|
akinator_statistics :-
|
|
|
write('=== РАСШИРЕННАЯ СТАТИСТИКА ==='), nl,
|
|
|
|
|
|
% Анализ уникальности
|
|
|
analyze_uniqueness,
|
|
|
nl,
|
|
|
|
|
|
% Анализ сложности вопросов
|
|
|
analyze_question_difficulty,
|
|
|
nl,
|
|
|
|
|
|
% Рекомендации
|
|
|
provide_recommendations.
|
|
|
|
|
|
% Анализ уникальности объектов
|
|
|
analyze_uniqueness :-
|
|
|
findall(Obj, object(Obj), Objects),
|
|
|
findall(Obj, is_unique_object(Obj), UniqueObjects),
|
|
|
length(Objects, Total),
|
|
|
length(UniqueObjects, Unique),
|
|
|
Duplicate is Total - Unique,
|
|
|
|
|
|
write('АНАЛИЗ УНИКАЛЬНОСТИ:'), nl,
|
|
|
write(' Всего объектов: '), write(Total), nl,
|
|
|
write(' Уникальных: '), write(Unique), nl,
|
|
|
write(' Дубликатов: '), write(Duplicate), nl,
|
|
|
|
|
|
( Duplicate = 0 ->
|
|
|
write(' ✓ Все объекты различимы'), nl
|
|
|
; Efficiency is (Unique * 100) // Total,
|
|
|
write(' Эффективность различения: '), write(Efficiency), write('%'), nl
|
|
|
).
|
|
|
|
|
|
% Проверка уникальности объекта
|
|
|
is_unique_object(Object) :-
|
|
|
\+ (object(OtherObject),
|
|
|
OtherObject \= Object,
|
|
|
same_characteristics(Object, OtherObject)).
|
|
|
|
|
|
% Проверка одинаковых характеристик
|
|
|
same_characteristics(Obj1, Obj2) :-
|
|
|
\+ (question(Question, _),
|
|
|
characteristic(Obj1, Question, Value1),
|
|
|
characteristic(Obj2, Question, Value2),
|
|
|
Value1 \= Value2).
|
|
|
|
|
|
% Анализ сложности вопросов
|
|
|
analyze_question_difficulty :-
|
|
|
write('АНАЛИЗ СЛОЖНОСТИ ВОПРОСОВ:'), nl,
|
|
|
findall(Q, question(Q, _), Questions),
|
|
|
forall(member(Question, Questions), analyze_single_question_difficulty(Question)).
|
|
|
|
|
|
analyze_single_question_difficulty(Question) :-
|
|
|
question(Question, Text),
|
|
|
findall(_, characteristic(_, Question, yes), YesList),
|
|
|
findall(_, characteristic(_, Question, no), NoList),
|
|
|
length(YesList, YesCount),
|
|
|
length(NoList, NoCount),
|
|
|
Total is YesCount + NoCount,
|
|
|
|
|
|
( Total > 0 ->
|
|
|
Balance is abs(YesCount - NoCount),
|
|
|
BalancePercent is (Balance * 100) // Total,
|
|
|
write(' '), write(Question), write(': '),
|
|
|
( BalancePercent < 20 ->
|
|
|
write('сбалансированный ('), write(BalancePercent), write('%)')
|
|
|
; BalancePercent < 40 ->
|
|
|
write('умеренный ('), write(BalancePercent), write('%)')
|
|
|
; write('несбалансированный ('), write(BalancePercent), write('%)')
|
|
|
), nl
|
|
|
; write(' '), write(Question), write(': нет данных'), nl
|
|
|
).
|
|
|
|
|
|
% Рекомендации по улучшению
|
|
|
provide_recommendations :-
|
|
|
write('РЕКОМЕНДАЦИИ:'), nl,
|
|
|
|
|
|
% Проверка дубликатов
|
|
|
findall(Obj, \+ is_unique_object(Obj), Duplicates),
|
|
|
( Duplicates = [] ->
|
|
|
write(' ✓ Дубликаты не найдены'), nl
|
|
|
; write(' ⚠ Найдены дубликаты, рекомендуется добавить вопросы'), nl
|
|
|
),
|
|
|
|
|
|
% Проверка покрытия
|
|
|
findall(Q, question(Q, _), Questions),
|
|
|
findall(Obj, object(Obj), Objects),
|
|
|
length(Questions, QCount),
|
|
|
length(Objects, ObjCount),
|
|
|
MaxCoverage is 2^QCount,
|
|
|
|
|
|
( ObjCount =< MaxCoverage ->
|
|
|
write(' ✓ Покрытие вопросов достаточное'), nl
|
|
|
; RecommendedQuestions is ceiling(log(ObjCount)/log(2)),
|
|
|
write(' ⚠ Рекомендуется минимум '), write(RecommendedQuestions),
|
|
|
write(' вопросов для '), write(ObjCount), write(' объектов'), nl
|
|
|
).
|
|
|
|
|
|
% ===============================================
|
|
|
% ДЕМОНСТРАЦИОННЫЕ ФУНКЦИИ
|
|
|
% ===============================================
|
|
|
|
|
|
% Демонстрация работы акинатора
|
|
|
demo_akinator :-
|
|
|
write('=== ДЕМОНСТРАЦИЯ АКИНАТОРА ==='), nl, nl,
|
|
|
|
|
|
write('1. ИНФОРМАЦИЯ О БАЗЕ ДАННЫХ'), nl,
|
|
|
write('============================'), nl,
|
|
|
akinator_info,
|
|
|
nl,
|
|
|
|
|
|
write('2. ТЕСТИРОВАНИЕ ЛОГИКИ'), nl,
|
|
|
write('======================'), nl,
|
|
|
test_akinator_logic,
|
|
|
nl,
|
|
|
|
|
|
write('3. АНАЛИЗ ЭФФЕКТИВНОСТИ'), nl,
|
|
|
write('========================'), nl,
|
|
|
akinator_statistics,
|
|
|
nl,
|
|
|
|
|
|
write('4. ИНСТРУКЦИИ ПО ИСПОЛЬЗОВАНИЮ'), nl,
|
|
|
write('==============================='), nl,
|
|
|
show_usage_instructions,
|
|
|
nl.
|
|
|
|
|
|
% Тестирование логики акинатора
|
|
|
test_akinator_logic :-
|
|
|
write('Тестирование поиска кандидатов:'), nl,
|
|
|
|
|
|
% Тест 1: домашний хищник
|
|
|
retractall(answer(_, _)),
|
|
|
assert(answer(is_domestic, yes)),
|
|
|
assert(answer(is_predator, yes)),
|
|
|
get_current_candidates(Candidates1),
|
|
|
write('Домашние хищники: '), write_list(Candidates1), nl,
|
|
|
|
|
|
% Тест 2: крупное летающее
|
|
|
retractall(answer(_, _)),
|
|
|
assert(answer(is_large, yes)),
|
|
|
assert(answer(can_fly, yes)),
|
|
|
get_current_candidates(Candidates2),
|
|
|
write('Крупные летающие: '), write_list(Candidates2), nl,
|
|
|
|
|
|
% Тест 3: полосатое животное
|
|
|
retractall(answer(_, _)),
|
|
|
assert(answer(has_stripes, yes)),
|
|
|
get_current_candidates(Candidates3),
|
|
|
write('Полосатые животные: '), write_list(Candidates3), nl,
|
|
|
|
|
|
retractall(answer(_, _)).
|
|
|
|
|
|
% Показать инструкции по использованию
|
|
|
show_usage_instructions :-
|
|
|
write('КАК ИСПОЛЬЗОВАТЬ АКИНАТОР:'), nl, nl,
|
|
|
|
|
|
write('1. ЗАПУСК ИГРЫ:'), nl,
|
|
|
write(' ?- start_akinator.'), nl,
|
|
|
write(' Следуйте инструкциям на экране'), nl, nl,
|
|
|
|
|
|
write('2. ОТВЕТЫ НА ВОПРОСЫ:'), nl,
|
|
|
write(' yes - да'), nl,
|
|
|
write(' no - нет'), nl,
|
|
|
write(' quit - выход из игры'), nl, nl,
|
|
|
|
|
|
write('3. ДЕМОНСТРАЦИОННЫЕ КОМАНДЫ:'), nl,
|
|
|
write(' ?- demo_akinator. % Полная демонстрация'), nl,
|
|
|
write(' ?- akinator_info. % Информация о базе'), nl,
|
|
|
write(' ?- akinator_statistics. % Статистика'), nl,
|
|
|
write(' ?- test_akinator_logic. % Тестирование логики'), nl, nl,
|
|
|
|
|
|
write('4. MAKEFILE КОМАНДЫ:'), nl,
|
|
|
write(' make run % Показать информацию об акинаторе'), nl,
|
|
|
write(' make interactive % Запустить интерактивную сессию'), nl,
|
|
|
write(' make demo % Запустить демонстрацию'), nl,
|
|
|
write(' make test % Запустить тесты'), nl, nl.
|
|
|
|
|
|
% Вспомогательная функция для вывода списка
|
|
|
write_list([]).
|
|
|
write_list([Item]) :- write(Item).
|
|
|
write_list([Item|Rest]) :-
|
|
|
write(Item), write(', '), write_list(Rest).
|
|
|
|
|
|
% ===============================================
|
|
|
% СЛУЖЕБНЫЕ ПРЕДИКАТЫ
|
|
|
% ===============================================
|
|
|
|
|
|
% Очистка состояния
|
|
|
reset_akinator :-
|
|
|
retractall(answer(_, _)),
|
|
|
retractall(questions_asked(_)),
|
|
|
retractall(session_stats(_, _, _)),
|
|
|
write('Состояние акинатора сброшено.'), nl.
|
|
|
|
|
|
% Экспорт статистики сессии
|
|
|
export_session_stats(Filename) :-
|
|
|
tell(Filename),
|
|
|
write('% Статистика сессии акинатора'), nl,
|
|
|
write('% Экспортировано: '), get_time(Time), write(Time), nl, nl,
|
|
|
session_stats(Correct, Wrong, Total),
|
|
|
write('session_correct_guesses('), write(Correct), write(').'), nl,
|
|
|
write('session_wrong_guesses('), write(Wrong), write(').'), nl,
|
|
|
write('session_total_games('), write(Total), write(').'), nl,
|
|
|
told,
|
|
|
write('Статистика экспортирована в '), write(Filename), nl.
|
|
|
|
|
|
% Получить случайное животное для тестирования
|
|
|
random_animal(Animal) :-
|
|
|
findall(Obj, object(Obj), Objects),
|
|
|
length(Objects, Len),
|
|
|
random(0, Len, Index),
|
|
|
nth0(Index, Objects, Animal).
|
|
|
|
|
|
% Симуляция игры для тестирования
|
|
|
simulate_game(Animal) :-
|
|
|
write('Симуляция игры для животного: '), write(Animal), nl,
|
|
|
retractall(answer(_, _)),
|
|
|
|
|
|
% Устанавливаем все характеристики животного
|
|
|
forall(characteristic(Animal, Question, Answer),
|
|
|
assert(answer(Question, Answer))),
|
|
|
|
|
|
% Проверяем, сможет ли акинатор угадать
|
|
|
get_current_candidates([Animal]),
|
|
|
write('✓ Акинатор успешно определил '), write(Animal), nl.
|
|
|
|
|
|
simulate_game(Animal) :-
|
|
|
write('✗ Акинатор не смог однозначно определить '), write(Animal), nl. |