Попытка диверсии – найти преступника.

      Комментарии к записи Попытка диверсии – найти преступника. отключены

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

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

    zageul
    Участник

    Необходимо решить задачу на Visual Prolog 5.2:

    Попытка диверсии

    На планету Дранак прилетел космический корабль, но не все местные жители этому обрадовались.
    Ночью неизвестный преступник прокрался к кораблю и хотел сломать систему подачи воздуха.
    На следующий день задержали троих подозреваемых. Каждый из них высказался три раза.
    Мы знаем, что все высказывания одного из подозреваемых – правда,
    все высказывания второго – ложь, а про то, насколько лжет третий, ничего не известно.
    Тем не менее преступника можно найти. Кто это?

    А: 1. Это сделал не я.
    2. Я всегда говорю правду.
    3. Мне не нравятся космические полеты.

    Б: 1. Это сделал не я.
    2. Я всегда говорю неправду.
    3. Мне не нравятся пришельцы из космоса.

    В: 1. Это сделал не я.
    2. Только одно из моих высказываний ложно.
    3. Мне нравятся гости из космоса.

    Получился такой код:

    DOMAINS
      имя = symbol
      номер = integer
    
    			
    PREDICATES
      nondeterm возможное_имя(имя)
      nondeterm сказал (имя, номер)
      nondeterm является_преступником (имя) 
      nondeterm говорит_правду (имя,номер)
      nondeterm говорит_ложь (имя,номер)
      nondeterm говорит_неизвестно (имя)
    	  
    	
    CLAUSES
      возможное_имя(а).
      возможное_имя(б).
      возможное_имя(в).
      % Высказывания
      % Это сделал не я.
      сказал (а,1):-
        not(является_преступником(а)).
    	
      % Мне не нравятся космические полеты.	
      сказал (а,2):-
        является_преступником(а).
    	
      % Я всегда говорю правду.	
      сказал (а,3):-
        сказал (а,3), сказал (а,1), сказал (а,2).
    	
      % Это сделал не я.	
      сказал (б,1):-
        not(является_преступником(б)).
    	
      %  Мне не нравятся пришельцы из космоса.	
      сказал (б,2):-
        является_преступником(б).
    	
      % Я всегда говорю неправду.	
      сказал (б,3):-
        not(сказал (б,3)), not(сказал (б,1)), not(сказал (б,2)).
    	
      % Это сделал не я.	
      сказал (в,1):-
        not(является_преступником(в)).
    	
      % Мне нравятся гости из космоса.	
      сказал (в,2):-
        not(является_преступником(в)).
    	
      % Только одно из моих высказываний ложно.	
      сказал (в,3):-
        not(сказал (в,1)), сказал (в,2), сказал (в,3);
        сказал (в,1), not(сказал (в,2)), сказал (в,3);
        сказал (в,1), сказал (в,2), not(сказал (в,3)).
    		
    		
      % Проверка правдивости высказывания в зависимости от того, кем является персонаж
      % все высказывания одного из подозреваемых - правда
      говорит_правду(Кто_сказал,Номер_высказывания):-
        сказал (Кто_сказал, Номер_высказывания).
    	
      % все высказывания второго - ложь 
      говорит_ложь(Кто_сказал,Номер_высказывания):-
        not(сказал (Кто_сказал, Номер_высказывания)).
    	
      % насколько лжет третий, ничего не известно.
      говорит_неизвестно(Кто_сказал):-
        сказал (Кто_сказал,1), сказал (Кто_сказал,2), сказал (Кто_сказал,3);
        сказал (Кто_сказал,1), сказал (Кто_сказал,2), not(сказал (Кто_сказал,3));
        сказал (Кто_сказал,1), not(сказал (Кто_сказал,2)), сказал (Кто_сказал,3);
        сказал (Кто_сказал,1), not(сказал (Кто_сказал,2)), not(сказал (Кто_сказал,3));
        not(сказал (Кто_сказал,1)), сказал (Кто_сказал,2), сказал (Кто_сказал,3);
        not(сказал (Кто_сказал,1)), сказал (Кто_сказал,2), not(сказал (Кто_сказал,3));
        not(сказал (Кто_сказал,1)), not(сказал (Кто_сказал,2)), сказал (Кто_сказал,3);
        not(сказал (Кто_сказал,1)), not(сказал (Кто_сказал,2)), not(сказал (Кто_сказал,3)).
    			
      % Поиск ответа задачи
      является_преступником(Преступник):-
        % Генерация гипотезы.
        возможное_имя(П), 
        возможное_имя(Л), not(Л=П),
        возможное_имя(Н), not(Н=П), not(Н=Л),			
        % Проверка высказываний
        говорит_правду(П,1),
        говорит_правду(П,2),
        говорит_правду(П,3),
        говорит_ложь(Л,1),
        говорит_ложь(Л,2),
        говорит_ложь(Л,3),
        говорит_неизвестно(Н).	
    GOAL
      является_преступником(Преступник).

    При попытке решения выплывает “PROGRAM ERROR. 1010”, подскажите пожалуйста с чем связана ошибка и как можно ее исправить.

  • #2657

    Ошибка “PROGRAM ERROR. 1010” говорит о переполнении стека, чаще всего это возникает при зацикливании (вечной рекурсии).
    Ваш код я не смог понять, так правило является_преступником принимает в качестве аргумента переменную Преступник, но в коде правила она не используется, т.е. при любом раскладе функция не вернет ничего более полезного чем неинициализированную переменную.

    Я не знаю точно в чем у вас ошибка, но зацикливание может быть например тут:

    сказал (в,3):-
        not(сказал (в,1)), сказал (в,2), сказал (в,3);
        сказал (в,1), not(сказал (в,2)), сказал (в,3);
        сказал (в,1), сказал (в,2), not(сказал (в,3)).

    Так как чтобы вычислить правило вы вызываете это же правило с точно таким же набором аргументов. Очевидно, выполнение зациклится, а т.к. используется рекурсия (т.е. вызовы функции, сохраняющие аргументы при каждом вызове в стек) – переполнится стек.

    Я предлагаю Вам посмотреть пример решения похожей задачи на правильные и ложные высказывания и попробовать что-то исправить. В любом случае – пишите о результатах, даже если совсем ничего не получится, мы поможем.

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