Каждое воскресенье в нашей компании принято устраивать весёлые викторины, это одна из них.
Чтобы найти убийцу мистера Бодди, нужно узнать, где находился каждый человек и какое оружие было в комнате. Подсказки разбросаны по всей викторине (вы не можете ответить на первый вопрос, пока не прочитаете все десять).
Я тащусь от таких головоломок (вообще-то почти от любых головоломок). Они могли бы занять часы и часы размышлений, но всегда на помощь приходит Prolog! Посмотрим, как он помогает решить такие задачи на рассуждения.
Суть Prolog — в констатации фактов, составлении фактов и их запросе.
Создание файла
После изложения фактов в базе знаний можем пойти дальше и задавать вопросы об истинности фактов, а также о том, какие выводы можно из них сделать.
Можем составлять и более сложные вопросы. Например, кто дружит с Джоном или кто любит Джулию.
Мы установили дружественные отношения Джона с Джулией (
Prolog помогает избежать дублирования с помощью правил логического заключения:
Правило истинно, если все внутренние утверждения истинны (перечислены и логически сложены через запятую).
Хорошо, теперь у нас есть все необходимые знания. Потренируемся на раскраске карты.
Начнём с известной математической проблемы. Требуется, чтобы ни у каких смежных областей не было одинакового цвета.

Поэтому рассуждения должны быть такие, у нас есть три вещи:
Определим домен наших областей (красный, зелёный, синий).
Это всё.
Здесь мы определяем решение как правило
Prolog продолжит генерировать значения, пока не найдёт вариант, удовлетворяющий правилу с учётом ограничений.
… но мы здесь не картинки раскрашиваем, а ищем убийцу.
Для начала, представим подозреваемых. Есть три мужчины (Джордж, Джон, Роберт) и три женщины (Барбара, Кристина, Иоланда). Каждый человек находится в отдельной комнате (ванная, столовая, кухня, гостиная, кладовая, кабинет). В каждой комнате найдено подозрительное оружие (сумка, огнестрельное оружие, газ, нож, яд, верёвка).
Кого нашли на кухне?
Из этого можно сделать вывод, что у нас пять доменов:
Правило
Мы начинаем с определения правила убийцы с уникальными людьми в местах и уникальных людей, имеющих оружие, и теперь будет указывать отношение между людьми в местах с теми, кто имеет оружие
Обратите внимание, что у нас по-прежнему шесть подозреваемых.
Чтобы легко рассуждать о переменных, таких как ванная, столовая, огнестрельное оружие, газ, мы сразу определяем:
Теперь продолжаем добавлять ограничения после последней запятой в правиле
При мужчине на кухне нет верёвки, ножа или сумки. Оружие не является огнестрельным. Какое оружие найдено на кухне?
Здесь мы говорим, что переменная
Подсказка 2. Барбара либо в кабинете, либо в ванной, а Иоланда — в другой комнате из двух названных. В какой комнате нашли Барбару?
Таким образом, мы можем сказать, что
Человек с сумкой — это ни Барбара, ни Джордж, и он не был ни в ванной, ни в столовой. У кого была сумка?
Женщина с верёвкой найдена в кабинете. Кто это?
Подсказка 5. Оружие в гостиной принадлежит либо Джону, либо Джорджу. Какое оружие в гостиной?
Ножа не было в столовой. Где был нож?
Подсказка 7. Иоланды не было ни в кабинете, ни в кладовой. Какое оружие в комнате у Иоланды?
У Джорджа найдено огнестрельное оружие.
Было обнаружено, что мистера Бодди отравили газом в кладовой. Подозреваемый в той комнате был убийцей. Кто это?
Устанавливаем соответствие для газа, кладовой и убийцы, затем используем
Код опубликован здесь. Вероятно, он мог быть намного лучше, поскольку я не эксперт в Прологе :)
Загадка
Чтобы найти убийцу мистера Бодди, нужно узнать, где находился каждый человек и какое оружие было в комнате. Подсказки разбросаны по всей викторине (вы не можете ответить на первый вопрос, пока не прочитаете все десять).
- Для начала, представим подозреваемых. Есть три мужчины (Джордж, Джон, Роберт) и три женщины (Барбара, Кристина, Иоланда). Каждый человек находится в отдельной комнате (ванная, столовая, кухня, гостиная, кладовая, кабинет). В каждой комнате найдено подозрительное оружие (сумка, огнестрельное оружие, газ, нож, яд, верёвка). Вопрос: кого нашли на кухне?
- Подсказка 1. При мужчине на кухне нет ни верёвки, ни ножа, ни сумки. Оружие не является огнестрельным. Вопрос: какое оружие найдено на кухне?
- Подсказка 2. Барбара либо в кабинете, либо в ванной, а Иоланда — в другой комнате из двух названных. В какой комнате нашли Барбару?
- Подсказка 3. Человек с сумкой — это ни Барбара, ни Джордж, и он не был ни в ванной, ни в столовой. У кого была сумка?
- Подсказка 4. Женщина с верёвкой найдена в кабинете. Кто это?
- Подсказка 5. Оружие в гостиной принадлежит либо Джону, либо Джорджу. Какое оружие в гостиной?
- Подсказка 6. Ножа не было в столовой. Где был нож?
- Подсказка 7. Иоланды не было ни в кабинете, ни в кладовой с соответствующим оружием для этих комнат. Какое оружие у Иоланды?
- Подсказка 8. У Джорджа найдено огнестрельное оружие. В какой комнате?
- Было обнаружено, что мистера Бодди отравили газом в кладовой. Подозреваемый в той комнате был убийцей. Кто же это?
Я тащусь от таких головоломок (вообще-то почти от любых головоломок). Они могли бы занять часы и часы размышлений, но всегда на помощь приходит Prolog! Посмотрим, как он помогает решить такие задачи на рассуждения.
Prolog 101
Установка SWI-Prolog
~> swipl Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 6.6.6) Copyright (c) 1990-2013 University of Amsterdam, VU Amsterdam SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. Please visit http://www.swi-prolog.org for details. For help, use ?- help(Topic). or ?- apropos(Word). ?- write('Hello, World!'). Hello, World! true. ?- write('Hello,'), nl, write('world'). Hello, world true. ?- X is 3*4 + 2. X = 14.
swipl— программа-интерпретатор Prologwriteназывается функтором, а представлениеwrite/1означает, что он принимает 1 аргумент (та же концепция в Erlang и Elixir для добавления количества аргументов к имени функции)nlиспользуется для печати новой строки- последовательность команд разделяется запятыми, которые также заменяют оператор AND
- за оператором присвоения
isследует математическое выражение - переменные пишутся заглавными
X, а не x
База знаний
Суть Prolog — в констатации фактов, составлении фактов и их запросе.
Создание файла
hello.pl:friend(john, julia). friend(john, jack). friend(julia, sam). friend(julia, molly). loves(john, julia). loves(julia, sam). loves(sam, julia). male(brad). male(john). male(jim). male(alfred). female(marry). child(brad, alfred). child(john, jim). child(john, marry).
- для загрузки используем
[hello].: обратите внимание на точку в конце listingперечисляет все факты в базе знаний
?- [hello]. % hello compiled 0.00 sec, 3 clauses true. ?- listing(friend). friend(john, julia). friend(john, jack). friend(julia, sam). friend(julia, molly). true. ?- listing(loves). loves(john, julia). loves(julia, sam). loves(sam, julia). true.
Запрос фактов
После изложения фактов в базе знаний можем пойти дальше и задавать вопросы об истинности фактов, а также о том, какие выводы можно из них сделать.
?- friend(john, julia). true . ?- friend(john, jack). true. ?- loves(john, julia). true. ?- loves(john, sam). false.
Можем составлять и более сложные вопросы. Например, кто дружит с Джоном или кто любит Джулию.
?- friend(john, Who). Who = julia ; Who = jack.
?- listing(child). child(brad, alfred). child(john, jim). child(john, mary). true. ?- child(john, X). X = jim ; X = mary.
Джон во френдзоне?
Мы установили дружественные отношения Джона с Джулией (
friend(john, julia)), но для Prolog это не значит, что Джулия дружит с Джоном: нужно добавить ещё один факт friend(julia, john). Также мы уже указали, у кого какие дети, и явно не хотим дублировать код, отдельно указывая родителей каждого ребёнка. Мы не хотим писать что-то вродеchild(brad, alfred). child(john, jim). child(john, mary). parent(alfred, brad). parent(jim, john). parent(mary, john).
Prolog помогает избежать дублирования с помощью правил логического заключения:
rule :- stmt1, stmt2,...
Правило истинно, если все внутренние утверждения истинны (перечислены и логически сложены через запятую).
friend(X, Y) :- friend(Y,X). parent(X, Y) :- child(Y,X). father(X, Y) :- child(Y,X), male(X). mother(X, Y) :- child(Y,X), female(X). friendzoned(X) :- loves(X, Y), \+ loves(Y,X).
- правило
friend(X,Y)справедливо приfriend(Y,X) parent(X,Y)справедливо при установленномchild(Y,X)father(X,Y)справедливо при установленныхparent(X,Y)иmale(X)mother(X,Y)справедливо при установленныхparent(X,Y)иfemale(X)friendzoned(X)справедливо, если X любитSOMEONE Y, а Y не любит X (заметили скрытую переменную Y?)
?- friend(julia, john). true . ?- male(jim). true. ?- parent(jim,X). X = john. ?- father(jim, X). X = john. ?- mother(X, john). X = marry. ?- mother(marry,X). X = john. ?- mother(marry, john). true. ?- loves(julia, X). X = sam. ?- friendzoned(julia). false. ?- friendzoned(john). true.
Хорошо, теперь у нас есть все необходимые знания. Потренируемся на раскраске карты.
Раскраска карты
Начнём с известной математической проблемы. Требуется, чтобы ни у каких смежных областей не было одинакового цвета.

