Technology

Easy Forth: Be taught forth with REPL within the browser


Introduction

This diminutive e book is right here to coach you a programming language known as Forth. Forth is a
language now not like most others. It’s no longer helpful or object oriented, it doesn’t
have form-checking, and it assuredly has zero syntax. It was written within the 70s, but
is restful used on the present time for
obvious purposes.

Why would you will ought to learn such an distinctive language? Every original programming
language you learn helps you mediate about concerns in original ways. Forth is intensely
straightforward to learn, but it completely requires you to mediate in a clear formulation than you’re used
to. That makes it a excellent language to broaden your coding horizons.

This e book comprises a straightforward implementation of Forth I wrote in JavaScript. It’s by
no intention excellent, and is missing most of the efficiency you’d question in an real
Forth scheme. It’s factual right here to give you a straightforward formulation to investigate cross-check the examples. (If
you’re a Forth expert, please
make contributions right here and fabricate it better!)

I’m going to take that you know at least one other programming language, and have
a general belief of how stacks work as an info structure.

Along with Some Numbers

The thing that separates Forth from most other languages is its utilize of the
stack. In Forth, every little thing revolves at some stage within the stack. Any time you form a
number, it will get pushed onto the stack. While you’d esteem to add two numbers together,
typing + takes the head two numbers off the stack, provides them, and puts
the tip end result again on the stack.

Let’s take a seek for at an instance. Kind (don’t reproduction-paste) the next into the
interpreter, typing Enter after each and every line.

1
2
3

Every time you form a line followed by the Enter key, the Forth interpreter
executes that line, and appends the string okay to permit you to know there were no
errors. That you just can ought to restful additionally detect that as you originate each and every line, the dwelling on the
top fills up with numbers. That dwelling is our visualization of the stack. It
can ought to restful seek for esteem this:

1 2 3 <- Top

Now, into the identical interpreter, form a single + followed by the Enter key. The pinnacle two
parts on the stack, 2 and 3, were changed by 5.

1 5 <- Top

At this level, your editor window can ought to restful seek for esteem this:

1 okay
2 okay
3 okay
+ okay

Kind + as soon as more and press Enter, and the head two parts will probably be changed by 6. If
you form + one extra time, Forth will attempt to pop the head two parts off the
stack, even supposing there’s biggest one component on the stack! This results in a
Stack underflow error:

1 okay
2 okay
3 okay
+ okay
+ okay
+ Stack underflow

Forth doesn’t power you to form each and every token as a separate line. Kind the
following into the next editor, followed by the Enter key:

123 456 +

The stack can ought to restful now seek for esteem this:

579 <- Top

This model, the assign the operator appears to be like after the operands, is identified as
Reverse-Polish
notation
. Let’s attempt
something pretty extra subtle, and calculate 10 (5 + 2). Kind the
following into the interpreter:

5 2 + 10 

One in every of the excellent issues about Forth is that the reveal of operations is
fully in response to their reveal within the program. Let’s scream, when executing 5
2 + 10 *
, the interpreter pushes 5 to the stack, then 2, then provides them and
pushes the resulting 7, then pushes 10 to the stack, then multiplies 7 and 10.
Which skill, there’s no need for parentheses to crew operators with lower
precedence.

Stack Effects

Most Forth phrases impact the stack in some formulation. Some take values off the stack,
some stir away original values on the stack, and some originate a aggregate of both. These “stack
results” are frequently represented the usage of comments of the fabricate ( before -- after
)
. Let’s scream, + is ( n1 n2 -- sum )n1 and n2 are the head two numbers
on the stack, and sum is the value left on the stack.

Defining Words

The syntax of Forth is intensely straightforward. Forth code is interpreted as
a chain of dwelling-delimited phrases. Nearly all non-whitespace characters are right
in phrases. When the Forth interpreter reads a phrase, it tests to win if a
definition exists in an internal structure identified as the Dictionary. If it’s
chanced on, that definition is performed. Otherwise, the phrase is belief to be a
number, and it’s pushed onto the stack. If the phrase can’t be converted to a
number, an error occurs.

