2.17 Animal identification game

Here is a Prolog version of the animal identification game (simple expert system) presented in a Lisp program in Chapter 6 of Winston and Horn (1985). Load the file and pose the query ?- go. The program uses its identification rules to determine the animal that you have chosen.

/* animal.pro
  animal identification game.  

    start with ?- go.     */

go :- hypothesize(Animal),
      write('I guess that the animal is: '),
      write(Animal),
      nl,
      undo.

/* hypotheses to be tested */
hypothesize(cheetah)   :- cheetah, !.
hypothesize(tiger)     :- tiger, !.
hypothesize(giraffe)   :- giraffe, !.
hypothesize(zebra)     :- zebra, !.
hypothesize(ostrich)   :- ostrich, !.
hypothesize(penguin)   :- penguin, !.
hypothesize(albatross) :- albatross, !.
hypothesize(unknown).             /* no diagnosis */

/* animal identification rules */
cheetah :- mammal, 
           carnivore, 
           verify(has_tawny_color),
           verify(has_dark_spots).
tiger :- mammal,  
         carnivore,
         verify(has_tawny_color), 
         verify(has_black_stripes).
giraffe :- ungulate, 
           verify(has_long_neck), 
           verify(has_long_legs).
zebra :- ungulate,  
         verify(has_black_stripes).

ostrich :- bird,  
           verify(does_not_fly), 
           verify(has_long_neck).
penguin :- bird, 
           verify(does_not_fly), 
           verify(swims),
           verify(is_black_and_white).
albatross :- bird,
             verify(appears_in_story_Ancient_Mariner),
             verify(flys_well).

/* classification rules */
mammal    :- verify(has_hair), !.
mammal    :- verify(gives_milk).
bird      :- verify(has_feathers), !.
bird      :- verify(flys), 
             verify(lays_eggs).
carnivore :- verify(eats_meat), !.
carnivore :- verify(has_pointed_teeth), 
             verify(has_claws),
             verify(has_forward_eyes).
ungulate :- mammal, 
            verify(has_hooves), !.
ungulate :- mammal, 
            verify(chews_cud).

/* how to ask questions */
ask(Question) :-
    write('Does the animal have the following attribute: '),
    write(Question),
    write('? '),
    read(Response),
    nl,
    ( (Response == yes ; Response == y)
      ->
       assert(yes(Question)) ;
       assert(no(Question)), fail).

:- dynamic yes/1,no/1.

/* How to verify something */
verify(S) :-
   (yes(S) 
    ->
    true ;
    (no(S)
     ->
     fail ;
     ask(S))).

/* undo all yes/no assertions */
undo :- retract(yes(_)),fail. 
undo :- retract(no(_)),fail.
undo.

The program is mainly interesting with regard to how it tries to verify certain properties that it uses to draw conclusions, and how it asks questions and records the answers for further reference. If a question q is asked and the answer is 'yes', then that answer is recorded by asserting 'yes(q)' and succeeding, otherwise the answer is recorded by asserting 'no(q)' and failing. Even 'yes' answers need to be recorded since a subsequent 'no' answer to a different question while trying to verify the same hypothesis may cause the entire hypothesis to fail, but that same 'yes' answer could lead to a successful verification of a different hypothesis later. This is how the program avoids asking the same question twice. The general method of verifying a condition q is then to check whether 'yes(q)' has been stored in memory, and succeed, or 'no(q)' has been stored, and fail, otherwise ask(q).

Chapter 6 builds a general framework for expert systems in Prolog.


Prolog Code for this section.
Prolog Tutorial Contents