Поэтому рассуждения должны быть такие, у нас есть три вещи:
- Переменные — области, которые мы хотим раскрасить: A, B, С, D, Е.
- Домен — диапазон значений, которые можно присвоить переменным: красный, синий, зелёный.
- Ограничение, что смежные области не могут быть одинакового цвета.
Домен
Определим домен наших областей (красный, зелёный, синий).
color(red). color(green). color(blue).
Это всё.
Спрашиваем решение
colorify(A,B,C,D,E) :- color(A), color(B), color(C), color(D), color(E), \+ A=B, \+ A=C, \+ A=D, \+ A=E, \+ B=C, \+ C=D, \+ D=E.
Здесь мы определяем решение как правило
colorify с пятью переменными А, B, С, D, Е, а внутри правила назначаем доменный цвет (красный, синий, зелёный) для переменных и устанавливаем ограничения, что А не равно B, не равно С… и т. д.\+ X=Y означает, что X не равно YProlog продолжит генерировать значения, пока не найдёт вариант, удовлетворяющий правилу с учётом ограничений.
?- [mapcoloring] | . true. ?- colorify(A,B,C,D,E) | . A = red, B = D, D = green, C = E, E = blue ; A = red, B = D, D = blue, C = E, E = green ; A = green, B = D, D = red, C = E, E = blue ; A = green, B = D, D = blue, C = E, E = red ; A = blue, B = D, D = red, C = E, E = green ; A = blue, B = D, D = green, C = E, E = red
color(red). color(green). color(blue). colorify(A,B,C,D,E) :- color(A), color(B), color(C), color(D), color(E), \+ A=B, \+ A=C, \+ A=D, \+ A=E, \+ B=C, \+ C=D, \+ D=E.
… но мы здесь не картинки раскрашиваем, а ищем убийцу.
Убийство
Для начала, представим подозреваемых. Есть три мужчины (Джордж, Джон, Роберт) и три женщины (Барбара, Кристина, Иоланда). Каждый человек находится в отдельной комнате (ванная, столовая, кухня, гостиная, кладовая, кабинет). В каждой комнате найдено подозрительное оружие (сумка, огнестрельное оружие, газ, нож, яд, верёвка).
Кого нашли на кухне?
Домен
Из этого можно сделать вывод, что у нас пять доменов:
man, woman, person или подозреваемый, location и weapons, а наши переменные (A, B, C, D, E, F) должны представлять и человека, и место, и оружие с некоторыми ограничениями, которые будут выявлены в предстоящих подсказках.man(george). man(john). man(robert). woman(barbara). woman(christine). woman(yolanda). person(X):- man(X). person(X):- woman(X). location(bathroom). location(dining). location(kitchen). location(livingroom). location(pantry). location(study). weapon(bag). weapon(firearm). weapon(gas). weapon(knife). weapon(poison). weapon(rope).
Правило
uniq_ppl генерирует уникальные значения для наших переменных.uniq_ppl(A,B,C,D,E,F):- person(A), person(B), person(C), person(D), person(E), person(F), \+A=B, \+A=C, \+A=D, \+A=E, \+A=F, \+B=C, \+B=D, \+B=E, \+B=F, \+C=D, \+C=E, \+C=F, \+D=E, \+D=F, \+E=F.
Решение
Мы начинаем с определения правила убийцы с уникальными людьми в местах и уникальных людей, имеющих оружие, и теперь будет указывать отношение между людьми в местах с теми, кто имеет оружие
Обратите внимание, что у нас по-прежнему шесть подозреваемых.
Вступление
murderer(X) :- uniq_ppl(Bathroom, Dining, Kitchen, Livingroom, Pantry, Study), uniq_ppl(Bag, Firearm, Gas, Knife, Poison, Rope),
Чтобы легко рассуждать о переменных, таких как ванная, столовая, огнестрельное оружие, газ, мы сразу определяем:
- Ванная — оно же подозреваемый (мужчина или женщина) в ванной
- Огнестрельное оружие — оно же подозреваемый (мужчина или женщина) с огнестрельным оружием
- и так далее… можете представить это как решётку
Теперь продолжаем добавлять ограничения после последней запятой в правиле
murderer.Подсказка 1
При мужчине на кухне нет верёвки, ножа или сумки. Оружие не является огнестрельным. Какое оружие найдено на кухне?
% 2. Clue 1: The man in the kitchen was not found with the rope, knife, or bag. % Which weapon, then, which was not the firearm, was found in the kitchen? man(Kitchen), \+Kitchen=Rope, \+Kitchen=Knife, \+Kitchen=Bag, \+Kitchen=Firearm,
Здесь мы говорим, что переменная
Kitchen удовлетворяет факту man (определено в нашем домене), и заявляем, что кем бы ни был человек на кухне, у него нет ничего из перечисленного: Rope, Knife, Bag, Firearm.Подсказка 2
Подсказка 2. Барбара либо в кабинете, либо в ванной, а Иоланда — в другой комнате из двух названных. В какой комнате нашли Барбару?
Таким образом, мы можем сказать, что
woman есть и в кабинете, и в ванной, И это не Кристина, а также вычёркиваем остальные варианты для Барбары и Иоланды (кухня, столовая, гостиная, кладовая).% % 3. Clue 2: Barbara was either in the study or the bathroom; Yolanda was in the other. % % Which room was Barbara found in? woman(Bathroom), woman(Study), \+christine=Bathroom, \+christine=Study, \+barbara=Dining, \+barbara=Kitchen, \+barbara=Livingroom, \+barbara=Pantry,
Подсказка 3
Человек с сумкой — это ни Барбара, ни Джордж, и он не был ни в ванной, ни в столовой. У кого была сумка?
% % 4. Clue 3: The person with the bag, who was not Barbara nor George, was not in the bathroom nor the dining room. % % Who had the bag in the room with them? \+barbara=Bag, \+george=Bag, \+Bag=Bathroom, \+Bag=Dining,
Подсказка 4
Женщина с верёвкой найдена в кабинете. Кто это?
% % 5. Clue 4: The woman with the rope was found in the study. % % Who had the rope? woman(Rope), Rope=Study,
Подсказка 5
Подсказка 5. Оружие в гостиной принадлежит либо Джону, либо Джорджу. Какое оружие в гостиной?
man in Livingroom Livingroom isn’t robert % % 6. Clue 5: The weapon in the living room was found with either John or George. % % What weapon was in the living room? man(Livingroom), \+Livingroom=robert,
Подсказка 6
Ножа не было в столовой. Где был нож?
% % 7. Clue 6: The knife was not in the dining room. % % So where was the knife? \+Knife=Dining,
Подсказка 7
Подсказка 7. Иоланды не было ни в кабинете, ни в кладовой. Какое оружие в комнате у Иоланды?
% % 8. Clue 7: Yolanda was not with the weapon found in the study nor the pantry. % % What weapon was found with Yolanda? \+yolanda=Pantry, \+yolanda=Study,
Подсказка 8
У Джорджа найдено огнестрельное оружие.
% % 9. Clue 8: The firearm was in the room with George. % % In which room was the firearm found? Firearm=george,
Подсказка 9
Было обнаружено, что мистера Бодди отравили газом в кладовой. Подозреваемый в той комнате был убийцей. Кто это?
% % 10. It was discovered that Mr. Boddy was gassed in the pantry. The suspect found in that room was the murderer. % % Who, then, do you point the finger towards? Pantry=Gas, Pantry=X, write("KILLER IS :"), write(X), nl, writeanswers(Bathroom, Dining, Kitchen, Livingroom, Pantry, Study, Bag, Firearm, Gas, Knife, Poison, Rope).
Устанавливаем соответствие для газа, кладовой и убийцы, затем используем
write для вывода ответов writeanswers.writeanswers(Bathroom, Dining, Kitchen, Livingroom, Pantry, Study, Bag, Firearm, Gas, Knife, Poison, Rope):- write("Bathroom: "), write(Bathroom), nl, write("Dining: "), write(Dining), nl, write("Livingroom: "), write(Livingroom), nl, write("Pantry: "), write(Pantry), nl, write("Study: "), write(Study), nl, write("Kitchen: "), write(Kitchen), nl, write("Knife: "), write(Knife), nl, write("Gas: "), write(Gas), nl, write("Rope: "), write(Rope), nl, write("Bag: "), write(Bag), nl, write("Poison: "), write(Poison), nl, write("Firearm: "), write(Firearm), nl.
Кто убийца?
?- [crime2]. true. ?- murderer(X). KILLER IS :christine Bathroom: yolanda Dining: george Livingroom: john Pantry: christine Study: barbara Kitchen: robert Knife: yolanda Gas: christine Rope: barbara Bag: john Poison: robert Firearm: george X = christine ;
Код опубликован здесь. Вероятно, он мог быть намного лучше, поскольку я не эксперт в Прологе :)