You’d also attempt that out yourself below. Kind foo (an unrecognized phrase)
and press enter.

That you just can ought to restful note something esteem this:

foo foo ?

foo ? intention that Forth was unable to win a definition for foo, and it
wasn’t a right number.

We are in a position to safe our own definition of foo the usage of two special phrases known as :
(colon) and ; (semicolon). : is our formulation of telling Forth we desire to safe
a definition. The first phrase after the : turns into the definition name, and the
remainder of the phrases (unless the ;) fabricate up the body of the definition. It’s
feeble to consist of two areas between the name and the body of the
definition. Are attempting coming into the next:

: foo  100 + ;
1000 foo
foo foo foo

Warning: A general mistake is to head away out out the dwelling before the ; phrase. Because of Forth
phrases are dwelling delimited and can maintain most characters, +; is a completely
right phrase and is now not always parsed as two separate phrases.

As you’ve expectantly found out, our foo phrase merely provides 100 to the value on
top of the stack. It’s no longer very engaging, but it completely can ought to restful give you an belief of
how easy definitions work.

Stack Manipulation

Now we can open taking a seek for at some of Forth’s predefined phrases. First,
let’s seek for at some phrases for manipulating the parts on the head of the stack.

dup ( n -- n n )

dup is immediate for “replica” – it duplicates the head component of the stack. Let’s scream,
place that out:

1 2 3 dup

That you just can ought to restful discontinuance up with the next stack:

1 2 3 3 <- Top

fall ( n -- )

fall merely drops the head component of the stack. Running:

1 2 3 fall

offers you a stack of:

1 2 <- Top

swap ( n1 n2 -- n2 n1 )

swap, as you can also have guessed, swaps the head two parts of the stack. Let’s scream:

1 2 3 4 swap

will give you:

1 2 4 3 <- Top

over ( n1 n2 -- n1 n2 n1 )

over in all fairness much less glaring: it takes the 2nd component from the head of the
stack and duplicates it to the head of the stack. Running this:

1 2 3 over

will end result in this:

1 2 3 2 <- Top

rot ( n1 n2 n3 -- n2 n3 n1 )

Lastly, rot “rotates” the head three parts of the stack. The third
component from the head of the stack will get moved to the head of the stack, pushing
the opposite two parts down.

1 2 3 rot

offers you:

2 3 1 <- Top

Producing Output

Subsequent, let’s seek for at some phrases for outputting textual content to the console.

. ( n -- ) (period)

The most classic output phrase in Forth is .. You’d also utilize . to output the head of
the stack within the output of the scorching line. Let’s scream, attempt running this
(fabricate obvious to consist of the whole areas!):

1 . 2 . 3 . 4 5 6 . . .

That you just can ought to restful note this:

1 . 2 . 3 . 4 5 6 . . . 1 2 3 6 5 4 okay

Going thru this in reveal, we push 1, then pop it off and output it. Then
we originate the identical with 2 and 3. Subsequent we push 4, 5, and 6 onto the stack.
We then pop them off and output them one-by-one. That’s why the final three
numbers within the output are reversed: the stack is final in, first out.

emit ( c -- )

emit would possibly perhaps well even be used to output numbers as ascii characters. Ethical esteem . outputs
the number on the head of the stack, emit outputs that number as an ascii
personality. Let’s scream:

 33 119 111 87 emit emit emit emit

I won’t give the output right here in an effort to no longer kill the surprise. This would possibly perhaps well presumably additionally be
written as:

87 emit 111 emit 119 emit 33 emit

Now not like ., emit doesn’t output any dwelling after each and every personality, enabling you
to safe arbitrary strings of output.

cr ( -- )

cr is immediate for carriage return – it merely outputs a newline:

cr 100 . cr 200 . cr 300 .

This would possibly perhaps output:

cr 100 . cr 200 . cr 300 .
100
200
300 okay

