Головоломка Эйнштейна в прологе

#prolog #zebra-puzzle

#пролог #зебра-головоломка

Вопрос:

Я пытался решить головоломку Эйнштейна — издание для пяти друзей — в прологе, но я застрял. Кажется, я не могу найти ошибку в своем коде или что сделать, чтобы ее решить. Цель состоит в том, чтобы написать программу Prolog, которая правильно определяет, какую головоломку каждый из них сделал, тему головоломки и сколько времени им потребовалось для ее завершения — решение (человек, Вид, время, тема)

Я также получаю эту ошибку: uncaught exception: error(existence_error(procedure,members/3),clue1/0)

Я думаю, это как-то связано с участниками?

база знаний:

  1. Пятеро друзей — это Кристал, Энджи, та, кто решала головоломку с внешним пространством, та, кому потребовалось 30 минут, чтобы завершить головоломку, и та, кто выполнял поиск по слову.

  2. Итан либо закончил плитки с буквами за 90 минут, либо сделал головоломку на зимнюю тематику за 20 минут.

  3. У Дерека и того, кто решал логическую головоломку, одному потребовалось 45 минут, в то время как другой решал головоломку на тему фильмов. Мальчикам потребовалось наименьшее и наибольшее время, чтобы закончить свои головоломки.

  4. Ник потратил меньше 40 минут, работая над своей головоломкой, которая не была визуальным судоку. Энджи потратила более 40 минут, работая над своей головоломкой с котом.

  5. Девушка, которая потратила 60 минут, работая над спортивной головоломкой, НЕ сделала головоломки. головоломка была сделана мальчиком за меньшее время, чем тот, кто решал логическую головоломку, но больше времени, чем тот, кто выполнял поиск по слову.

  6. На выполнение визуального судоку либо уходил час, либо оно было тематическим. Дерек не делал головоломку на зимнюю тематику (которая не была поиском по слову).

Вот мой код:

 woman(krystal).
woman(angie).
man(dereck).
man(ethan).
man(nick).

kind(word).
kind(sudoku).
kind(letter).
kind(jigsaw).
kind(logic).

time(30).
time(90).
time(20).
time(45).
time(60).

theme(outerspace).
theme(winter).
theme(movies).
theme(sports).
theme(cat).

members([],_).
members([M|Ms],Xs) :- select(M,Xs,Ys),members(Ms,Ys).


clue1(Game) :- members([[krystal,_,_,_,_], [angie,_,_,_], [P,_,30,_], [P,word,_,_], [P,_,_,outerspace]], Game, man(P)).
clue2(Game) :- members([[krystal,_,_,_,_], [angie,_,_,_],[P,_,_,outerspace], [P,_,_,outerspace], [P,_,_,outerspace]], Game, man(P)).
clue3(Game) :- members([[krystal,_,_,_,_], [angie,_,_,_],[P,_,30,_], [P,_,30,_], [P,_,30,_]], Game, man(P)).
clue4(Game) :- members([[krystal,_,_,_,_], [angie,_,_,_],[P,_,_,word], [P,_,_,word], [P,_,_,word]], Game, man(P)).
clue5(Game) :- member([ethan, letter, 90,_], Game).
clue5(Game) :- member([ethan, _, 20, winter], Game).
clue6(Game) :- member([P, _, 20, _], Game, man(P)).
clue6(Game) :- member([P, _, 90, _], Game), man(P).
clue7(Game) :- member([dereck, _, 45, _], Game).
clue7(Game) :- member([dereck, _, _, movies], Game).
clue8(Game) :- member([_, logic, 45, _], Game).
clue8(Game) :- member([_, logic, _, sport], Game).
clue9(Game) :- member([nick, _, 30, _], Game).
clue9(Game) :- member([nick, _, 20, _], Game).
clue10(Game) :- member([P, sudoku, _, _], Game,  nick(P)).
clue11(Game) :- member([angie, _, 45, cat], Game).
clue11(Game) :- member([angie, _, 60, cat], Game).
clue11(Game) :- member([angie, _, 90, cat], Game).
clue12(Game) :- member([P, Q, 60, sport], Game, girl(P),  sport(Q)).

