Prolog program that finds the culprit of a crime given the following facts

215 views Asked by At

Facts about the situation -- image

(free online OCR:) The police are trying to track down the gang of three kids who have been steeling pumpkins. So far, they have established the following facts: the kids' first names are Angela, Mary, and David; one is 5, one is 7, and one is 8; one has the last name Diamond, and the one with the last name Grant is 3 years older than the one with the Last name Leung. You can assume Angela and Mary are female and David is male.

Use the technique shown in the zebra example discussed in class (the code is available on the course web page) to find missing information on the gang: each child's age, gender, first name and last name, consistent with the data above. Encode the above data as is and do not add additional facts. Document your code appropriately. Additionally, use your Prolog code to show whether or not the computed information uniquely identifies the culprits. Submit these test results and a short explanation of their meaning in the file q2testa.txt.

(Zebra Technique Example.)

I believe the suspects can be organized as follows:

suspect(Angela, _, _, female)
suspect(Mary, _, _, female)
suspect(David, _, _, male)

also I know that the ages are arranged as follows:

suspect( _, Leung, 5, _)
suspect(_, Diamond, 7, _)
suspect(_, Grant,    8, _)

this is where I am stuck as far as how to create the Prolog function to generate a full table of suspects given the above information. Some help would be appreciated.

3

There are 3 answers

1
Kintalken On BEST ANSWER

:- op(1,'xfy','contains') .

puzzle(CULPRITs)
:-
there_are_three_culprits(CULPRITs) ,
the_set_of_first_names_is_known(CULPRITs) ,
the_set_of_last_names_is_known(CULPRITs) ,
the_set_of_ages_is_known(CULPRITs) ,
one_is_three_years_older(CULPRITs)
.

there_are_three_culprits(CULPRITs)
:-
length(CULPRITs,3)
.

the_set_of_first_names_is_known(CULPRITs)
:-
CULPRITs contains {first_name:'Angela',last_name:_,age:_} ,
CULPRITs contains {first_name:'Mary',last_name:_,age:_} ,
CULPRITs contains {first_name:'David',last_name:_,age:_}
.

the_set_of_last_names_is_known(CULPRITs)
:-
CULPRITs contains {first_name:_,last_name:'Diamond',age:_} ,
CULPRITs contains {first_name:_,last_name:'Grant',age:_} ,
CULPRITs contains {first_name:_,last_name:'Leung',age:_}
.

the_set_of_ages_is_known(CULPRITs)
:-
CULPRITs contains {first_name:_,last_name:_,age:5} ,
CULPRITs contains {first_name:_,last_name:_,age:7} ,
CULPRITs contains {first_name:_,last_name:_,age:8}
.

one_is_three_years_older(CULPRITs)
:-
CULPRITs contains {first_name:_,last_name:'Grant',age:AGE_GRANT} ,
CULPRITs contains {first_name:_,last_name:'Leung',age:AGE_LEUNG} ,
AGE_GRANT is AGE_LEUNG + 3
.

CULPRITs contains CULPRIT
:-
prolog:member(CULPRIT,CULPRITs)
.


There is not an definitive answer to this puzzle . With the given clues there are still 36 possible solutions .