." ( -- )

Lastly we’ve ." – a clear phrase for outputting strings. The ." phrase works
in a totally different intention internal definitions to interactive mode. ." marks the origin of
a string to output, and the tip of the string is marked by ". The closing "
isn’t a phrase, and so doesn’t ought to be dwelling-delimited. Right here’s an instance:

: scream-hello  ." Hey there!" ;
scream-hello

That you just can ought to restful note the next output

scream-hello Hey there! okay

We are in a position to combine .", ., cr, and emit to safe extra advanced output:

: print-stack-top  cr dup ." The pinnacle of the stack is " .
  cr ." which appears to be like to be like esteem '" dup emit ." ' in ascii  " ;
48 print-stack-top

Running this can ought to restful present the next output:

48 print-stack-top
The pinnacle of the stack is 48
which appears to be like to be like esteem ‘0’ in ascii okay

Conditionals and Loops

Now onto the enjoyable stuff! Forth, esteem most other languages, has conditionals and
loops for controlling the bound of your program. To esteem how they work,
nonetheless, first we’ve to achieve booleans in Forth.

Booleans

There’s the truth is no boolean form in Forth. The number 0 is handled as fraudulent,
and another number is nice, even supposing the canonical perfect value is -1 (all
boolean operators return 0 or -1).

To study if two numbers are equal, you can utilize =:

3 4 = .
5 5 = .

This can ought to restful output:

3 4 = . 0 okay
5 5 = . -1 okay

You’d also utilize < and > for lower than and increased than. < checks to see if the
second item from the top of the stack is less than the top item of the stack, and
vice versa for >:

3 4 < .
3 4 > .

3 4 < . -1 ok
3 4 > . 0 okay

The boolean operators And, Or, and Now not are readily available as and, or, and invert:

3 4 < 20 30 < and .
3 4 < 20 30 > or .
3 4 < invert .

The first line is the identical of 3 < 4 & 20 < 30 in a C-essentially essentially based language.
The 2nd line is the identical of 3 < 4 | 20 > 30. The third line is the
identical of !(3 < 4).

and, or, and invert are all bitwise operations. For correctly-formed flags
(0 and -1) they’ll work as anticipated, but they’ll give unsuitable results for
arbitrary numbers.

if then

Now we can at final catch onto conditionals. Conditionals in Forth can biggest be
used internal definitions. The most classic conditional observation in Forth is if
then
, which is the same to a normal if observation in most languages.
Right here’s an instance of a definition the usage of if then. In this instance, we’re additionally
the usage of the mod phrase, which returns the modulo of the head two numbers on the
stack. In this case, the head number is 5, and the opposite is whatever was placed
on the stack before calling buzz?. Therefore, 5 mod 0 = is a boolean
expression that tests to win if the head of the stack is divisible by 5.

: buzz?  5 mod 0 = if ." Buzz" then ;
3 buzz?
4 buzz?
5 buzz?

This would possibly perhaps output:

3 buzz? okay
4 buzz? okay
5 buzz? Buzz okay

It’s distinguished to repeat that the then phrase marks the tip of the if observation.
This makes it identical to fi in Bash or discontinuance in Ruby, as an illustration.

Any other distinguished thing to value is that if consumes the head value on the
stack when it tests to win if it’s perfect or fraudulent.

if else then

if else then is the same to an if/else observation in most languages. Right here’s
an instance of its utilize:

: is-it-zero?  0 = if ." Yes!" else ." No!" then ;
0 is-it-zero?
1 is-it-zero?
2 is-it-zero?

This outputs:

0 is-it-zero? Yes! okay
1 is-it-zero? No! okay
2 is-it-zero? No! okay

This time, the if clause (consequent) is every little thing between if and else,
and the else clause (alternative) is every little thing between else and then.

originate loop

originate loop in Forth most carefully resembles a for loop in most C-essentially essentially based languages.
Within the body of a originate loop, the special phrase i pushes the scorching loop index
onto the stack.

