about summary refs log tree commit diff stats
path: root/forth/guesser.fth
diff options
context:
space:
mode:
Diffstat (limited to 'forth/guesser.fth')
-rw-r--r--forth/guesser.fth100
1 files changed, 100 insertions, 0 deletions
diff --git a/forth/guesser.fth b/forth/guesser.fth
new file mode 100644
index 0000000..01d84a0
--- /dev/null
+++ b/forth/guesser.fth
@@ -0,0 +1,100 @@
+\ --- Number Guessing Game for pForth ---
+
+\ First, we need some helper words for reliable numeric input.
+\ These are based on the pForth tutorial.
+( -- $addr )
+: INPUT$ ( A word to get a line of text from the user )
+    PAD 1+      ( addr --- , leave room on the scratchpad for a byte count )
+    80 ACCEPT   ( addr maxbytes -- numbytes , get up to 80 chars )
+    PAD C!      ( numbytes --- , store the count in the first byte )
+    PAD         ( -- $addr , leave the address of the counted string )
+;
+
+( -- n true | false )
+: INPUT# ( Read a line and convert it to a number )
+    INPUT$      ( -- $addr )
+    NUMBER?     ( $addr -- d_num true | false , convert string to double )
+    IF
+        SWAP DROP TRUE  ( d_num true -- n true , drop high part of double )
+    ELSE
+        FALSE           ( -- false )
+    THEN
+;
+
+\ --- Game Logic ---
+
+VARIABLE SECRET#  \ A place to store the secret number.
+
+( -- )
+: INIT-SECRET# ( Generate and store a random number )
+    501 CHOOSE  ( -- rand , CHOOSE gives a number from 0 to n-1 )
+    SECRET# !   ( rand -- , store it in our variable )
+;
+
+( -- n )
+: GET-GUESS ( Loop until the user enters a valid number )
+    BEGIN
+        CR ." Your guess (0-500)? "
+        INPUT#      ( -- n true | false )
+    UNTIL           ( loops until flag is true )
+;
+
+( guess -- correct? )
+: CHECK-GUESS ( Compares guess to the secret number, gives a hint )
+    SECRET# @       ( guess -- guess secret# )
+    2DUP =          ( guess secret# -- guess secret# flag )
+    IF              ( guess is equal to secret# )
+        ." You got it!" CR
+        2DROP TRUE  \ --> Make sure this 2DROP is here.
+    ELSE            ( guess is not equal )
+        2DUP <      ( guess secret# -- guess secret# flag )
+        IF
+            ." Too low!" CR
+            2DROP FALSE \ --> And this one.
+        ELSE
+            ." Too high!" CR
+            2DROP FALSE \ --> And this one.
+        THEN
+    THEN
+;
+
+( -- )
+: SEED-BY-WAITING ( Uses user's reaction time to seed the PRNG )
+    CR ." Press any key to begin..."
+    BEGIN
+        501 CHOOSE DROP  \ "Burn" a random number from the sequence
+        ?TERMINAL        \ Check if a key has been pressed
+    UNTIL
+    CR
+;
+
+( -- )
+: GUESSING-GAME ( The main word to run the game )
+    SEED-BY-WAITING \ Call our new interactive seeder
+    INIT-SECRET#
+    CR ." I'm thinking of a number between 0 and 500."
+    CR ." You have 5 chances to guess it."
+
+    FALSE           ( -- user-won? , place a 'false' flag on the stack )
+
+    5 0 DO          ( loop 5 times, from 0 to 4 )
+        CR 5 I - . ." guesses left."
+        GET-GUESS
+        CHECK-GUESS ( guess -- correct? )
+        IF          ( a correct guess was made )
+            DROP TRUE ( replace the 'user-won?' flag with 'true' )
+            LEAVE     ( and exit the loop immediately )
+        THEN
+    LOOP
+
+    ( The 'user-won?' flag is now on top of the stack )
+    IF
+        CR ." Congratulations!" CR
+    ELSE
+        CR ." Sorry, you ran out of guesses."
+        CR ." The number was " SECRET# @ . CR
+    THEN
+;
+
+GUESSING-GAME   \ This line executes the game word we just defined.
+BYE             \ This tells pForth to exit when the game is over.