/*
?- puzzle(CULPRITs).

CULPRITs = [{first_name:'Angela', last_name:'Diamond', age:7}, {first_name:'Mary', last_name:'Grant', age:8}, {first_name:'David', last_name:'Leung', age:5}] ;
CULPRITs = [{first_name:'Angela', last_name:'Diamond', age:7}, {first_name:'Mary', last_name:'Leung', age:5}, {first_name:'David', last_name:'Grant', age:8}] ;
CULPRITs = [{first_name:'Angela', last_name:'Grant', age:8}, {first_name:'Mary', last_name:'Diamond', age:7}, {first_name:'David', last_name:'Leung', age:5}] ;
CULPRITs = [{first_name:'Angela', last_name:'Leung', age:5}, {first_name:'Mary', last_name:'Diamond', age:7}, {first_name:'David', last_name:'Grant', age:8}] ;
CULPRITs = [{first_name:'Angela', last_name:'Grant', age:8}, {first_name:'Mary', last_name:'Leung', age:5}, {first_name:'David', last_name:'Diamond', age:7}] ;
CULPRITs = [{first_name:'Angela', last_name:'Leung', age:5}, {first_name:'Mary', last_name:'Grant', age:8}, {first_name:'David', last_name:'Diamond', age:7}] ;
CULPRITs = [{first_name:'Angela', last_name:'Diamond', age:7}, {first_name:'David', last_name:'Grant', age:8}, {first_name:'Mary', last_name:'Leung', age:5}] ;
CULPRITs = [{first_name:'Angela', last_name:'Diamond', age:7}, {first_name:'David', last_name:'Leung', age:5}, {first_name:'Mary', last_name:'Grant', age:8}] ;
CULPRITs = [{first_name:'Angela', last_name:'Grant', age:8}, {first_name:'David', last_name:'Diamond', age:7}, {first_name:'Mary', last_name:'Leung', age:5}] ;
CULPRITs = [{first_name:'Angela', last_name:'Leung', age:5}, {first_name:'David', last_name:'Diamond', age:7}, {first_name:'Mary', last_name:'Grant', age:8}] ;
CULPRITs = [{first_name:'Angela', last_name:'Grant', age:8}, {first_name:'David', last_name:'Leung', age:5}, {first_name:'Mary', last_name:'Diamond', age:7}] ;
CULPRITs = [{first_name:'Angela', last_name:'Leung', age:5}, {first_name:'David', last_name:'Grant', age:8}, {first_name:'Mary', last_name:'Diamond', age:7}] ;
CULPRITs = [{first_name:'Mary', last_name:'Diamond', age:7}, {first_name:'Angela', last_name:'Grant', age:8}, {first_name:'David', last_name:'Leung', age:5}] ;
CULPRITs = [{first_name:'Mary', last_name:'Diamond', age:7}, {first_name:'Angela', last_name:'Leung', age:5}, {first_name:'David', last_name:'Grant', age:8}] ;
CULPRITs = [{first_name:'Mary', last_name:'Grant', age:8}, {first_name:'Angela', last_name:'Diamond', age:7}, {first_name:'David', last_name:'Leung', age:5}] ;
CULPRITs = [{first_name:'Mary', last_name:'Leung', age:5}, {first_name:'Angela', last_name:'Diamond', age:7}, {first_name:'David', last_name:'Grant', age:8}] ;
CULPRITs = [{first_name:'Mary', last_name:'Grant', age:8}, {first_name:'Angela', last_name:'Leung', age:5}, {first_name:'David', last_name:'Diamond', age:7}] ;
CULPRITs = [{first_name:'Mary', last_name:'Leung', age:5}, {first_name:'Angela', last_name:'Grant', age:8}, {first_name:'David', last_name:'Diamond', age:7}] ;
CULPRITs = [{first_name:'David', last_name:'Diamond', age:7}, {first_name:'Angela', last_name:'Grant', age:8}, {first_name:'Mary', last_name:'Leung', age:5}] ;
CULPRITs = [{first_name:'David', last_name:'Diamond', age:7}, {first_name:'Angela', last_name:'Leung', age:5}, {first_name:'Mary', last_name:'Grant', age:8}] ;
CULPRITs = [{first_name:'David', last_name:'Grant', age:8}, {first_name:'Angela', last_name:'Diamond', age:7}, {first_name:'Mary', last_name:'Leung', age:5}] ;
CULPRITs = [{first_name:'David', last_name:'Leung', age:5}, {first_name:'Angela', last_name:'Diamond', age:7}, {first_name:'Mary', last_name:'Grant', age:8}] ;
CULPRITs = [{first_name:'David', last_name:'Grant', age:8}, {first_name:'Angela', last_name:'Leung', age:5}, {first_name:'Mary', last_name:'Diamond', age:7}] ;
CULPRITs = [{first_name:'David', last_name:'Leung', age:5}, {first_name:'Angela', last_name:'Grant', age:8}, {first_name:'Mary', last_name:'Diamond', age:7}] ;
CULPRITs = [{first_name:'Mary', last_name:'Diamond', age:7}, {first_name:'David', last_name:'Grant', age:8}, {first_name:'Angela', last_name:'Leung', age:5}] ;
CULPRITs = [{first_name:'Mary', last_name:'Diamond', age:7}, {first_name:'David', last_name:'Leung', age:5}, {first_name:'Angela', last_name:'Grant', age:8}] ;
CULPRITs = [{first_name:'Mary', last_name:'Grant', age:8}, {first_name:'David', last_name:'Diamond', age:7}, {first_name:'Angela', last_name:'Leung', age:5}] ;
CULPRITs = [{first_name:'Mary', last_name:'Leung', age:5}, {first_name:'David', last_name:'Diamond', age:7}, {first_name:'Angela', last_name:'Grant', age:8}] ;
CULPRITs = [{first_name:'Mary', last_name:'Grant', age:8}, {first_name:'David', last_name:'Leung', age:5}, {first_name:'Angela', last_name:'Diamond', age:7}] ;
CULPRITs = [{first_name:'Mary', last_name:'Leung', age:5}, {first_name:'David', last_name:'Grant', age:8}, {first_name:'Angela', last_name:'Diamond', age:7}] ;
CULPRITs = [{first_name:'David', last_name:'Diamond', age:7}, {first_name:'Mary', last_name:'Grant', age:8}, {first_name:'Angela', last_name:'Leung', age:5}] ;
CULPRITs = [{first_name:'David', last_name:'Diamond', age:7}, {first_name:'Mary', last_name:'Leung', age:5}, {first_name:'Angela', last_name:'Grant', age:8}] ;
CULPRITs = [{first_name:'David', last_name:'Grant', age:8}, {first_name:'Mary', last_name:'Diamond', age:7}, {first_name:'Angela', last_name:'Leung', age:5}] ;
CULPRITs = [{first_name:'David', last_name:'Leung', age:5}, {first_name:'Mary', last_name:'Diamond', age:7}, {first_name:'Angela', last_name:'Grant', age:8}] ;
CULPRITs = [{first_name:'David', last_name:'Grant', age:8}, {first_name:'Mary', last_name:'Leung', age:5}, {first_name:'Angela', last_name:'Diamond', age:7}] ;
CULPRITs = [{first_name:'David', last_name:'Leung', age:5}, {first_name:'Mary', last_name:'Grant', age:8}, {first_name:'Angela', last_name:'Diamond', age:7}] ;
false .
*/