The pinnacle two values on the stack give the starting value (inclusive) and ending
value (uncommon) for the i value. The starting value is taken from the head
of the stack. Right here’s an instance:

: loop-check  10 0 originate i . loop ;
loop-check

This can ought to restful output:

loop-check 0 1 2 3 4 5 6 7 8 9 okay

The expression 10 0 originate i . loop is roughly identical to:

for (int i = 0; i < 10; i++) {
  print(i);
}

Fizz Buzz

We are in a position to put in writing the typical Fizz Buzz
program without concerns the usage of a originate loop:

: fizz?  3 mod 0 = dup if ." Fizz" then ;
: buzz?  5 mod 0 = dup if ." Buzz" then ;
: fizz-buzz?  dup fizz? swap buzz? or invert ;
: originate-fizz-buzz  25 1 originate cr i fizz-buzz? if i . then loop ;
originate-fizz-buzz

fizz? tests to win if the head of the stack is divisible by 3 the usage of 3 mod 0
=
. It then makes utilize of dup to replica this end result. The pinnacle reproduction of the value is
consumed by if. The 2nd reproduction is left on the stack and acts as the return
value of fizz?.

If the number on top of the stack is divisible by 3, the string "Fizz" will
be output, in another case there'll probably be no output.

buzz? does the identical thing but with 5, and outputs the string "Buzz".

fizz-buzz? calls dup to replica the value on top of the stack, then calls
fizz?, converting the head reproduction into a boolean. After this, the head of the
stack includes the distinctive value, and the boolean returned by fizz?.
swap swaps these, so the distinctive top-of-stack value is again on top, and the
boolean is below. Subsequent we name buzz?, which replaces the head-of-stack
value with a boolean flag. Now the head two values on the stack are booleans
representing whether the number was divisible by 3 or 5. After this, we name
or to win if both of these is nice, and invert to say this value.
Logically, the body of fizz-buzz? is the same to:

!(x % 3 == 0 || x % 5 == 0)

Therefore, fizz-buzz? returns a boolean indicating if the argument is no longer
divisible by 3 or 5, and thus can ought to restful be printed. Lastly, originate-fizz-buzz loops
from 1 to 25, calling fizz-buzz? on i, and outputting i if fizz-buzz?
returns perfect.

While you’re having misfortune determining what’s happening internal fizz-buzz?, the
instance below would possibly perhaps well presumably permit you to to achieve how it works. All we’re doing right here
is executing each and every phrase of the definition of fizz-buzz? on a separate line. As
you originate each and every line, note the stack to win how it changes:

: fizz?  3 mod 0 = dup if ." Fizz" then ;
: buzz?  5 mod 0 = dup if ." Buzz" then ;
4
dup
fizz?
swap
buzz?
or
invert

Right here’s how each and every line affects the stack:

4         4 <- Top
dup       4 4 <- Top
fizz?     4 0 <- Top
swap      0 4 <- Top
buzz?     0 0 <- Top
or        0 <- Top
invert    -1 <- Top

Be awake, the remaining value on the stack is the return value of the fizz-buzz?
phrase. In this case, it’s perfect, since the number was no longer divisible by 3 or 5,
and so can ought to restful be printed.

Right here’s the identical thing but starting with 5:

5         5 <- Top
dup       5 5 <- Top
fizz?     5 0 <- Top
swap      0 5 <- Top
buzz?     0 -1 <- Top
or        -1 <- Top
invert    0 <- Top

In this case the distinctive top-of-stack value was divisible by 5, so nothing
can ought to restful be printed.

Variables and Constants

Forth additionally lets you assign values in variables and constants. Variables allow
you to support video display of fixing values without needing to store them on the stack.
Constants give you a straightforward formulation to discuss with a label that won’t exchange.

Variables

Since the role of local variables is assuredly played by the stack, variables
in Forth are used extra to store command that will probably be needed at some stage in multiple
phrases.

Defining variables is modest:

