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

#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)