\ animal.4th
\ animal 01.12.25 18:21 -- EJB
\ silly animal guessing game in which the computer
\ "learns" new animals as it goes.
\ written on 25 December 2001 by Edward J. Beroset
\ and released to the public domain by the author.
\ Modified to run under kForth --- K. Myneni, 2001-12-29
\ Modified to run under 4tH --- H. Bezemer, 2003-03-26
INCLUDE lib/ncoding.4th
2048 STRING ANIMAL-TREE \ allot space for the binary tree
/NELL STRING ROOT
80 STRING MYPAD
VARIABLE TREE-PTR
ANIMAL-TREE TREE-PTR !
\ insert an integer value into the tree
: TREE, ( n -- )
TREE-PTR @ N! TREE-PTR @ NELL+ TREE-PTR ! ;
\ insert a string into the tree
: TREE-S, ( c-addr u -- )
DUP TREE,
DUP >R
TREE-PTR @ SWAP CMOVE
TREE-PTR @ R> + TREE-PTR ! ;
\ adds a new node to the binary tree using
\ the passed string as the data
: NEWNODE ( c-addr u -- c-addr )
ALIGN
TREE-PTR @ >R \ save original address
0 TREE, \ save YES node
0 TREE, \ save NO node
TREE-S, \ save string
R> ; \ return address of this node
\ returns the address of the left branch of
\ the passed node
: LEFT ( a-addr -- a-addr )
N@ ;
\ returns the address of the right branch of
\ the passed node
: RIGHT ( a-addr -- a-addr )
NELL+ N@ ;
\ returns TRUE if this is a terminal node.
: TERM? ( a-addr -- t )
DUP LEFT SWAP RIGHT OR 0= ;
\ given the address of a node, types the
\ text stored at that node.
: GETQ ( a-addr -- )
NELL+ NELL+ DUP N@ SWAP NELL+ SWAP TYPE ;
\ cleans up the question.
: CLEANQ ( a-addr u -- a-addr u)
OVER DUP C@ BL INVERT AND SWAP C!
2DUP 1- CHARS + DUP C@ [CHAR] ? TUCK =
IF DROP DROP ELSE SWAP CHAR+ C! 1+ THEN ;
\ prints the question based on the text
\ stored at this node.
: SHOWQ ( a-addr -- )
DUP TERM? IF \ is it a terminal node?
." Is it a " GETQ ." ?"
ELSE
GETQ
THEN CR ;
\ returns TRUE if the passed char was y or Y
: YES? ( n -- t )
DUP [CHAR] Y = SWAP
[CHAR] y = OR ;
\ returns TRUE if the passed char was n or N
: NO? ( n -- t )
DUP [CHAR] N = SWAP
[CHAR] n = OR ;
\ returns the letter pressed by the user
\ and TRUE if that was either Y or N
: GETA ( -- n t )
MYPAD 1 ACCEPT DROP MYPAD C@
DUP DUP YES? SWAP NO? OR ;
\ asks a question based on the text at the
\ passed node and gets a response. The
\ letter returned is the users response and
\ the flag returned is TRUE if the user
\ wants to continue
: QUERY ( a-addr -- n t )
SHOWQ ." (Y, N or Q): "
GETA CR ;
\ learning consists of asking three questions. The questions
\ are: what was the animal? what's a question to differentiate?
\ and what is the answer to that question in the case of the new
\ animal? The first question causes a new terminal node to be
\ created. The second causes a new non-terminal node to be
\ created, and the last question allows the links to that
\ non-terminal to be set correctly.
: LEARN ( a-addr -- )
." What is the animal you were thinking of?" CR
MYPAD DUP 80 ACCEPT NEWNODE CR ( -- oldtermaddr newnode )
." What is a yes/no question that differentiates a "
OVER N@ GETQ ." from a " DUP GETQ ." ?" CR
MYPAD DUP 80 ACCEPT CLEANQ NEWNODE ( -- oldtermaddr newnode qnode )
CR ." And what is the answer in the case of a " OVER GETQ
." ? " GETA CR IF
YES? IF
DUP ROT ROT N! ( -- oldtermadd qnode )
OVER OVER NELL+ SWAP N@ SWAP N!
SWAP N!
ELSE
DUP ROT ROT NELL+ N! ( -- oldtermadd qnode )
OVER OVER SWAP N@ SWAP N!
SWAP N!
THEN
THEN ;
\ starts with the address of a variable which contains the
\ first structure. We do it this way so that the variable
\ can be modified when we learn a new animal.
: GUESS ( a-addr -- a-addr t )
DUP N@ QUERY IF \ user wants to continue
OVER N@ TERM? IF
YES? IF \ answer was Y
." I guessed it! Let's play again!" CR CR
DROP
ELSE \ answer was N
." You stumped me! "
LEARN
THEN
ROOT
ELSE \ follow answer to next question
YES? IF
N@
ELSE
N@ NELL+
THEN
THEN 0 \ indicate user wants to continue
ELSE DROP 1 \ indicate user wants to quit
THEN ;
\ seeds the binary tree with a single terminal node
: SEED ( -- )
S" cow" NEWNODE ROOT N! ;
\ given a node address, this either prints
\ the text if it's a terminal node or replaces
\ the address with the addresses of the left
\ and right nodes.
: EXPAND ( a-addr -- a-addr a-addr | )
DUP TERM? IF
GETQ CR
ELSE
DUP LEFT SWAP RIGHT
THEN ;
\ lists the animals known to the game
: INVENTORY ( -- )
0 ROOT N@ CR BEGIN EXPAND DUP 0= UNTIL DROP ;
\ plays the animal game
: ANIMAL
." You think of an animal and I'll try to guess it!" CR
." Let's start!" CR CR
SEED ROOT BEGIN GUESS UNTIL DROP ;
ANIMAL
|