variable steadiness

This assuredly mates a explicit reminiscence blueprint with the name steadiness.
steadiness is now a phrase, and all it does is to push its reminiscence blueprint onto the
stack:

variable steadiness
steadiness

That you just can ought to restful note the value 1000 on the stack. This Forth implementation arbitrarily
starts storing variables on the reminiscence blueprint 1000.

The phrase ! shops a label on the reminiscence blueprint referenced by a variable, and the
phrase @ fetches the value from a reminiscence blueprint:

variable steadiness
123 steadiness !
steadiness @

This time you are going to ought to restful note the value 123 on the stack. 123 steadiness pushes the
value and the reminiscence blueprint onto the stack, and ! shops that value at that
reminiscence blueprint. Likewise, @ retrieves the value in response to the reminiscence blueprint,
and pushes that value onto the stack. While you’ve used C or C++, you can mediate of
steadiness as a pointer that is dereferenced by @.

The phrase ? is defined as @ . and it prints the scorching value of a variable.
The phrase +! is used to amplify the value of a variable by a obvious amount
(esteem += in C-essentially essentially based languages).

variable steadiness
123 steadiness !
steadiness ?
50 steadiness +!
steadiness ?

Flee this code and likewise you are going to ought to restful note:

variable steadiness okay
123 steadiness ! okay
steadiness ? 123 okay
50 steadiness +! okay
steadiness ? 173 okay

Constants

If in case you have gotten a label that doesn’t exchange, you can store it as a fixed. Constants
are defined in a single line, esteem this:

42 fixed acknowledge

This creates a original fixed known as acknowledge with the value 42. Now not like variables,
constants factual signify values, pretty than reminiscence areas, so there’s no need
to utilize @.

42 fixed acknowledge
2 acknowledge 

Running this will probably push the value 84 on the stack. acknowledge is handled as if it
was the number it represents (factual esteem constants and variables in other languages).

Arrays

Forth doesn’t precisely support arrays, but it completely does let you allocate a zone of
contiguous reminiscence, loads esteem arrays in C. To allocate this reminiscence, utilize the allot
phrase.

variable numbers
3 cells allot
10 numbers 0 cells + !
20 numbers 1 cells + !
30 numbers 2 cells + !
40 numbers 3 cells + !

This case creates a reminiscence blueprint known as numbers, and reserves three extra
reminiscence cells after this blueprint, giving a total of four reminiscence cells. (cells
factual multiplies by the cell-width, which is 1 in this implementation.)

numbers 0 + offers the take care of of the indispensable cell within the array. 10 numbers 0 + !
shops the value 10 within the indispensable cell of the array.

We are in a position to without concerns write phrases to simplify array access:

variable numbers
3 cells allot
: number  ( offset -- addr )  cells numbers + ;

10 0 number !
20 1 number !
30 2 number !
40 3 number !

2 number ?

number takes an offset into numbers and returns the reminiscence take care of at that
offset. 30 2 number ! shops 30 at offset 2 in numbers, and 2 number ?
prints the value at offset 2 in numbers.

Keyboard Enter

Forth has a clear phrase known as key, which is used for accepting keyboard enter.
When the key phrase is performed, execution is paused unless a key's pressed. Once
a key's pressed, the indispensable code of that key's pushed onto the stack. Take a look at out the
following:

key . key . key .

While you proceed this line, you’ll detect that before every little thing nothing occurs. That is because
the interpreter is waiting for your keyboard enter. Are attempting hitting the A key, and
you are going to ought to restful note the keycode for that key, 65, seem as output on the scorching line.
Now hit B, then C, and likewise you are going to ought to restful note the next:

key . key . key . 65 66 67 okay

Printing keys with open unless

Forth has but any other fabricate of loop known as open unless. This works esteem a while
loop in C-essentially essentially based languages. Every time the phrase unless is hit, the interpreter
tests to win if the head of the stack is non-zero (perfect). If it's, it jumps
again to the matching open. If no longer, execution continues.

