Логическая задача: три рыболова-гиперборейца

      Комментарии к записи Логическая задача: три рыболова-гиперборейца отключены

Главная Форумы Программирование Помощь с решением задач на Prolog Решение головоломок на Prolog Логическая задача: три рыболова-гиперборейца

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

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

    questioner
    Участник

    Дана логическая задача, нужно решить на Visual Prolog 5.2:

    Три гиперборейца-рыболова вернулись с рыбалки. Известно, что один из этих троих – сорореанец, который всегда говорит правду, второй – норореанец, который всегда лжет, а третий – мидрореанец, который говорит правду и лжет через раз, но первый ответ может быть и правдой, и ложью. Когда их спросили, много ли рыбы удалось поймать, один из троих отказался отвечать, а двое сказали вот что:

    А: 1. В наши сети попалась мало рыбы.
    2. Б забрасывал и вытаскивал сеть.
    Б: 1. Я управлял лодкой, а не занимался сетью.
    2. Мы наловили много рыбы.
    3. Если бы В уговорили ответить, он бы три раза повторил, что он сорореанец.

    Кто и троих сорореанец, кто мидрореанец и кто норореанец?

    Я смотрел примеры решения других логических задач, но это не помогло, т.к. второй участник говорит о том, что сказал бы третий. Как это оформить?

  • #2791

    Сначала описываем типы данных задачи:

    1. who_d — имена трех участников;
    2. type_d — типы участников;
    3. bool_d — тип высказывания (истинное/ложное);
    4. amount_d — количество (много/мало);
    5. activity_d — деятельность (управление лодкой/сетью);
    6. state_d — высказывание участника, используется также как состояние программы. Представляет собой количество рыбы или активность участника, или тип участника, или набор высказываний другого участника;
    7. states_d — список высказываний;
    8. who_say_d — составной тип, объединяющий участника и набор высказываний;
    9. who_says_d, types_d, activities_d, amounts_d — списки типов, высказываний, деятельности и количеств.

    На языке Visual Prolog это можно записать следующим образом:

    DOMAINS
    	who_d = a;b;c
    	type_d = soreanec;nororeanec;midroreanec
    	
    	bool_d = true;false
    	
    	amount_d = little;much
    	activity_d = drifter; boater
    	
    	state_d = fish(amount_d);who_activity(who_d, activity_d);who_type(who_d, type_d);who_says(who_d, states_d)
    	states_d = state_d*
    	
    	who_say_d = who_says(who_d, states_d)
    	
    	who_says_d = who_say_d*
    	types_d = type_d*
    	activities_d = activity_d*
    	amounts_d = amount_d*

    Теперь опишем предикаты для генерации состояний программы:

    PREDICATES
    	nondeterm type(type_d)
    	nondeterm activity(activity_d)
    	nondeterm fish_amount(state_d)
    CLAUSES
      	type(Type):-
      		Types = [soreanec, nororeanec, midroreanec],
      		member(Type, Types).
      		
      	activity(Activity):-
      		Activities = [drifter, boater],
      		member(Activity, Activities).
    	
      	fish_amount(Amount):-
    		Amounts = [fish(little), fish(much)],
    		member(Amount, Amounts).

    В данном случае предикаты используют функцию member для получения элемента списка. Функция является недетерминированной и возвратит по очереди каждый элемент (решений будет столько, сколько элементов в списке).
    Если мы сейчас запросим генерацию состояний (не повторяющихся типов рыболовов, активностью участника b и количеством рыбы), то получим 24 варианта:

    GOAL 
    	type(A), type(B), type(C),
    	NOT(A = B), NOT(A = C), NOT(B = C),
    
    	activity(BActivity),
    	fish_amount(FishAmount).
    

    logical_problem_three_fisherman

    Теперь нужно описать высказывания участников и запустить проверку их соответствия состоянию программы:

    	check_says(
    		[		%	WhoSays
    			who_says(a, [fish(little), who_activity(b, drifter)]),
    			who_says(b, [who_activity(b, boater), fish(much), 
    				who_says(c, [
    					who_type(c, soreanec), who_type(c, soreanec), who_type(c, soreanec)
    				])
    			])
    		],
    		[		%	States
    			who_type(a, A), who_type(b, B), who_type(c, C), who_activity(b, BActivity), FishAmount
    		]
    	).

    Тут показано как можно записать высказывания и состояния. Но кроме этого нам потребуется объявить функцию check_says и ряд вспомогательных функций:

    	nondeterm check_says(who_says_d, states_d)
    	
    	nondeterm check_say(type_d, states_d, states_d)
    	nondeterm check_midroreanec_say(bool_d, states_d, states_d)
    	
    	nondeterm true_say(state_d, states_d)
    	nondeterm false_say(state_d, states_d)

    1. check_says проверяет набор соответствие состояний набору высказываний;
    2. check_say проверяет единственное высказывание с учетом типа того, кто его сделал (если сорореанец — то высказывание должно быть истинно и т.п.);
    3. true_say и false_say проверяют истинность и ложность высказывания;
    4. check_midroreanec_say проверяет высказывания мидрореанца. Если первое ложно — то от второго потребует истинность и наоборот.

    Реализация функций на Visual Prolog:

      	check_says([], _States):-!.
      	check_says([who_says(Who, Says)|TailSays], States):-
      		member(who_type(Who, Type), States), 
      		check_say(Type, Says, States),
      		check_says(TailSays, States).
      		
      	true_say(who_says(Who, Says), States):-
      		member(who_type(Who, Type), States), 
      		check_say(Type, Says, States).
      	true_say(Say, States):- 
      		member(Say, States).
      		
      	false_say(Say, States):-
      		true_say(Say, States), !, fail.
      	false_say(Say, States).
      		
      	check_say(_Type, [], _States):-!.
      	check_say(soreanec, [HeadSay|TailSays], States):-
      		true_say(HeadSay, States), 
      		check_say(soreanec, TailSays, States).
      	check_say(nororeanec, [HeadSay|TailSays], States):-
      		false_say(HeadSay, States), 
      		check_say(nororeanec, TailSays, States).
      	check_say(midroreanec, [HeadSay|TailSays], States):-
      	 	true_say(HeadSay, States), !,
      		check_midroreanec_say(false, TailSays, States);
      		check_midroreanec_say(true, TailSays, States).
      		
      	check_midroreanec_say(_Bool, [], _States):-!.
      	check_midroreanec_say(true, [HeadSay|Says], States):-
      		true_say(HeadSay, States), !,
      		check_midroreanec_say(false, Says, States).
      	check_midroreanec_say(false, [HeadSay|Says], States):-
      	 	false_say(HeadSay, States), !,
      		check_midroreanec_say(true, Says, States).

    Теперь интерпретатор выдаст нам единственное решение:
    A=soreanec, B=nororeanec, C=midroreanec, BActivity=drifter, FishAmount=fish(little)

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