Search code examples
prologvisual-prolog

Prolog logical task


There is a logical problem: four friends: Ivan, Petr, Mikhail, Sergey spent their time in different ways: two were playing chess, one read books, one watched TV. Find who does what if Sergey does not play chess and Petr did not watch TV.

Here is my solution:

PREDICATES
    question(string,string,string,string)
    friend(string)
    readBook(string)
    watchTV(string)
    playsChess(string, string)

CLAUSES
    friend(ivan).
    friend(petr).
    friend(mikhail).
    friend(sergey).

    readBook(X):-
        friend(X).

    watchTV(X):-
        friend(X),
        X<>"petr".

    playsChess(X,Y):-
        friend(X),
        friend(Y),
        X<>Y,
        X<>"sergey",
        Y<>"sergey".

    question(A,B,C,D):-
        friend(A),
        friend(B),
        friend(C),
        friend(D),
        playsChess(A,B),
        readBook(C),
        watchTV(D),
        A<>B, A<>C, A<>D,
        B<>C, B<>D,
        C<>D.
GOAL
    question(A,B,C,D).

I have the following solution:

A=ivan, B=petr, C=mikhail, D=sergey (1)
A=ivan, B=petr, C=sergey, D=mikhail (2)
A=ivan, B=mikhail, C=petr, D=sergey (3)
A=petr, B=ivan, C=mikhail, D=sergey (4)
A=petr, B=ivan, C=sergey, D=mikhail (5)
A=petr, B=mikhail, C=ivan, D=sergey (6)
A=petr, B=mikhail, C=sergey, D=ivan (7)
A=mikhail, B=ivan, C=petr, D=sergey (8)
A=mikhail, B=petr, C=ivan, D=sergey (9)
A=mikhail, B=petr, C=sergey, D=ivan (10)
10 Solutions

But some lines are redundant since they are combined A and B. For example lines (1) and (4) (A=ivan, B=petr and A=petr, B=ivan). I tried to use ! here:

playsChess(X,Y):-!,
    friend(X),
    friend(Y),
    X<>Y,
    X<>"sergey",
    Y<>"sergey".

but it has no effect. So the question is: how can I get rid of excess solution results?


Solution

  • The simplest way to solve the problem would be to constrain A and B further and force one to be "greater" than the other. I'm not sure exactly if this is the syntax in Visual Prolog, but try this. Note the use of A > B instead of A <> B.

    question(A,B,C,D):-
        friend(A),
        friend(B),
        friend(C),
        friend(D),
        playsChess(A,B),
        readBook(C),
        watchTV(D),
        A > B, A<>C, A<>D,
        B<>C, B<>D,
        C<>D.
    

    By constraining with > instead of <> you will ensure that you won't have symmetrical cases. For example, a > b is false, but a < b is true. However, both a <> b and b <> a are true, so the <> gives both a, b and b, a.

    Your cut (!) did nothing because when you use it on a predicate that has only one clause like this:

    my_predicate(...) :- !, subqueries ...
    

    It just tells Prolog not to backtrack beyond the beginning of the first subquery. Since there are no other my_predicate clauses to backtrack to anyway, it has no effect.