Right here’s an instance of the usage of open unless to print key codes:

: print-keycode  open key dup . 32 = unless ;
print-keycode

This would possibly perhaps support printing key codes unless you press dwelling. That you just can ought to restful note something esteem this:

print-keycode 80 82 73 78 84 189 75 69 89 67 79 68 69 32 okay

key waits for key enter, then dup duplicates the keycode from key. We
then utilize . to output the head reproduction of the keycode, and 32 = to check to win
if the keycode is the identical as 32. If it's, we spoil out of the loop, in another case we
loop again to open.

Snake!

Now it’s time to assign all of it together and fabricate a game! In command of having you form
the whole code, I’ve pre-loaded it into the editor.

Sooner than we seek for on the code, attempt playing the sport. To open the sport, originate the
phrase open. Then utilize the arrow keys to pass the snake. While you lose, you can proceed
open as soon as more.

Sooner than we delve too deeply into this code, two disclaimers. First, that is horrible
Forth code. I’m by no intention a Forth expert, so there’s doubtlessly each and every form of issues
I’m doing in fully the horrible formulation. Second, this game makes utilize of a number of non-current
tactics in reveal to interface with JavaScript. I’ll struggle thru these now.

Non-Standard Additions

The Canvas

You'd also have observed that this editor is varied from the others: it has an HTML5
Canvas component constructed in. I’ve created a beautiful easy reminiscence-mapped interface for
drawing onto this canvas. The canvas is split up into 24 x 24 “pixels” which is ready to
be sad or white. The first pixel is chanced on on the reminiscence take care of given by the
variable graphics, and the remainder of the pixels are offsets from the variable. So,
as an illustration, to blueprint a white pixel within the head-left corner you can proceed

1 graphics !

The game makes utilize of the next phrases to blueprint to the canvas:

: convert-x-y ( x y -- offset )  24 cells + ;
: blueprint ( color x y -- )  convert-x-y graphics + ! ;
: blueprint-white ( x y -- )  1 rot rot blueprint ;
: blueprint-sad ( x y -- )  0 rot rot blueprint ;

Let's scream, 3 4 blueprint-white draws a white pixel on the coordinates (3, 4). The
y coordinate is multiplied by 24 to catch the row, then the x coordinated is added
to catch the column.

Non-Blockading Keyboard Enter

The Forth phrase key blocks, so is inferior for a game esteem this. I’ve added
a variable known as final-key which continuously holds the value of the final key to be
pressed. final-key is biggest updated while the interpreter is running Forth code.

Random Quantity Technology

The Forth current doesn’t clarify a strategy of generating random numbers, so I’ve
added a phrase known as random ( range -- n ) that takes a range and returns a
random number from 0 to range - 1. Let's scream, 3 random would possibly perhaps well presumably
return 0, 1, or 2.

sleep ( ms -- )

Lastly, I’ve added a blocking sleep phrase that pauses execution for the
assortment of milliseconds given.

The Game Code

Now we can work thru the code from open to pause.

Variables and Constants

The open of the code factual fashions up some variables and constants:

variable snake-x-head
500 cells allot

variable snake-y-head
500 cells allot

variable apple-x
variable apple-y

0 fixed left
1 fixed up
2 fixed factual
3 fixed down

24 fixed width
24 fixed top

variable course
variable size

snake-x-head and snake-y-head are reminiscence areas used to store the x and
y coordinates of the head of the snake. 500 cells of reminiscence are alloted after
these two areas to store the coordinates of the tail of the snake.

Subsequent we clarify two phrases for getting access to reminiscence areas representing the body
of the snake.

: snake-x ( offset -- take care of )
  cells snake-x-head + ;

: snake-y ( offset -- take care of )
  cells snake-y-head + ;

Ethical esteem the number phrase earlier, these two phrases are used to access
parts within the arrays of snake segments. After this approach some phrases for
drawing to the canvas, described above.

We utilize constants to discuss with the four directions (left, up, factual, and
down), and a variable course to store the scorching course.

