Programming in Forth with Forth style
Sometimes I've found Forth code that is written without the Forth style. This page shows two examples, and how I rewrote them. This page is a brief version of the original article in Spanish, with step by step changes in the code.
Example 1
In Sideras (page in Spanish), a little game written in Ace Forth by an unknown author, I found the following word:
: izq
x @ 0 > ascii 5 k= and
if
x c@ 1- x !
then
;
The word k= has the following definition (but it's not relevant for the example);
: k= inkey = ;
The word izq (abbreviation of "left" in Spanish) tests the 5 key and, if the player's x coord is more than zero, it is decreased.
It works... But it's not the Forth's style. Here you are my alternative:
: izq x dup @ ascii 5 k= - 0 max swap ! ;
Result:
| original code | new code | |
|---|---|---|
| words | 15 | 11 |
| control structures | 1 | 0 |
| calculations | 2 | 1 |
times the x variable is mentioned | 3 | 1 |
In Ace Forth, the result of a boolean operation is 0 or 1. In ANS Forth the result is 0 or -1 (more useful and logical), so the code would be:
: izq x dup @ [char] 5 k= + 0 max swap ! ;
Example 2
Let's see a larger example. The listing of Chase, a little game for the Jupiter Ace, was published by Andrew Curtis in Popular Computing Weekly in 1983.
Original code
The original code is almost ilegible:
10 VARIABLE X
15 VARIABLE Y
1 VARIABLE A
1 VARIABLE B
: CHASE CLS 10 X ! 15 Y ! 1 A ! 1 B ! BEGIN X @ Y @ AT ." " A @ B @ AT ." " INKEY 53 = IF Y @ 2 - Y ! THEN INKEY 54 = IF X @ 2 - X ! THEN INKEY 55 = IF X @ 2 + X ! THEN INKEY 56 = IF Y @ 2 + Y ! THEN X @ 20 > IF 20 X ! THEN Y @ 30 > IF 30 Y ! THEN X @ 1 < IF 1 X ! THEN Y @ 1 < IF 1 Y ! THEN X @ A @ = IF Y @ B @ = IF ." GOT YOU!" 250 1000 BEEP QUIT THEN THEN X @ A @ > IF A @ 1+ A ! THEN X @ A @ < IF A @ 1– A ! THEN Y @ B @ > IF B @ 1+ B ! THEN Y @ B @ < IF B @ 1– B ! THEN X @ Y @ AT ." A" A @ B @ AT ." E" 250 70 BEEP 0 1 = UNTIL ;
In lowercase and with proper indentation, the code looks much better. It's clear the code was written with the style of BASIC: many conditionals, and many redundant calculations.
10 variable x
15 variable y
1 variable a
1 variable b
: chase
cls
10 x ! 15 y !
1 a ! 1 b !
begin
x @ y @ at ." "
a @ b @ at ." "
inkey 53 = if y @ 2 - y ! then
inkey 54 = if x @ 2 - x ! then
inkey 55 = if x @ 2 + x ! then
inkey 56 = if y @ 2 + y ! then
x @ 20 > if 20 x ! then
y @ 30 > if 30 y ! then
x @ 1 < if 1 x ! then
y @ 1 < if 1 y ! then
x @ a @ = if
y @ b @ = if
." got you!" 250 1000 beep quit
then
then
x @ a @ > if a @ 1+ a ! then
x @ a @ < if a @ 1– a ! then
y @ b @ > if b @ 1+ b ! then
y @ b @ < if b @ 1– b ! then
x @ y @ at ." A"
a @ b @ at ." E"
250 70 beep
0 1 =
until
;
Modified code
This is my version, with no conditional structure, simplified calculations and simpler main loop:
10 variable x
15 variable y
1 variable a
1 variable b
: chase
cls
10 x ! 15 y !
1 a ! 1 b !
begin
x @ y @ at space
a @ b @ at space
y @ inkey 53 = 2 * - inkey 56 = 2 * + 1 max 30 min y !
x @ inkey 54 = 2 * - inkey 55 = 2 * + 1 max 20 min x !
x @ a @ = y @ b @ = and 0=
while
a @ x @ over > + x @ a @ < negate + a !
b @ y @ over > + y @ b @ < negate + b !
x @ y @ at ." A"
a @ b @ at ." E"
250 70 beep
repeat
." got you!" 250 1000 beep
;
It's almost Forth style, but not completely: Factoring is needed. Instead of one large word, many little specialized and independent words are better: the code gets easier to read and mantain.
The result of factoring the code of Chase became a new program: Heat Seeker.