prolog

Prolog - Solution of a riddle


I have found a riddle in the internet and I wanna solve it using Prolog. I have a Prolog program but the result does not match my logical approach so I am interested what I am missing in my Prolog program. Any help would be appreciated. Sorry for posting to stackoverflow, I couldn't find any more suitable stackexchange site for this problem.

Text of the riddle:

In the jungle there lives a tribe of natives, whose expression has an extraordinary eccentricity: Men always tell the truth; women never say two false sentences in sequence, or two true sentences in sequence. The most uncomfortable thing is that both men and women dress and look the same in general, so with the recognition of truth it is sometimes complicated. An anthropologist tries to study natives, but he still does not know well native language. So one day he meets a family and asks a child if he is a boy, Anthropologist does not understand the answer. That is why he turns to parents, one of whom tells him "The child said he was a boy" and the other says "The child is a girl, the child lied." The anthropologist needed to know how the child had responded (or lied) to continue the research of local traditions determine the gender of the child and of both parents.

My logical approach which is correct I believe:

A child can be either a woman or a man. Let him be a man. Then he had to say he was a man, because men always tell the truth. Parent 2 says the child is a girl and the child lied. Parent 2 is certainly not a man, because it would be in contradiction that the child is a man. But the parent can not be a woman, because just one sentence would have to be false. But that is not because the child is a boy, and he certainly did not lie. In addition, the child is a man, therefore he is not a girl, and therefore both sentences are untrue. The child is certainly not a man. Let the child be a woman. Which has complicated it a little bit because a child could either say she was a man or a woman. Let the child be a woman and say she is a man. Let's start with Parent 2. This must be a man, because he says the baby is a woman and lied. Parent 1 can be a woman because she says the baby said she was a boy. A woman may or may not lie. It could also be a man if we admit that a child can have two fathers. For control, let the child be a woman and say she is a woman. Parent 2 must be a woman because she says the baby is a girl, which is true, but at the same time says she was lying, which is not true. Then parent 1 must be a man, but it can not be because men always tell the truth. But Parent 1 said the child said he was a boy, which is not true. This would only be possible if the child could have two wives for the parents. Solution: A child is a woman, parent 1 is a woman, and parent 2 is a man.

My Prolog program says that there are multiple solutions to this problem. The first one says that the child is a man as well as Parent 1. Parent 2 is a woman. The correct solution is the seventh one. Am I missing some "if" or ! operator somewhere? Or is this approach completely bad?

% split(+list, -listOfItemsAtEvenPositions, -listOfItemsAtOddPositions)

split([], [], []).
split([X|TList], Even, [X|TOdd]) :- rozdel(TList, TOdd, Even).

% says(+gender, +listOfSentences, -listOfTrueSentences)

% Men always say the truth.
says(man, X, X).

% Women never say two false sentences in sequence, or two true sentences in sequence.
says(woman, Sentences, TrueSentences) :-
   split(Sentences, _, TrueSentences); % Every odd sentence says the truth.
   split(Sentences, TrueSentences, _). % Every even sentence says the truth.

% solution(-genderOfChild, -genderOfFirstParent, -genderOfSecondParent)

solution(Child, Parent1, Parent2) :-

   % The child said something.
   says(Child, _, _),

   % The first parent says: "The child said he was a boy"
   says(Parent1, [says(Child, [Child=man], _)], _),

   % The second parent says: "The child is a girl, the child lied."
   says(Parent2, [Child=woman, says(Child, [Child=man], _)], _),

   % The child cannot have two parents of same gender.
   Parent1 \= Parent2.

I am a newbie in Prolog so that's about it.


Solution

  • Here is what I wrote

    :- use_module(library(clpb)).
    
    solve(L) :-
        L = [A,B,C,D],
        % A : true means the child is a boy
        % B : true means the child tells the truth
        % C : true means person 1 is a man
        % D : true means person 2 is a man
    
    
        % person 1 : The child said he was a boy (and a man tells the truth)
        % if person 1 is a man
        sat(C =< A),
        % if person 1 is a woman, we can't write anything
        % because there's only one sentence
    
    
        % person 2 "The child is a girl, the child lied"
        % if person 2 is a man
        sat(D =< ~A * ~B),
        % if person 2 is a woman
        sat(~D =< ((~A # B) # (A # ~B))),
    
        % Prolog works
        labeling([A,B,C,D]).
    

    I get :

    ?- solve(L).
    L = [0, 0, 0, 1].
    

    which means that the child is a girl, she lies and person 1 too. Person 2 is a man.

    Note that person 1 can be ignored :

    :- use_module(library(clpb)).
    
    solve(L) :-
        L = [A,B,C],
        % A : true means the child is a boy
        % B : true means the child tells the truth
        % C : true means person 2 is a man
    
    
        % person 2 "The child is a girl, the child lied"
        % if person 2 is a man
        sat(C =< ~A * ~B),
        % if person 2 is a woman
        sat(~C =< ((~A # B) # (A # ~B))),
    
        % Prolog works
        labeling([A,B,C]).
    

    with answer :

    ?- solve(L).
    L = [0, 0, 1].