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
, the interpreter pushes 5 to the stack, then 2, then provides them and
2 + 10 *
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
, which is the same to a normal
thenif
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/loop
s 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 @
loops from
originate -1 +loopsize
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.