Initialization

After this we initialize every little thing:

: blueprint-partitions
  width 0 originate
    i 0 blueprint-sad
    i top 1 - blueprint-sad
  loop
  top 0 originate
    0 i blueprint-sad
    width 1 - i blueprint-sad
  loop ;

: initialize-snake
  4 size !
  size @ 1 + 0 originate
    12 i - i snake-x !
    12 i snake-y !
  loop
  factual course ! ;

: command-apple-command apple-x ! apple-y ! ;

: initialize-apple  4 4 command-apple-command ;

: initialize
  width 0 originate
    top 0 originate
      j i blueprint-white
    loop
  loop
  blueprint-partitions
  initialize-snake
  initialize-apple ;

blueprint-partitions makes utilize of two originate/loops to blueprint the horizontal and vertical partitions,
respectively.

initialize-snake fashions the size variable to 4, then loops from 0 to
size + 1 filling within the starting snake positions. The snake positions are
continuously saved one longer than the dimensions so we can develop the snake without concerns.

command-apple-command and initialize-apple command the initial command of the
apple to (4,4).

Lastly, initialize fills every little thing in white and calls the three
initialization phrases.

Transferring the Snake

Right here’s the code for spirited the snake in response to the scorching value of course:

: pass-up  -1 snake-y-head +! ;
: pass-left  -1 snake-x-head +! ;
: pass-down  1 snake-y-head +! ;
: pass-factual  1 snake-x-head +! ;

: pass-snake-head  course @
  left over  = if pass-left else
  up over    = if pass-up else
  factual over = if pass-factual else
  down over  = if pass-down
  then then then then fall ;

 Transfer each and every segment of the snake forward by one
: pass-snake-tail  0 size @ originate
    i snake-x @ i 1 + snake-x !
    i snake-y @ i 1 + snake-y !
  -1 +loop ;

pass-up, pass-left, pass-down, and pass-factual factual add or subtract one
from the x or y coordinate of the snake head. pass-snake-head inspects the
value of course and calls the correct pass-* phrase. This over = if
pattern is an idiomatic formulation of doing case statements in Forth.

pass-snake-tail goes thru the array of snake positions backwards, copying
each and every value forward by 1 cell. That is is believed as before we pass the snake head, to
pass each and every segment of the snake forward one dwelling. It makes utilize of a originate/+loop, a
variation of a originate/loop that pops the stack on each and every iteration and provides that
value to the next index, in its place of incrementing by 1 each and every time. So 0 size @
originate -1 +loop
loops from size to 0 in increments of -1.

Keyboard Enter

The next share of code takes the keyboard enter and changes the snake course
if relevant.

: is-horizontal  course @ dup
  left = swap
  factual = or ;

: is-vertical  course @ dup
  up = swap
  down = or ;

: turn-up     is-horizontal if up course ! then ;
: turn-left   is-vertical if left course ! then ;
: turn-down   is-horizontal if down course ! then ;
: turn-factual  is-vertical if factual course ! then ;

: exchange-course ( key -- )
  37 over = if turn-left else
  38 over = if turn-up else
  39 over = if turn-factual else
  40 over = if turn-down
  then then then then fall ;

: check-enter
  final-key @ exchange-course
  0 final-key ! ;

is-horizontal and is-vertical check the scorching assign of residing of the course
variable to win if it’s a horizontal or vertical course.

The turn-* phrases are used to command a original course, but utilize is-horizontal and
is-vertical to check the scorching course first to win if the original course
is good. Let's scream, if the snake is spirited horizontally, surroundings a original
course of left or factual doesn’t fabricate sense.

exchange-course takes a key and calls the correct turn-* phrase if the
key was one in all the arrow keys. check-enter does the work of getting the final
key from the final-key pseudo-variable, calling exchange-course, then surroundings
final-key to 0 to level to that essentially the most most modern keypress has been dealt with.

The Apple

