Animals builds a decision-tree that guesses an animal. When it fails to guess yours, it asks for a question that might divide the search space.
I coded Animals in icon which was a challenge to use its sense of expression success or failure to control flow.
Of course the behavior of the program depends on the quality of questions offered by users. I programmed in the first few questions to divide the space:
node ("Does it swim", node ("a trout"), node ("Can it fly", node ("an eagle"), node ("a cat")))
My brother's girlfriend Teresa thought she would surely stump the program when she chose pterodactyl. She knew she'd lost when it asked, is it hard to spell?
The program stored the tree of choices as nodes, either branches that asked about a characteristic, or leaves that asked about a specific animal. The subtrees of a branch either had or didn't have the specific characteristic.
Nodes were written recursively to a flat-file database. When reading, I had only to distinguish leaves from branches. When I read a branch, I read (recursively) two more nodes, one for "yes" and one for "no".
Try recursing through this sample data:
Does it swim Is it warm blooded Is it really big a whale a seal Is it very small an amoeba Does it have legs a frog a trout Can it fly Is it furry Does it have bones a bat Will it sting a bee a moth Is it endangered an eagle Would it live in the city Will it sing a parrot a pigeon a hawk Has it four legs Is it really big Does it have spots a giraffe an elephant Is it a domestic animal Do you have to walk it a dog a cat Does it eat plants Is it magical an unicorn a bear Will it eat people a tiger Does it live on a farm a pig Is it striped a skunk a fox It has more than four a spider Does it stand erect a man Does it leave a trail a slug a snake
I read the database with the following icon code. The read_node procedure reads one line, establishes it as the match subject, then, based on matching, either creates a leaf node with that subject or creates a branch node with the subject and two more nodes.
procedure read_database () if file := open (filename, "r") then { root := read_node () close (file) return \root } end procedure read_node () return read (file) ? { (match ("a " | "an ") & node (&subject)) | node (&subject, read_node (), read_node ()) } end
See also Animals Decision Tree in Dot