4
Enigmativity On

It's very simple with some basic predicates:

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

clue1(Suspects) :- members([[angela,_,_,female],[mary,_,_,female],[david,_,_,male]],Suspects).
clue2(Suspects) :- members([[_,leung,5,_],[_,diamond,7,_],[_,grant,8,_]],Suspects).

solve(Suspects) :-
    Suspects = [[_,_,_,_],[_,_,_,_],[_,_,_,_]],
    clue1(Suspects),
    clue2(Suspects).

That gives me:

?- solve(X).
X = [[angela, leung, 5, female], [mary, diamond, 7, female], [david, grant, 8, male]] ;
X = [[angela, leung, 5, female], [mary, grant, 8, female], [david, diamond, 7, male]] ;
X = [[angela, diamond, 7, female], [mary, leung, 5, female], [david, grant, 8, male]] ;
X = [[angela, grant, 8, female], [mary, leung, 5, female], [david, diamond, 7, male]] ;
X = [[angela, diamond, 7, female], [mary, grant, 8, female], [david, leung, 5, male]] ;
X = [[angela, grant, 8, female], [mary, diamond, 7, female], [david, leung, 5, male]] ;
X = [[angela, leung, 5, female], [david, diamond, 7, male], [mary, grant, 8, female]] ;
X = [[angela, leung, 5, female], [david, grant, 8, male], [mary, diamond, 7, female]] ;
X = [[angela, diamond, 7, female], [david, leung, 5, male], [mary, grant, 8, female]] ;
X = [[angela, grant, 8, female], [david, leung, 5, male], [mary, diamond, 7, female]] ;
X = [[angela, diamond, 7, female], [david, grant, 8, male], [mary, leung, 5, female]] ;
X = [[angela, grant, 8, female], [david, diamond, 7, male], [mary, leung, 5, female]] ;
X = [[mary, leung, 5, female], [angela, diamond, 7, female], [david, grant, 8, male]] ;
X = [[mary, leung, 5, female], [angela, grant, 8, female], [david, diamond, 7, male]] ;
X = [[mary, diamond, 7, female], [angela, leung, 5, female], [david, grant, 8, male]] ;
X = [[mary, grant, 8, female], [angela, leung, 5, female], [david, diamond, 7, male]] ;
X = [[mary, diamond, 7, female], [angela, grant, 8, female], [david, leung, 5, male]] ;
X = [[mary, grant, 8, female], [angela, diamond, 7, female], [david, leung, 5, male]] ;
X = [[david, leung, 5, male], [angela, diamond, 7, female], [mary, grant, 8, female]] ;
X = [[david, leung, 5, male], [angela, grant, 8, female], [mary, diamond, 7, female]] ;
X = [[david, diamond, 7, male], [angela, leung, 5, female], [mary, grant, 8, female]] ;
X = [[david, grant, 8, male], [angela, leung, 5, female], [mary, diamond, 7, female]] ;
X = [[david, diamond, 7, male], [angela, grant, 8, female], [mary, leung, 5, female]] ;
X = [[david, grant, 8, male], [angela, diamond, 7, female], [mary, leung, 5, female]] ;
X = [[mary, leung, 5, female], [david, diamond, 7, male], [angela, grant, 8, female]] ;
X = [[mary, leung, 5, female], [david, grant, 8, male], [angela, diamond, 7, female]] ;
X = [[mary, diamond, 7, female], [david, leung, 5, male], [angela, grant, 8, female]] ;
X = [[mary, grant, 8, female], [david, leung, 5, male], [angela, diamond, 7, female]] ;
X = [[mary, diamond, 7, female], [david, grant, 8, male], [angela, leung, 5, female]] ;
X = [[mary, grant, 8, female], [david, diamond, 7, male], [angela, leung, 5, female]] ;
X = [[david, leung, 5, male], [mary, diamond, 7, female], [angela, grant, 8, female]] ;
X = [[david, leung, 5, male], [mary, grant, 8, female], [angela, diamond, 7, female]] ;
X = [[david, diamond, 7, male], [mary, leung, 5, female], [angela, grant, 8, female]] ;
X = [[david, grant, 8, male], [mary, leung, 5, female], [angela, diamond, 7, female]] ;
X = [[david, diamond, 7, male], [mary, grant, 8, female], [angela, leung, 5, female]] ;
X = [[david, grant, 8, male], [mary, diamond, 7, female], [angela, leung, 5, female]].
0
Will Ness On

