Guess who-like game in Prolog

I'm developing a Guess Who? game using Prolog. The mechanics of the game are very easy. A player (in this case, the human) chooses one person among many possible ones, and the other player (the computer) starts asking yes/no questions about some attributes of the person. Eventually, with the given answers, there will only be one possible person.

So far, I've been able to make a set of rules and predicates so that the computer can guess the person based on the questions that have been asked so far. I have a set of suspects - those are the people that, with the available clues, could fit.

suspect('Person 1') :- eyes(blue) , age(old) , gender(male).

The predicates for the attributes are defined so that they will be true either if the question regarding that attribute has not been asked yet, or if the question has been asked and the answer matches the attribute of the suspect.

gender(X) :- not(asked_gender) ; value_of(gender, X).

That way, if two suspects share the same eyes and age and different gender, as long as the gender remains unasked, both of them will be plausible suspects.

However, the hard part now is to automate the process of asking those questions. Basically, I'm looking forward to a solution where Prolog were able to get the possible values for the attributes from the suspects' predicates, instead of listing theme somewhere else. I'm pretty sure there must be a way of doing this, given prolog is able to use the program's code as data itself.

How could I do that?

Upvotes: 4

Views: 3440

Answers (2)

joel76
joel76

Reputation: 5645

This works in SWI-Prolog :

:- dynamic value/1.

suspect('Person 1') :- eyes(blue) , age(old) , gender(male).

suspect('Person 2') :- eyes(green) , age(young) , gender(male).

suspect('Person 3') :- eyes(brown) , age(young) , gender(male).


fetch(Criterion, Value) :-
    retractall(value(_)),
    assert(value([])),
    forall(clause(suspect(_), Body),
    check(Body, Criterion)),
    retract(value(Value)).

check((F, T), Criterion) :-
    F =..[Criterion, V1],
    retract(value(V2)),
    (   member(V1, V2) -> V3 = V2; V3 = [V1 | V2]),
    assert(value(V3)).
    check(T, Criterion).


check((_F, T), Criterion) :-
    check(T, Criterion).

check((F), Criterion) :-
    F =..[Criterion, V1],
    retract(value(V2)),
    (   member(V1, V2) -> V3 = V2; V3 = [V1 | V2]),
    assert(value(V3)).

check((_F), _Criterion).

For example : ?- fetch(gender, Value). Value = [male].

?- fetch(eyes, Value). Value = [brown,green,blue].

Upvotes: 3

Ihmahr
Ihmahr

Reputation: 1120

Well, I would imagine a construction like this:

go :-
    findall(People,suspect(People),SuspectList),
    length(SuspectList,1),
    member(Perb,SuspectList),
    write('It is '),write(Perb),write('!!'),nl,!.

go :-
    askQuestion,
    go.

Where in askQuestion/0 you'd ask questions with the read/1 predicate and assert/1 the answers. This is where you could try and make it 'intelligent' or you could just iterate over the different questions.

Upvotes: -1

Related Questions