Visual Prolog 5.2 логическая задача "На выставке собак"

      Комментарии к записи Visual Prolog 5.2 логическая задача "На выставке собак" отключены

Главная Форумы Программирование Помощь с решением задач на Prolog Решение головоломок на Prolog Visual Prolog 5.2 логическая задача "На выставке собак"

В этой теме 1 ответ, 2 участника, последнее обновление  Васильев Владимир Сергеевич 1 год, 2 мес. назад.

  • Автор
    Сообщения
  • #2766

    Neuderjimayia
    Участник

    Здравствуйте. Есть следующая задача:

    На выставке собак случилась интересная ситуация.
    Четыре брата — Энди, Билл, Николас и Дональд — выставили по две собаки, которых звали так же, как братьев.
    То есть двух собак звали Энди, двух Билл, двух — Николас и двух — Дональд.
    Из восьми собак было три лабрадора, три дога и два далматинца.
    Никто из братьев не держит двух собак одной породы.
    Нет двух собак одной породы с одинаковой кличкой.
    Никакая из собак Энди не носит имя Дональд и никакая из собак Николаса не зовется Энди.
    Нет дога по кличке Энди, и нет Лабрадора по кличке Дональд. У Билла нет лабрадора.
    Кто держит далматинцев? Какие у них клички?

    Собственными силами был получен такой код:

    DOMAINS
      хозяин=symbol
      порода=symbol
      кличка=symbol
      пес=пес(хозяин,порода,кличка)
      псы=пес* 
    
    PREDICATES
      nondeterm возможное_имя(хозяин)
      nondeterm возможная_порода(порода)
      nondeterm возможная_кличка(кличка)
      nondeterm входит(пес,псы)
      nondeterm условие(пес,пес)
      nondeterm условие(пес)
      nondeterm ответ(пес,пес)
    
    CLAUSES
    
      возможное_имя(энди). 
      возможное_имя(билл). 
      возможное_имя(николас). 
      возможное_имя(дональд).
    
      возможная_порода(лабрадор). 
      возможная_порода(дог). 
      возможная_порода(далматин).
    
      возможная_кличка(энди). 
      возможная_кличка(билл). 
      возможная_кличка(николас). 
      возможная_кличка(дональд).
    
    %Принадлежность элемента списку
    входит(Элемент,[Элемент|_]).
      входит(Элемент,[_|Хвост]):-входит(Элемент,Хвост).
    
    %Никто из братьев не держит двух собак одной породы.
    условие(пес(Хозяин,Порода1,_),пес(Хозяин,Порода2,_)):-
      not(Порода1=Порода2).
    
    %Нет двух собак одной породы с одинаковой кличкой.
    условие(пес(_,Порода,Кличка1),пес(_,Порода,Кличка2)):-
    	not(Кличка1=Кличка2).
    	
    %Никакая из собак Энди не носит имя Дональд
    условие(пес(энди,_,Кличка)):-
      not(Кличка=дональд).
    
    %Никакая из собак Николаса не зовется Энди
    условие(пес(николас,_,Кличка)):-
      not(Кличка=энди).
    	
    %Нет дога по кличке Энди
    условие(пес(_,Порода,Кличка)):-
      Порода=дог, not(Кличка=энди).
    	
    %Нет Лабрадора по кличке Дональд. 
    условие(пес(_,Порода,Кличка)):-
      Порода=лабрадор, not(Кличка=дональд).
    	
    %У Билла нет лабрадора
    условие(пес(бил,Порода,_)):-
      not(Порода=лабрадор).
    	
    ответ(пес(Хозяин1,далматин,Кличка1),пес(Хозяин2,далматин,Кличка2)):-
      %Генерация гипотезы
      возможное_имя(Хозяин1), возможная_кличка(Кличка1),
      возможное_имя(Хозяин2), возможная_кличка(Кличка2),
      Кличка1<>Кличка2, Хозяин1<>Хозяин2,
      условие(пес(Хозяин1,далматин,Кличка1)),
      условие(пес(Хозяин2,далматин,Кличка2)),
    	
      возможная_порода(Порода1э), возможная_порода(Порода2э),
      возможная_порода(Порода1б), возможная_порода(Порода2б),
      возможная_порода(Порода1н), возможная_порода(Порода2н),
      возможная_порода(Порода1д), возможная_порода(Порода2д),
    	
      возможная_кличка(Кличка1э), возможная_кличка(Кличка2э),
      возможная_кличка(Кличка1б), возможная_кличка(Кличка2б),
      возможная_кличка(Кличка1н), возможная_кличка(Кличка2н),
      возможная_кличка(Кличка1д), возможная_кличка(Кличка2д),
    	
      Псы=[пес(энди,Порода1э,Кличка1э),
        пес(энди,Порода2э,Кличка2э),
        пес(билл,Порода1б,Кличка1б),
        пес(билл,Порода2б,Кличка2б),
        пес(николас,Порода1н,Кличка1н),
        пес(николас,Порода2н,Кличка2н),
        пес(дональд,Порода1д,Кличка1д),
        пес(дональд,Порода2д,Кличка2д)],	
      %Проверка
      условие(пес(энди,Порода1э,Кличка1э),пес(энди,Порода1э,Кличка1э)),
      условие(пес(билл,Порода1б,Кличка1б),пес(билл,Порода2б,Кличка2б)),
      условие(пес(николас,Порода1н,Кличка1н),пес(николас,Порода2н,Кличка2н)),
      условие(пес(дональд,Порода1д,Кличка1д),пес(дональд,Порода2д,Кличка2д)),
      условие(пес(энди,Порода1э,Кличка1э)),
      условие(пес(энди,Порода2э,Кличка2э)),
      условие(пес(билл,Порода1б,Кличка1б)),
      условие(пес(билл,Порода2б,Кличка2б)),
      условие(пес(николас,Порода1н,Кличка1н)),
      условие(пес(николас,Порода1н,Кличка1н)),
      условие(пес(дональд,Порода1д,Кличка1д)),
      условие(пес(дональд,Порода2д,Кличка2д)),
      входит(пес(Хозяин1,далматин,Кличка1),Псы),
      входит(пес(Хозяин2,далматин,Кличка2),Псы).
    	
    Goal
      ответ(пес(Чей1,Порода1,Кличка1),пес(Чей2,Порода2,Кличка2)).

    Логика такая: мы предполагаем, что есть два далматина и задаем им случайных хозяев и клички. Также мы формируем полный список псов и прогоняем его через все условия, после чего проверяем входят ли те два далматина в этот список.
    Проблема судя по всему такая, что элементы списка как-то странно проходят через условия (или даже вообще не проверяются). Скорее всего я не понимаю чего-то важного в работе Prolog.
    Очень рассчитываю на помощь. Знаю что такая задача уже когда-то решалась, и можно найти на разных форумах, но преподаватель очень тщательно проверяет на плагиат, и уже один раз заворачивал, если вы сможете подсказать как доделать мою задумку, или скорректировать ее буду очень признательна.

    P.S. также пыталась решить формируя список хозяев, а не псов:

    DOMAINS
    имя=symbol
    порода=symbol
    кличка=symbol
    хозяин=хозяин(имя,порода,кличка,порода,кличка)
    братья=хозяин*
    
    PREDICATES
    nondeterm возможная_порода(порода)
    nondeterm возможная_кличка(кличка)
    nondeterm владелец(хозяин)
    nondeterm ответ(братья)
    
    CLAUSES
    
    возможная_порода(лабрадор). возможная_порода(дог). возможная_порода(далматин).
    
    возможная_кличка(энди). возможная_кличка(билл). возможная_кличка(николас). возможная_кличка(дональд).
    
    %Никто из братьев не держит двух собак одной породы.
    владелец(хозяин(_,Порода1,_,Порода2,_)):-
      not(Порода1=Порода2).
    	
    %Никакая из собак Энди не носит имя Дональд
    владелец(хозяин(энди,_,Кличка1,_,Кличка2)):-
      not(Кличка1=дональд), not(Кличка2=дональд).
    
    %Никакая из собак Николаса не зовется Энди
    владелец(хозяин(николас,_,Кличка1,_,Кличка2)):-
      not(Кличка1=энди), not(Кличка2=энди).
    	
    %Нет дога по кличке Энди
    владелец(хозяин(_,Порода1,Кличка1,Порода2,Кличка2)):-
      Порода1=дог, not(Кличка1=энди);
      Порода2=дог, not(Кличка2=энди).
    	
    %Нет Лабрадора по кличке Дональд. 
    владелец(хозяин(_,Порода1,Кличка1,Порода2,Кличка2)):-
      Порода1=лабрадор, not(Кличка1=дональд);
      Порода2=лабрадор, not(Кличка2=дональд).
    	
    %У Билла нет лабрадора
    владелец(хозяин(билл,Порода1,_,Порода2,_)):-
      not(Порода1=лабрадор), not(Порода2=лабрадор).
    	
    ответ(Братья):-
      Братья=[хозяин(энди,Порода1э,Кличка1э,Порода2э,Кличка2э),
        хозяин(билл,Порода1б,Кличка1б,Порода2б,Кличка2б),
        хозяин(николас,Порода1н,Кличка1н,Порода2н,Кличка2н),
        хозяин(дональд,Порода1д,Кличка1д,Порода2д,Кличка2д)],
      %Генерация гипотезы
      возможная_порода(Порода1э), возможная_порода(Порода2э),
      возможная_порода(Порода1б), возможная_порода(Порода2б),
      возможная_порода(Порода1н), возможная_порода(Порода2н),
      возможная_порода(Порода1д), возможная_порода(Порода2д),
    	
      возможная_кличка(Кличка1э), возможная_кличка(Кличка2э),
      возможная_кличка(Кличка1б), возможная_кличка(Кличка2б),
      возможная_кличка(Кличка1н), возможная_кличка(Кличка2н),
      возможная_кличка(Кличка1д), возможная_кличка(Кличка2д),
      %Проверка
    	
      владелец(хозяин(энди,Порода1э,Кличка1э,Порода2э,Кличка2э)),
      владелец(хозяин(билл,Порода1б,Кличка1б,Порода2б,Кличка2б)),
      владелец(хозяин(николас,Порода1н,Кличка1н,Порода2н,Кличка2н)),
      владелец(хозяин(дональд,Порода1д,Кличка1д,Порода2д,Кличка2д)).
    	
    Goal
    ответ(Братья).

    однако проблема точно такая-же.

  • #2767

    Эта часть правильная (только чуть-чуть упростил):

    имя(энди). 
    имя(билл). 
    имя(николас). 
    имя(дональд).
    
    порода(лабрадор). 
    порода(дог). 
    порода(далматин).
    
    кличка(X):-
      имя(X).

    Дальше Вам нужно сгенерировать клички и породы:

    кличка(КличкаПесЭнди_1).
    кличка(КличкаПесЭнди_2).
    порода(ПородаПесЭнди_1).
    порода(ПородаПесЭнди_2).
    % и так далее 

    Затем объединить их в список:

    Генерация = [
      имя_порода_кличка(энди, ПородаПесЭнди_1, КличкаПесЭнди_1),
      имя_порода_кличка(энди, ПородаПесЭнди_2, КличкаПесЭнди_2)
    ].

    И после этого, добавлять условия. Ваши условия я не смог понять (по крайней мере некоторые). Если вы уже сейчас запустите программу — получите множество вариантов решения, но с каждым условием оно будет сокращаться.
    Например, для условия: «Из восьми собак было три лабрадора, три дога и два далматинца.» вы можете использовать функцию count:

    count(Генерация, имя_порода_кличка(_, лабрадор, _), 3),
    count(Генерация, имя_порода_кличка(_, дог, _), 3),
    count(Генерация, имя_порода_кличка(_, далматин, _), 2).

    Для следующего: «Никто из братьев не держит двух собак одной породы.» — я бы написал отдельное правило:

    не_держит_собак_одной_породы(Генерация):-
      member(имя_порода_кличка(Имя, Порода, Кличка_1)),
      member(имя_порода_кличка(Имя, Порода, Кличка_2)),
      NOT(Кличка_1 = Кличка_2), !, fail.
    не_держит_собак_одной_породы(Генерация).

    Тут мы выбираем из списка при помощи функции member двух собак одного владельца (Имя в обоих вызовах будет связано с одним значением) и одной породы. Проверяем, чтобы это были разные собаки — у них разные клички. Если нам это удалось — выполняем отсечение для запрета поиска других решений и fail для завершения текущего решения неудачей. Если не удалось — то текущая Генерация не содержит братьев с собаками одной породы.

    Остальные правила проще и пишутся по аналогии. Попробуйте, если будут вопросы — задавайте.

Для ответа в этой теме необходимо авторизоваться.