To follow your approach, all you needed to do was to write it down:

find4( Kids) :-
  Kids = [ suspect('Angela', _, _, female),
           suspect('Mary', _, _, female),
           suspect('David', _, _, male) ],
  member( suspect( _, 'Leung', 5, _), Kids),
  member( suspect(_, 'Diamond', 7, _), Kids),
  member( suspect(_, 'Grant',    8, _), Kids).

So you practically already had the solution, although it breaks the conditions specified in the exercise, of "encoding the data as is".

Do note that atoms starting with upper case letters must be enclosed in single quotes, otherwise they will be treated as logical variables.

(previous version of the answer follows).


Advancing slowly by progressive development.

Our first attempts do not have to be working, only the last one does.

known1(P) :-
  P = "the kids' first names are Angela, Mary, and David; 
       one is 5, one is 7, and one is 8; 
       one has the last name Diamond, and 
       the one with the last name Grant is 
          3 years older than the one with the Last name Leung. 
       Angela and Mary are female and David is male".

find1(Q) :-
  Q = "each child's age, gender, first name and last name".

known2(P) :-
  P = [ first_names = [Angela, Mary, David],
        ages =        [5,      7,    8    ],
        last_names =  [Diamond, Grant, X  ],
        ages_of = [[Grant, A1], [Leung, A2]],
        ages_diff = [      A1,          A2,    3],
        males =       [              David],
        females =     [Angela, Mary       ] ].

find2(Q) :-
  known2(P),
  ages(P,Q), genders(P,Q), first_names(P,Q), last_names(P,Q).

Now that we've acquainted ourselves with the situation, we go on defining

find3( Kids ) :-
  Kids = [Angela, Mary, David],  first_name( Angela, angela),
                                 first_name( Mary, mary),
                                 first_name( David, david),
  member( Five,  Kids ),  age( Five, 5),
  member( Seven, Kids ),  age( Seven, 7),
  member( Eight, Kids ),  age( Eight, 8),
  member( Diamond, Kids ),  last_name( Diamond, 'Diamond'),
  member( Grant,   Kids ),  last_name( Grant, 'Grant'),
                            age(       Grant, A1),
  member( Leung,   Kids ),  last_name( Leung, 'Leung'),
                            age(       Leung,      A2),
                            3 is              A1 - A2,
                            female( Angela),
                            female( Mary),
                            male(   David).

So now that we got here, how can we implement those leftover predicates age, male, etc.? By wishful thinking, that's how:

first_name( A, N) :- attr( A, first_name-N).
age(        A, N) :- attr( A, age-N).
last_name(  A, N) :- attr( A, last_name-N).
male(       A   ) :- attr( A, gender-male).
female(     A   ) :- attr( A, gender-female).

And so we've reached the point where we can't delay the actual implementation any longer:

%% (* our workhorse: *)
attr( Rep, Attr-Value) :- 
    memberchk( Attr-X, Rep),       % unique attribute names
    X = Value.

And that's practically it:

17 ?- find3(_Kids), maplist(writeln, _Kids).
[first_name-angela,age-5,last_name-Leung,gender-female|_G5742]
[first_name-mary,age-7,last_name-Diamond,gender-female|_G5751]
[first_name-david,age-8,last_name-Grant,gender-male|_G5760]
true .

(and 5 solutions more).