clue13(Game) :- member([P, jigsaw, Q, _], Game, man(P),  time(20)).
clue13(Game) :- member([P, jigsaw, Q, _], Game, man(P),  time(90)).
clue13(Game) :- member([P, jigsaw, 30, _], Game, man(P)), member([_, word, 20, _], Game), (member([_, logic, 40, _], Game); member([_, logic, 60, _], Game); member([_, logic, 90, _], Game)).
clue13(Game) :- member([P, jigsaw, 45, _], Game, man(P)), (member([_, word, 20, _], Game); member([_, word, 30, _], Game)), (member([_, logic, 60, _], Game); member([_, logic, 90, _], Game)).
clue13(Game) :- member([P, jigsaw, 60, _], Game, man(P)), (member([_, word, 20, _], Game); member([_, word, 30, _], Game); member([_, word, 46, _], Game)), member([_, logic, 90, _], Game).

clue14(Game) :- member([_, sudoku, 60, _], Game).
clue14(Game) :- member([_, sudoku, _, outerspace], Game).
clue15(Game) :- member([P, _, _, winter], Game,  dereck(P)).
clue16(Game) :- member([_,word,_,P], Game,  winter(P)).

clue17(Game, A,B,C,D) :- member([A,B,C,D], Game).

solution(A,B,C,D) :-
    Game = [A,B,C,D],
    clue1(Game),
    clue2(Game),
    clue3(Game),
    clue4(Game),
    clue5(Game),
    clue6(Game),
    clue7(Game),
    clue8(Game),
    clue9(Game),
    clue10(Game),
    clue11(Game),
    clue12(Game),
    clue13(Game),
    clue14(Game),
    clue15(Game),
    clue16(Game),
    clue17(Game, A,B,C,D),
    members([[_,sudoku,_,_], [_,logic,_,_],[_,letter,_,_],[_,jigsaw,_,_],[_,word,_,_]],Game),
    members([[krystal,_,_,_],[angie,_,_,_],[ethan,_,_,_],[dereck,_,_,_],[nick,_,_,_]],Game),
    members([[_,_,60,_],[_,_,45,_],[_,_,90,_],[_,_,30,_],[_,_,20,_]],Game),
    members([[_,_,_,sports],[_,_,_,cat],[_,_,_,outerspace],[_,_,_,movies],[_,_,_,winter]],Game),
    write(Game),
    true.

/*
1) One is named Krytal who didnt do the Outerspace puzzle, the Word search and didnt use 30 min 
    and One is named Angie who didnt do the Outerspace puzzle, the Word search and didnt use 30 min
2) One boy did the Outerspace puzzle
3) One boy used 30 min
4) One boy did the Word Search  
5) Ethan either finished the letter tiles in 90 minutes or did the winter themed puzzle in 20 minutes.
6) Boys took the shortest and longest times to finish their puzzles.
7) Dereck either took 45 minutes or did a movies themed puzzle.
8) The one who did the logic puzzle either took 45 minutes or did a movies themed puzzle.
9) Nick spent less than 40 minutes working on his puzzle
10) Nick did not the Visual Sudoku. 
11) Angie spent more than 40 minutes working on her Cat puzzle.
12) The girl who spent 60 minutes working on a sports puzzle did NOT do the Jigsaw. 
13) the jigsaw was done by a boy in less time than the one who did the Logic Puzzle but more time than the one who did the Word Search.
14) The Visual Sudoku either took an hour to complete or was Outerspace themed. 
15) Dereck did not do the winter themed puzzle 
16) The Word Search is not winter themed
*/
  

Комментарии:

