Asking the questions
When a game is in progress much of the action will be to do with the computer asking you questions. As the game traces through the knowledge tree, at any particular time it will be looking at either a Question node or, if it thinks it knows what the animal is, an Animal node. Do you remember how you traced through a possible game scenario in the original diagram? If so, you'll see how the computer must pose a question to the human player at each stage. For example:
"Does it have wings?" - for a Question object or
"Are you thinking of an Eagle?" - for an Animal object.
Now the interesting thing here is that we can write the game so that it does not need to be aware of what type of node it is dealing with at any one time. It can go around just sending an #ask (say) message to each node that it comes across and, providing we implement a suitable #ask method in each of the Animal and Question classes everything should operate just fine. As it turns out, specifying object behaviour in this way is a fundamental part of object-oriented programming. We call this Polymorphism or Polymorphic behaviour. The key thing is that different classes of object can respond to the same method in different ways. This is great because it means that the sender need not be concerned about what type of object the receiver is, merely that it responds appropriately to the message being sent.
So let's add our polymorphic (it's a great word that) #ask methods to Question and Animal. Place them in the operations category.
"Ask the receiver's question and continue the game appropriately depending on the
answer that is received"
(MessageBox confirm: self displayString caption: 'The animal you''re thinking of...')
ifTrue: [ self yes ask ]
ifFalse: [ self no ask ].
Tip: Note the double quote '' marks used to obtain a single quote character within the caption text string. You must use these to indicate to the Smalltalk compiler that the string is not actually to be terminated at this point.
In the above method we are using a MessageBox to put up a simple dialog displaying the question text together with a suitable caption and a couple of buttons to allow the player to answer yes or no. Hopefully, you can now see how the game logic follows the yes or no branches in the knowledge tree based on the player's answer to the question.
Next is the Animal>>ask method. When this is called, the computer thinks it has a sensible guess for the animal (at least it has no more questions to ask anyway). Consequently, it must ask if the guess is correct and, if so it wins the game. If not, it prompts for a new Animal to be created with the real answer and for a new Question that will distinguish this from the original guess. You'll notice that there are some new messages being sent for which we have not yet designed the methods but, don't worry, we'll get to these in just a moment.
"Ask whether the receiver is the animal that the player is thinking of.
If it is then the game is over. If it is not then prompt for the true answer
and install it and a question which will distinguish this new animal from
the receiver. This allows the game to learn."
| newAnimal newQuestion |
(MessageBox confirm: ('Are you thinking of ', self displayString, '?'))
ifTrue: [ MessageBox notify: 'I guessed your animal correctly.' caption: 'GREAT, I WIN' ]
ifFalse: [ newAnimal := Animal prompt.
newQuestion := Question promptToDistinguish: self from: newAnimal ].
(MessageBox confirm: 'Do you wish to play again?' caption: 'I''m, getting better all the time...')
ifTrue: [ Animal playGame ].