Can't figure out how to get logical answer I'm looking for in Prolog

57 Views Asked by At

I'm trying to learn swi-prolog and I'm struggling with the following question.

The question goes: Vanessa, Mary and Penny study chemistry, biology and math, in countries Spain, Portugal, Venezuela. It is known, that Vanessa is not studying in Spain, while Mary is not in Portugal. The one who lives in Spain doesn't study math. The one in Portugal studies chemistry. Mary doesn't like biology, but likes Caracas. Define what each person studies and from where?

I tried many approaches where I tried to find where each person lives and then which subject is studied in each country, but when I try to combine those two things to get the end result, it is not definitive, and gives me ambiguous answer, meaning I get alternatives where one person lives in 2 different countries and might study 3 subjects. Any help or guidance is appreciated.

1

There are 1 best solutions below

0
On

A possible solution could be the following:

At first, we add the countries, persons, and subjects to the knowledgebase:

country(spain).
country(portugal).
country(venezuela).
person(vanessa).
person(mary).
person(penny).
subject(math).
subject(biology).
subject(chemistry).

Then we add invalid combinations:

invalidPC(vanessa, spain).                % vanessa is not studying in spain
invalidPC(mary, portugal).                % mary is not in portugal
invalidPC(mary, spain).                   % mary likes caracas (venezuela)

invalidPS(mary, biology).                 % mary doesn't like biology

invalidCS(spain, math).                   % the one who lives in spain doesn't study math
invalidCS(portugal, X) :- X \= chemistry. % the one in portugal studies chemistry

Next we need a predicate to determine valid country-person-subject combinations:

student([C, P, S]) :-
    country(C),
    person(P),
    subject(S),
    \+ invalidPC(P, C),
    \+ invalidPS(P, S),
    \+ invalidCS(C, S).

And last a predicate which calculates three students and checks if their values are distinct:

findStudents([C1, P1, S1], [C2, P2, S2], [C3, P3, S3]) :-
    student([C1, P1, S1]),
    student([C2, P2, S2]),
    student([C3, P3, S3]),
    distinct(C1, C2, C3),
    distinct(P1, P2, P3),
    distinct(S1, S2, S3), 
    !. % stop after the first solution to prevent permutations of the student order

distinct(A, B, C) :-
    A \= B,
    A \= C,
    B \= C, !.

This returns one result (without the ! in findStudents/3 there are 6 results, but these are only permutations). You can also omit the ! and for example set P1, P2, and P3 to fix values, i.e. vanessa, mary, penny.