1. Итак, ошибка в том, что members с тремя аргументами это не вещь. Что верно, вы определили только один с двумя, но вы вызываете его с тремя. Я бы предложил вставить вашу программу в swish.swi-prolog.org и перебираем все части, которые отмечены красным. Также member/2 есть встроенный, который выглядит до смешения похожим на ваш members . Возможно, вы захотите переименовать свой предикат…

Ответ №1:

Это всего лишь ответ на самый насущный вопрос, он не даст вам полного рабочего решения. Тем не менее, вы на правильном пути, пожалуйста, не отчаивайтесь!

Кроме того, прежде всего: загрузка вашей программы в SWI-Prolog выдает два предупреждения:

 Warning: /home/isabelle/einstein.pl:49:
    Singleton variables: [Q]
Warning: /home/isabelle/einstein.pl:50:
    Singleton variables: [Q]
  

Это означает, что в предложениях в этих местах у вас есть «одноэлементные» переменные: переменные, которые встречаются в предложении только один раз. Одноэлементные переменные могут указывать на очень серьезные логические ошибки, поэтому вы не должны игнорировать такие предупреждения. Может быть, переменная Q в первых двух предложениях clue13 должна как-то соотноситься со временем 20 и 90 ?

Что касается вашего сообщения об ошибке, давайте распакуем его:

  • existence_error(procedure, ...) означает, что вы пытались вызвать «процедуру» (чаще мы называем их «предикатами»), которая не существует
  • members/3 это процедура, которая не существует
  • clue1/0 это местоположение неудачного вызова.

Для справки, моя локальная версия SWI-Prolog сообщает о такой же ошибке, как эта, которая немного более удобна для пользователя:

 ?- solution(A, B, C, D).
ERROR: Undefined procedure: members/3
ERROR:   However, there are definitions for:
ERROR:         members/2
ERROR: 
ERROR: In:
ERROR:   [10] members([[krystal|...],...|...],[_3044,_3050|...],man(_3056))
ERROR:    [9] clue1([_3084,_3090|...]) at /home/isabelle/einstein.pl:29
ERROR:    [8] solution(_3116,_3118,_3120,_3122) at /home/isabelle/einstein.pl:64
ERROR:    [7] <user>
  

В любом случае, вы пытаетесь вызвать из clue1 предиката members с тремя аргументами, но такого определения не существует. Давайте посмотрим на ваше определение:

 clue1(Game) :- members([[krystal,_,_,_,_], [angie,_,_,_], [P,_,30,_], [P,word,_,_], [P,_,_,outerspace]], Game, man(P)).
  

Проблему трудно обнаружить, потому что вы усвоили очень плохие привычки форматирования кода. Это не ваша вина: слишком много классических книг по прологу настаивают на размещении слишком большого количества кода в одной строке, поэтому слишком много программистов на прологе пишут свой код таким образом.

То, что вы имели в виду, было чем-то более похожим на это:

 clue1(Game) :-
    members([[krystal,_,_,_,_], [angie,_,_,_], [P,_,30,_],
             [P,word,_,_], [P,_,_,outerspace]],
            Game,
    man(P)).
  

Вы видите это сейчас? members Вызов должен быть закрыт после Game и man(P) не должен быть аргументом для этого вызова. Так что это должно быть:

 clue1(Game) :-
    members([[krystal,_,_,_,_], [angie,_,_,_], [P,_,30,_],
             [P,word,_,_], [P,_,_,outerspace]],
            Game),
    man(P).
  

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

После этого ваша программа больше не будет иметь ошибки существования, но быстро завершится сбоем внутри members вызова. Вы пытаетесь вызвать members(<five-element list>, <four-element list>) , и это не может увенчаться успехом. То, как вы настраиваете Game переменную внутри solution , выглядит неправильно. Попробуйте использовать гораздо более описательные имена, чем A to D , для объектов, о которых вы говорите.