The next code is used for checking to win if the apple has been eaten, and if so,
spirited it to a original (random) blueprint. Also, if the apple has been eaten we develop
the snake.

 catch random x or y command within playable dwelling
: random-command ( -- pos )
  width 4 - random 2 + ;

: pass-apple
  apple-x @ apple-y @ blueprint-white
  random-command random-command
  command-apple-command ;

: develop-snake  1 size +! ;

: check-apple ( -- flag )
  snake-x-head @ apple-x @ =
  snake-y-head @ apple-y @ =
  and if
    pass-apple
    develop-snake
  then ;

random-command generates a random x or y coordinate within the variety of 2 to
width - 2. This prevents the apple from ever exhibiting factual next to the wall.

pass-apple erases the scorching apple (the usage of blueprint-white) then creates a original
pair of x/y coordinates for the apple the usage of random-command twice. Lastly,
it calls command-apple-command to pass the apple to the original coordinates.

develop-snake merely provides one to the size variable.

check-apple compares the x/y coordinates of the apple and the snake head to
note if they’re the identical (the usage of = twice and and to combine the two
booleans). If the coordinates are the identical, we name pass-apple to pass the
apple to a original command and develop-snake to fabricate the snake 1 segment longer.

Collision Detection

Subsequent we note if the snake has collided with the partitions or itself.

: check-collision ( -- flag )
   catch fresh x/y command
  snake-x-head @ snake-y-head @

   catch color at fresh command
  convert-x-y graphics + @

   stir away boolean flag on stack
  0 = ;

check-collision tests to win if the original snake head command is already sad
(this phrase is is believed as after updating the snake’s command but before drawing
it on the original command). We stir away a boolean on the stack to claim whether a
collision has occured or no longer.

Drawing the Snake and Apple

The next two phrases are accountable for drawing the snake and apple.

: blueprint-snake
  size @ 0 originate
    i snake-x @ i snake-y @ blueprint-sad
  loop
  size @ snake-x @
  size @ snake-y @
  blueprint-white ;

: blueprint-apple
  apple-x @ apple-y @ blueprint-sad ;

blueprint-snake loops thru each and every cell within the snake arrays, drawing a sad pixel
for every and every. After that it draws a white pixel at an offset of size. The
final share of the tail is at size - 1 into the array so size holds the
old final tail segment.

blueprint-apple merely draws a sad pixel on the apple’s fresh blueprint.

The Game Loop

The game loop continuously loops unless a collision occurs, calling each and every of the
phrases defined above in turn.

: game-loop ( -- )
  open
    blueprint-snake
    blueprint-apple
    100 sleep
    check-enter
    pass-snake-tail
    pass-snake-head
    check-apple
    check-collision
  unless
  ." Game Over" ;

: open  initialize game-loop ;

The open/unless loop makes utilize of the boolean returned by check-collision to win
whether to proceed looping or to exit the loop. When the loop is exited the
string "Game Over" is printed. We utilize 100 sleep to quit for 100 ms each and every
iteration, making the sport proceed at rougly 10 fps.

open factual calls initialize to reset every little thing, then kicks off game-loop.
Since the whole initialization occurs within the initialize phrase, you can name
open as soon as more after game over.


And that’s it! Optimistically the whole code within the sport made sense. If no longer, you can
attempt running particular particular person phrases to win their originate on the stack and/or on the
variables.

The Pause

Forth is de facto powerful extra extremely effective than what I’ve taught right here (and what I
applied in my interpreter). An even Forth scheme lets you vary how
the compiler works and safe original defining phrases, permitting you to fully
customise your environment and safe your own languages within Forth.

A substantial helpful resource for studying the chubby vitality of Forth is the immediate e book
“Beginning Forth” by Leo Brodie. It’s
readily available gratis online and teaches you the whole enjoyable stuff I skipped over. It additionally
has a merely command of exercises so that you can check out your info. You’ll ought to
download a reproduction of SwiftForth to proceed
the code though.

Related Articles

Back to top button