Oct 182020
 

https://dosbox-x.com/

 

DOSBox-X

Cross-platform DOS emulation package
Complete, accurate emulation and more

What is DOSBox-X?

DOSBox-X is an open-source DOS emulator for running DOS games and applications.
DOS-based Windows such as Windows 3.x and Windows 9x are officially supported.
Compared to DOSBox, DOSBox-X is much more flexible and provides more features.
Look at the DOSBox-X Wiki for more information about DOSBox-X and usage guides.

 Posted by at 5:24 pm
Apr 052020
 

 

https://skilldrick.github.io/easyforth/

 

Easy Forth

by Nick Morgan

View on GitHub

Introduction

This small ebook is here to teach you a programming language called Forth. Forth is a language unlike most others. It’s not functional or object oriented, it doesn’t have type-checking, and it basically has zero syntax. It was written in the 70s, but is still used today for certain applications.

Why would you want to learn such an odd language? Every new programming language you learn helps you think about problems in new ways. Forth is very easy to learn, but it requires you to think in a different way than you’re used to. That makes it a perfect language to broaden your coding horizons.

This book includes a simple implementation of Forth I wrote in JavaScript. It’s by no means perfect, and is missing a lot of the functionality you’d expect in a real Forth system. It’s just here to give you an easy way to try out the examples. (If you’re a Forth expert, please contribute here and make it better!)

I’m going to assume that you know at least one other programming language, and have a basic idea of how stacks work as a data structure.

Adding Some Numbers

The thing that separates Forth from most other languages is its use of the stack. In Forth, everything revolves around the stack. Any time you type a number, it gets pushed onto the stack. If you want to add two numbers together, typing + takes the top two numbers off the stack, adds them, and puts the result back on the stack.

Let’s take a look at an example. Type (don’t copy-paste) the following into the interpreter, typing Enter after each line.

1
2
3
<- Top

Every time you type a line followed by the Enter key, the Forth interpreter executes that line, and appends the string ok to let you know there were no errors. You should also notice that as you execute each line, the area at the top fills up with numbers. That area is our visualization of the stack. It should look like this:

1 2 3 <- Top

Now, into the same interpreter, type a single + followed by the Enter key. The top two elements on the stack, 2 and 3, have been replaced by 5.

1 5 <- Top

At this point, your editor window should look like this:

1 ok 2 ok 3 ok + ok

Type + again and press Enter, and the top two elements will be replaced by 6. If you type + one more time, Forth will try to pop the top two elements off the stack, even though there’s only one element on the stack! This results in a Stack underflow error:

1 ok 2 ok 3 ok + ok + ok + Stack underflow

Forth doesn’t force you to type every token as a separate line. Type the following into the next editor, followed by the Enter key:

123 456 +
<- Top

The stack should now look like this:

579 <- Top

This style, where the operator appears after the operands, is known as Reverse-Polish notation. Let’s try something a bit more complicated, and calculate 10 * (5 + 2). Type the following into the interpreter:

5 2 + 10 *
<- Top

One of the nice things about Forth is that the order of operations is completely based on their order in the program. For example, when executing 5 2 + 10 *, the interpreter pushes 5 to the stack, then 2, then adds them and pushes the resulting 7, then pushes 10 to the stack, then multiplies 7 and 10. Because of this, there’s no need for parentheses to group operators with lower precedence.

Stack Effects

Most Forth words affect the stack in some way. Some take values off the stack, some leave new values on the stack, and some do a mixture of both. These “stack effects” are commonly represented using comments of the form ( before -- after ). For example, + is ( n1 n2 -- sum ) – n1 and n2 are the top two numbers on the stack, and sum is the value left on the stack.

Defining Words

The syntax of Forth is extremely straightforward. Forth code is interpreted as a series of space-delimited words. Almost all non-whitespace characters are valid in words. When the Forth interpreter reads a word, it checks to see if a definition exists in an internal structure known as the Dictionary. If it is found, that definition is executed. Otherwise, the word is assumed to be a number, and it is pushed onto the stack. If the word cannot be converted to a number, an error occurs.

You can try that out yourself below. Type foo (an unrecognized word) and press enter.

<- Top

You should see something like this:

foo foo ?

foo ? means that Forth was unable to find a definition for foo, and it wasn’t a valid number.

We can create our own definition of foo using two special words called : (colon) and ; (semicolon). : is our way of telling Forth we want to create a definition. The first word after the : becomes the definition name, and the rest of the words (until the ;) make up the body of the definition. It’s conventional to include two spaces between the name and the body of the definition. Try entering the following:

: foo  100 + ;
1000 foo
foo foo foo

Warning: A common mistake is to miss out the space before the ; word. Because Forth words are space delimited and can contain most characters, +; is a perfectly valid word and is not parsed as two separate words.

<- Top

As you’ve hopefully figured out, our foo word simply adds 100 to the value on top of the stack. It’s not very interesting, but it should give you an idea of how simple definitions work.

Stack Manipulation

Now we can start taking a look at some of Forth’s predefined words. First, let’s look at some words for manipulating the elements at the top of the stack.

dup ( n -- n n )

dup is short for “duplicate” – it duplicates the top element of the stack. For example, try this out:

1 2 3 dup
<- Top

You should end up with the following stack:

1 2 3 3 <- Top

drop ( n -- )

drop simply drops the top element of the stack. Running:

1 2 3 drop

gives you a stack of:

1 2 <- Top
<- Top

swap ( n1 n2 -- n2 n1 )

swap, as you may have guessed, swaps the top two elements of the stack. For example:

1 2 3 4 swap

will give you:

1 2 4 3 <- Top
<- Top

over ( n1 n2 -- n1 n2 n1 )

over is a bit less obvious: it takes the second element from the top of the stack and duplicates it to the top of the stack. Running this:

1 2 3 over

will result in this:

1 2 3 2 <- Top
<- Top

rot ( n1 n2 n3 -- n2 n3 n1 )

Finally, rot “rotates” the top three elements of the stack. The third element from the top of the stack gets moved to the top of the stack, pushing the other two elements down.

1 2 3 rot

gives you:

2 3 1 <- Top
<- Top

Generating Output

Next, let’s look at some words for outputting text to the console.

. ( n -- ) (period)

The simplest output word in Forth is .. You can use . to output the top of the stack in the output of the current line. For example, try running this (make sure to include all the spaces!):

1 . 2 . 3 . 4 5 6 . . .
<- Top

You should see this:

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

Going through this in order, we push 1, then pop it off and output it. Then we do the same with 2 and 3. Next we push 45, and 6 onto the stack. We then pop them off and output them one-by-one. That’s why the last three numbers in the output are reversed: the stack is last in, first out.

emit ( c -- )

emit can be used to output numbers as ascii characters. Just like . outputs the number at the top of the stack, emit outputs that number as an ascii character. For example:

 33 119 111 87 emit emit emit emit
<- Top

I won’t give the output here so as to not ruin the surprise. This could also be written as:

87 emit 111 emit 119 emit 33 emit

Unlike .emit doesn’t output any space after each character, enabling you to build up arbitrary strings of output.

cr ( -- )

cr is short for carriage return – it simply outputs a newline:

cr 100 . cr 200 . cr 300 .
<- Top

This will output:

cr 100 . cr 200 . cr 300 . 100 200 300 ok

." ( -- )

Finally we have ." – a special word for outputting strings. The ." word works differently inside definitions to interactive mode. ." marks the beginning of a string to output, and the end of the string is marked by ". The closing " isn’t a word, and so doesn’t need to be space-delimited. Here’s an example:

: say-hello  ." Hello there!" ;
say-hello
<- Top

You should see the following output

say-hello Hello there! ok

We can combine .".cr, and emit to build up more complex output:

: print-stack-top  cr dup ." The top of the stack is " .
  cr ." which looks like '" dup emit ." ' in ascii  " ;
48 print-stack-top
<- Top

Running this should give you the following output:

48 print-stack-top The top of the stack is 48 which looks like ‘0’ in ascii ok

Conditionals and Loops

Now onto the fun stuff! Forth, like most other languages, has conditionals and loops for controlling the flow of your program. To understand how they work, however, first we need to understand booleans in Forth.

Booleans

There’s actually no boolean type in Forth. The number 0 is treated as false, and any other number is true, although the canonical true value is -1 (all boolean operators return 0 or -1).

To test if two numbers are equal, you can use =:

3 4 = .
5 5 = .

This should output:

3 4 = . 0 ok 5 5 = . -1 ok
<- Top

You can use < and > for less than and greater 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 ok
<- Top

The boolean operators And, Or, and Not are available as andor, and invert:

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

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

andor, and invert are all bitwise operations. For well-formed flags (0 and -1) they’ll work as expected, but they’ll give incorrect results for arbitrary numbers.

<- Top

if then

Now we can finally get onto conditionals. Conditionals in Forth can only be used inside definitions. The simplest conditional statement in Forth is if then, which is equivalent to a standard if statement in most languages. Here’s an example of a definition using if then. In this example, we’re also using the mod word, which returns the modulo of the top two numbers on the stack. In this case, the top number is 5, and the other is whatever was placed on the stack before calling buzz?. Therefore, 5 mod 0 = is a boolean expression that checks to see if the top of the stack is divisible by 5.

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

This will output:

3 buzz? ok 4 buzz? ok 5 buzz? Buzz ok

It’s important to note that the then word marks the end of the if statement. This makes it equivalent to fi in Bash or end in Ruby, for example.

Another important thing to realize is that if consumes the top value on the stack when it checks to see if it’s true or false.

if else then

if else then is equivalent to an if/else statement in most languages. Here’s an example of its use:

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

This outputs:

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

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

do loop

do loop in Forth most closely resembles a for loop in most C-based languages. In the body of a do loop, the special word i pushes the current loop index onto the stack.

The top two values on the stack give the starting value (inclusive) and ending value (exclusive) for the i value. The starting value is taken from the top of the stack. Here’s an example:

: loop-test  10 0 do i . loop ;
loop-test
<- Top

This should output:

loop-test 0 1 2 3 4 5 6 7 8 9 ok

The expression 10 0 do i . loop is roughly equivalent to:

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

Fizz Buzz

We can write the classic Fizz Buzz program easily using a do 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 ;
: do-fizz-buzz  25 1 do cr i fizz-buzz? if i . then loop ;
do-fizz-buzz
<- Top

fizz? checks to see if the top of the stack is divisible by 3 using 3 mod 0 =. It then uses dup to duplicate this result. The top copy of the value is consumed by if. The second copy 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, otherwise there will be no output.

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

fizz-buzz? calls dup to duplicate the value on top of the stack, then calls fizz?, converting the top copy into a boolean. After this, the top of the stack consists of the original value, and the boolean returned by fizz?swap swaps these, so the original top-of-stack value is back on top, and the boolean is underneath. Next we call buzz?, which replaces the top-of-stack value with a boolean flag. Now the top two values on the stack are booleans representing whether the number was divisible by 3 or 5. After this, we call or to see if either of these is true, and invert to negate this value. Logically, the body of fizz-buzz? is equivalent to:

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

Therefore, fizz-buzz? returns a boolean indicating if the argument is not divisible by 3 or 5, and thus should be printed. Finally, do-fizz-buzz loops from 1 to 25, calling fizz-buzz? on i, and outputting i if fizz-buzz? returns true.

If you’re having trouble figuring out what’s going on inside fizz-buzz?, the example below might help you to understand how it works. All we’re doing here is executing each word of the definition of fizz-buzz? on a separate line. As you execute each line, watch the stack to see 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
<- Top

Here’s how each 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

Remember, the final value on the stack is the return value of the fizz-buzz? word. In this case, it’s true, because the number was not divisible by 3 or 5, and so should be printed.

Here’s the same 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 original top-of-stack value was divisible by 5, so nothing should be printed.

Variables and Constants

Forth also allows you to save values in variables and constants. Variables allow you to keep track of changing values without having to store them on the stack. Constants give you a simple way to refer to a value that won’t change.

Variables

Because the role of local variables is generally played by the stack, variables in Forth are used more to store state that may be needed across multiple words.

Defining variables is simple:

variable balance

This basically associates a particular memory location with the name balancebalance is now a word, and all it does is to push its memory location onto the stack:

variable balance
balance
<- Top

You should see the value 1000 on the stack. This Forth implementation arbitrarily starts storing variables at the memory location 1000.

The word ! stores a value at the memory location referenced by a variable, and the word @ fetches the value from a memory location:

variable balance
123 balance !
balance @
<- Top

This time you should see the value 123 on the stack. 123 balance pushes the value and the memory location onto the stack, and ! stores that value at that memory location. Likewise, @ retrieves the value based on the memory location, and pushes that value onto the stack. If you’ve used C or C++, you can think of balance as a pointer that is dereferenced by @.

The word ? is defined as @ . and it prints the current value of a variable. The word +! is used to increase the value of a variable by a certain amount (like += in C-based languages).

variable balance
123 balance !
balance ?
50 balance +!
balance ?
<- Top

Run this code and you should see:

variable balance ok 123 balance ! ok balance ? 123 ok 50 balance +! ok balance ? 173 ok

Constants

If you have a value that doesn’t change, you can store it as a constant. Constants are defined in one line, like this:

42 constant answer

This creates a new constant called answer with the value 42. Unlike variables, constants just represent values, rather than memory locations, so there’s no need to use @.

42 constant answer
2 answer *
<- Top

Running this will push the value 84 on the stack. answer is treated as if it was the number it represents (just like constants and variables in other languages).

Arrays

Forth doesn’t exactly support arrays, but it does allow you to allocate a zone of contiguous memory, a lot like arrays in C. To allocate this memory, use the allot word.

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

This example creates a memory location called numbers, and reserves three extra memory cells after this location, giving a total of four memory cells. (cells just multiplies by the cell-width, which is 1 in this implementation.)

numbers 0 + gives the address of the first cell in the array. 10 numbers 0 + ! stores the value 10 in the first cell of the array.

We can easily write words 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 ?
<- Top

number takes an offset into numbers and returns the memory address at that offset. 30 2 number ! stores 30 at offset 2 in numbers, and 2 number ? prints the value at offset 2 in numbers.

Keyboard Input

Forth has a special word called key, which is used for accepting keyboard input. When the key word is executed, execution is paused until a key is pressed. Once a key is pressed, the key code of that key is pushed onto the stack. Try out the following:

key . key . key .
<- Top

When you run this line, you’ll notice that at first nothing happens. This is because the interpreter is waiting for your keyboard input. Try hitting the A key, and you should see the keycode for that key, 65, appear as output on the current line. Now hit B, then C, and you should see the following:

key . key . key . 65 66 67 ok

Printing keys with begin until

Forth has another kind of loop called begin until. This works like a while loop in C-based languages. Every time the word until is hit, the interpreter checks to see if the top of the stack is non-zero (true). If it is, it jumps back to the matching begin. If not, execution continues.

Here’s an example of using begin until to print key codes:

: print-keycode  begin key dup . 32 = until ;
print-keycode
<- Top

This will keep printing key codes until you press space. You should see something like this:

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

key waits for key input, then dup duplicates the keycode from key. We then use . to output the top copy of the keycode, and 32 = to check to see if the keycode is equal to 32. If it is, we break out of the loop, otherwise we loop back to begin.

Snake!

Now it’s time to put it all together and make a game! Rather than having you type all the code, I’ve pre-loaded it into the editor.

Before we look at the code, try playing the game. To start the game, execute the word start. Then use the arrow keys to move the snake. If you lose, you can run start again.

<- Top

variable snake-x-head ok

500 cells allot ok

ok

variable snake-y-head ok

500 cells allot ok

ok

variable apple-x ok

variable apple-y ok

ok

0 constant left ok

1 constant up ok

2 constant right ok

3 constant down ok

ok

24 constant width ok

24 constant height ok

ok

variable direction ok

variable length ok

ok

: snake-x ( offset — address )

cells snake-x-head + ; ok

ok

: snake-y ( offset — address )

cells snake-y-head + ; ok

ok

: convert-x-y ( x y — offset ) 24 cells * + ; ok

: draw ( color x y — ) convert-x-y graphics + ! ; ok

: draw-white ( x y — ) 1 rot rot draw ; ok

: draw-black ( x y — ) 0 rot rot draw ; ok

ok

: draw-walls

width 0 do

i 0 draw-black

i height 1 – draw-black

loop

height 0 do

0 i draw-black

width 1 – i draw-black

loop ; ok

ok

: initialize-snake

4 length !

length @ 1 + 0 do

12 i – i snake-x !

12 i snake-y !

loop

right direction ! ; ok

ok

: set-apple-position apple-x ! apple-y ! ; ok

ok

: initialize-apple 4 4 set-apple-position ; ok

ok

: initialize

width 0 do

height 0 do

j i draw-white

loop

loop

draw-walls

initialize-snake

initialize-apple ; ok

ok

: move-up -1 snake-y-head +! ; ok

: move-left -1 snake-x-head +! ; ok

: move-down 1 snake-y-head +! ; ok

: move-right 1 snake-x-head +! ; ok

ok

: move-snake-head direction @

left over = if move-left else

up over = if move-up else

right over = if move-right else

down over = if move-down

then then then then drop ; ok

ok

\ Move each segment of the snake forward by one ok

: move-snake-tail 0 length @ do

i snake-x @ i 1 + snake-x !

i snake-y @ i 1 + snake-y !

-1 +loop ; ok

ok

: is-horizontal direction @ dup

left = swap

right = or ; ok

ok

: is-vertical direction @ dup

up = swap

down = or ; ok

ok

: turn-up is-horizontal if up direction ! then ; ok

: turn-left is-vertical if left direction ! then ; ok

: turn-down is-horizontal if down direction ! then ; ok

: turn-right is-vertical if right direction ! then ; ok

ok

: change-direction ( key — )

37 over = if turn-left else

38 over = if turn-up else

39 over = if turn-right else

40 over = if turn-down

then then then then drop ; ok

ok

: check-input

last-key @ change-direction

0 last-key ! ; ok

ok

\ get random x or y position within playable area ok

: random-position ( — pos )

width 4 – random 2 + ; ok

ok

: move-apple

apple-x @ apple-y @ draw-white

random-position random-position

set-apple-position ; ok

ok

: grow-snake 1 length +! ; ok

ok

: check-apple

snake-x-head @ apple-x @ =

snake-y-head @ apple-y @ =

and if

move-apple

grow-snake

then ; ok

ok

: check-collision ( — flag )

\ get current x/y position

snake-x-head @ snake-y-head @

\ get color at current position

convert-x-y graphics + @

\ leave boolean flag on stack

0 = ; ok

ok

: draw-snake

length @ 0 do

i snake-x @ i snake-y @ draw-black

loop

length @ snake-x @

length @ snake-y @

draw-white ; ok

ok

: draw-apple

apple-x @ apple-y @ draw-black ; ok

ok

ok

: game-loop ( — )

begin

draw-snake

draw-apple

100 sleep

check-input

move-snake-tail

move-snake-head

check-apple

check-collision

until

.” Game Over” ; ok

ok

: start initialize game-loop ; ok

ok

Before we delve too deeply into this code, two disclaimers. First, this is terrible Forth code. I’m by no means a Forth expert, so there’s probably all kinds of things I’m doing in completely the wrong way. Second, this game uses a few non-standard techniques in order to interface with JavaScript. I’ll go through these now.

Non-Standard Additions

The Canvas

You may have noticed that this editor is different from the others: it has an HTML5 Canvas element built in. I’ve created a very simple memory-mapped interface for drawing onto this canvas. The canvas is split up into 24 x 24 “pixels” which can be black or white. The first pixel is found at the memory address given by the variable graphics, and the rest of the pixels are offsets from the variable. So, for example, to draw a white pixel in the top-left corner you could run

1 graphics !
<- Top

The game uses the following words to draw to the canvas:

: convert-x-y ( x y -- offset )  24 cells * + ;
: draw ( color x y -- )  convert-x-y graphics + ! ;
: draw-white ( x y -- )  1 rot rot draw ;
: draw-black ( x y -- )  0 rot rot draw ;

For example, 3 4 draw-white draws a white pixel at the coordinates (3, 4). The y coordinate is multiplied by 24 to get the row, then the x coordinated is added to get the column.

Non-Blocking Keyboard Input

The Forth word key blocks, so is unsuitable for a game like this. I’ve added a variable called last-key which always holds the value of the last key to be pressed. last-key is only updated while the interpreter is running Forth code.

Random Number Generation

The Forth standard doesn’t define a way of generating random numbers, so I’ve added a word called random ( range -- n ) that takes a range and returns a random number from 0 to range – 1. For example, 3 random could return 01, or 2.

sleep ( ms -- )

Finally, I’ve added a blocking sleep word that pauses execution for the number of milliseconds given.

The Game Code

Now we can work through the code from start to finish.

Variables and Constants

The start of the code just sets 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 constant left
1 constant up
2 constant right
3 constant down

24 constant width
24 constant height

variable direction
variable length

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

Next we define two words for accessing memory locations representing the body of the snake.

: snake-x ( offset -- address )
  cells snake-x-head + ;

: snake-y ( offset -- address )
  cells snake-y-head + ;

Just like the number word earlier, these two words are used to access elements in the arrays of snake segments. After this come some words for drawing to the canvas, described above.

We use constants to refer to the four directions (leftupright, and down), and a variable direction to store the current direction.

Initialization

After this we initialize everything:

: draw-walls
  width 0 do
    i 0 draw-black
    i height 1 - draw-black
  loop
  height 0 do
    0 i draw-black
    width 1 - i draw-black
  loop ;

: initialize-snake
  4 length !
  length @ 1 + 0 do
    12 i - i snake-x !
    12 i snake-y !
  loop
  right direction ! ;

: set-apple-position apple-x ! apple-y ! ;

: initialize-apple  4 4 set-apple-position ;

: initialize
  width 0 do
    height 0 do
      j i draw-white
    loop
  loop
  draw-walls
  initialize-snake
  initialize-apple ;

draw-walls uses two do/loops to draw the horizontal and vertical walls, respectively.

initialize-snake sets the length variable to 4, then loops from 0 to length + 1 filling in the starting snake positions. The snake positions are always kept one longer than the length so we can grow the snake easily.

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

Finally, initialize fills everything in white and calls the three initialization words.

Moving the Snake

Here’s the code for moving the snake based on the current value of direction:

: move-up  -1 snake-y-head +! ;
: move-left  -1 snake-x-head +! ;
: move-down  1 snake-y-head +! ;
: move-right  1 snake-x-head +! ;

: move-snake-head  direction @
  left over  = if move-left else
  up over    = if move-up else
  right over = if move-right else
  down over  = if move-down
  then then then then drop ;

\ Move each segment of the snake forward by one
: move-snake-tail  0 length @ do
    i snake-x @ i 1 + snake-x !
    i snake-y @ i 1 + snake-y !
  -1 +loop ;

move-upmove-leftmove-down, and move-right just add or subtract one from the x or y coordinate of the snake head. move-snake-head inspects the value of direction and calls the appropriate move-* word. This over = if pattern is an idiomatic way of doing case statements in Forth.

move-snake-tail goes through the array of snake positions backwards, copying each value forward by 1 cell. This is called before we move the snake head, to move each segment of the snake forward one space. It uses a do/+loop, a variation of a do/loop that pops the stack on every iteration and adds that value to the next index, instead of incrementing by 1 each time. So 0 length @ do -1 +loop loops from length to 0 in increments of -1.

Keyboard Input

The next section of code takes the keyboard input and changes the snake direction if appropriate.

: is-horizontal  direction @ dup
  left = swap
  right = or ;

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

: turn-up     is-horizontal if up direction ! then ;
: turn-left   is-vertical if left direction ! then ;
: turn-down   is-horizontal if down direction ! then ;
: turn-right  is-vertical if right direction ! then ;

: change-direction ( key -- )
  37 over = if turn-left else
  38 over = if turn-up else
  39 over = if turn-right else
  40 over = if turn-down
  then then then then drop ;

: check-input
  last-key @ change-direction
  0 last-key ! ;

is-horizontal and is-vertical check the current status of the direction variable to see if it’s a horizontal or vertical direction.

The turn-* words are used to set a new direction, but use is-horizontal and is-vertical to check the current direction first to see if the new direction is valid. For example, if the snake is moving horizontally, setting a new direction of left or right doesn’t make sense.

change-direction takes a key and calls the appropriate turn-* word if the key was one of the arrow keys. check-input does the work of getting the last key from the last-key pseudo-variable, calling change-direction, then setting last-key to 0 to indicate that the most recent keypress has been dealt with.

The Apple

The next code is used for checking to see if the apple has been eaten, and if so, moving it to a new (random) location. Also, if the apple has been eaten we grow the snake.

\ get random x or y position within playable area
: random-position ( -- pos )
  width 4 - random 2 + ;

: move-apple
  apple-x @ apple-y @ draw-white
  random-position random-position
  set-apple-position ;

: grow-snake  1 length +! ;

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

random-position generates a random x or y coordinate in the range of 2 to width - 2. This prevents the apple from ever appearing right next to the wall.

move-apple erases the current apple (using draw-white) then creates a new pair of x/y coordinates for the apple using random-position twice. Finally, it calls set-apple-position to move the apple to the new coordinates.

grow-snake simply adds one to the length variable.

check-apple compares the x/y coordinates of the apple and the snake head to see if they’re the same (using = twice and and to combine the two booleans). If the coordinates are the same, we call move-apple to move the apple to a new position and grow-snake to make the snake 1 segment longer.

Collision Detection

Next we see if the snake has collided with the walls or itself.

: check-collision ( -- flag )
  \ get current x/y position
  snake-x-head @ snake-y-head @

  \ get color at current position
  convert-x-y graphics + @

  \ leave boolean flag on stack
  0 = ;

check-collision checks to see if the new snake head position is already black (this word is called after updating the snake’s position but before drawing it at the new position). We leave a boolean on the stack to say whether a collision has occured or not.

Drawing the Snake and Apple

The next two words are responsible for drawing the snake and apple.

: draw-snake
  length @ 0 do
    i snake-x @ i snake-y @ draw-black
  loop
  length @ snake-x @
  length @ snake-y @
  draw-white ;

: draw-apple
  apple-x @ apple-y @ draw-black ;

draw-snake loops through each cell in the snake arrays, drawing a black pixel for each one. After that it draws a white pixel at an offset of length. The last part of the tail is at length - 1 into the array so length holds the previous last tail segment.

draw-apple simply draws a black pixel at the apple’s current location.

The Game Loop

The game loop constantly loops until a collision occurs, calling each of the words defined above in turn.

: game-loop ( -- )
  begin
    draw-snake
    draw-apple
    100 sleep
    check-input
    move-snake-tail
    move-snake-head
    check-apple
    check-collision
  until
  ." Game Over" ;

: start  initialize game-loop ;

The begin/until loop uses the boolean returned by check-collision to see whether to continue looping or to exit the loop. When the loop is exited the string "Game Over" is printed. We use 100 sleep to pause for 100 ms every iteration, making the game run at rougly 10 fps.

start just calls initialize to reset everything, then kicks off game-loop. Because all the initialization happens in the initialize word, you can call start again after game over.


And that’s it! Hopefully all the code in the game made sense. If not, you can try running individual words to see their effect on the stack and/or on the variables.

The End

Forth is actually much more powerful than what I’ve taught here (and what I implemented in my interpreter). A true Forth system allows you to modify how the compiler works and create new defining words, allowing you to completely customize your environment and create your own languages within Forth.

A great resource for learning the full power of Forth is the short book “Starting Forth” by Leo Brodie. It’s available for free online and teaches you all the fun stuff I left out. It also has a good set of exercises for you to test out your knowledge. You’ll need to download a copy of SwiftForth to run the code though.

 Posted by at 6:11 am
Apr 062019
 

http://cestmir.freeside.sk/projects/dhtml-nixie-display/

 

Virtual nixie tube (digitron) display – DHTML component library

© 2007-08 Čestmír Hýbl <cestmir.hybl@nustep.net>

Current date (NixieDisplay example)

Current time (NixieClock example)

Calculator (NixieCalculator example)

(just type expressions on keyboard as on any basic electronic calculator)
[q] sqrt   [Q] sqr   [^] pow   [m] +/-   [p] PI   [Enter] =   [Esc] clear

About

This DHTML component collection was developed for fun and is meant as tribute to nixie tube display era.

Features:

  • object-oriented JavaScript, DHTML, CSS
  • simple, well-designed API
  • fully customizable (custom glyph matrix images, between-digit gaps, custom character support using configurable map from char to glyph index)
  • decimal separator support via separate glyph matrix row
  • should be compatible with any modern browser (tested in IE 6.0, FF 2.0, Opera 8.5)

Notices:

  • included nixie glyphs were taken using real nixie tubes (Philips ZM1080, Tesla ZM1082, RFT Z573M). Decimal point and minus signs were added artificially for devices not containing them.
  • components are not limited to emulate nixie-looking displays, glyphs containing any sign types can be used

Usage

(suppose you have package archive extracted in ./nixie directory)

1. include library in head section of the page:

    <script type="text/javascript" src="nixie/nixie.js"></script>

2. drop some box element to serve as display container:

    <div id="nd1"></div>

3. instantiate and use component:

    <script type="text/javascript">
      var nd = new NixieDisplay();
      nd.id = 'nd1';
      nd.charCount = 12;
      nd.urlCharsetImage = 'nixie/nixie/zm1082_l1_09bdm_62x150_8b.png';
      nd.charWidth = 62;
      nd.charHeight = 150;
      nd.charGapWidth = 5;
      nd.align = 'right';
      nd.init();

      nd.setText('-1.234567890');
    </script>

Explore library and this demo page sources for more info.

Download

  • nixie_display_20080214a.zip [1032 kB]
    • DHTML component package (including several screen-resolution glyph matrices)
    • changelog:
      2012-10-08 rev. 20080214a: Calculator: Chrome [Esc] handlig bug fix
  • nixie_display_fullres_glyphs_20080214.zip [8.9 MB]
    • high-resolution photos of nixie tube signs, useful for creating custom resolution glyphs
    • tips:
      • when resampling whole matrix, keep in mind, that each single contained glyph must be of same dimensions and both it’s width and height must be integer number – i.e. total matrix image width has to be divisible by 12 and (at the same time) total height by 2 (this would eventually require a slight change of aspect ratio)
      • use anti-aliased algorithm to resample glyphs
      • consider applying decent sharpen effect after resampling to emphasize edges, blured by resampling
      • consider saving resulting glyph matrix as optimized indexed color (paletted) image to reduce size. Don’t use lossy format (JPEG) to save low resolution glyphs.
      • bitmap editor, supporting scripts and batch operations is useful for preparing custom glyph sets

License

Free for non-commercial use only. Copyright and project URL has to be preserved.

(this holds for both the code and the images)

References

[1] Wikipedia: Nixie tube
http://en.wikipedia.org/wiki/Nixie_tube
 Posted by at 5:10 pm
Feb 132019
 

http://homepage.cs.uiowa.edu/~jones/bcd/bcd.html

 

BCD Arithmetic, a tutorial

Part of the Arithmetic Tutorial Collection 
by Douglas W. Jones
THE UNIVERSITY OF IOWA Department of Computer Science

Copyright © 1999, Douglas. W. Jones, with major revisions made in 2002. This work may be transmitted or stored in electronic form on any computer attached to the Internet or World Wide Web so long as this notice is included in the copy. Individuals may make single copies for their own use. All other rights are reserved.

Index

 Posted by at 5:41 am
Jan 092016
 

http://www.element14.com/community/community/raspberry-pi/blog/2015/10/06/a-raspberry-to-teach-optics

 

export JAVACMD=/opt/jdk1.8.0_65/bin/java
geogebra

organtin

Teaching optics with a Raspberry Pi

Posted by organtin in Raspberry Pi on Oct 6, 2015 3:44:37 PM

Raspberry Pi is a great tool for teaching. Its affordable price makes it appealing for students and teachers that can make interesting “experiments” without spending a fortune.

 

The understanding of optics requires lot of geometry, but equations are deeply understood only by a small number of students. Drawings may help, but making them requires some ability and precision. Needless to say, in most cases, the result is static and, in order to understand what happens in different conditions, require to realise many drawings.

 

A very interesting alternative is using an application called GeoGebra that can be downloaded for free from the Internet. Interesting enough, GeoGebra runs on Raspberry Pi. Every student, then, can do his/her own experiment with optics using GeoGebra. See this post to learn how to install it (quite simple, in fact; the only tricky part being installing the Java virtual machine). In short, download the arm version of the Java VM fromhttp://jdk8.java.net/fxarmpreview/index.html, then issue the following commands in a terminal

 

sudo apt-get update
sudo apt-get install geogebra
sudo apt-get install geogebra-gnome
mkdir -p /opt 
sudo tar zxvf (name of package) -C /opt 
rm (name of package) 
sudo /opt/jdk1.8.0/bin/java -version
export JAVACMD=/opt/jdk1.8.0/bin/java
geogebra
 Posted by at 12:53 pm
Jan 072016
 
 Posted by at 2:49 pm
Oct 202014
 

http://www.styleshout.com/

Free Awesome Website Templates.

Hello, welcome to styleshout. This site offers a collection of beautifully handcrafted html5 and css3 website templates – free of charge!

Looking for free high-quality website templates? You’ve come to the right place! There are many free template providers out there but what makes us different is that we focus more on the quality of our designs. We promise that here you’ll find some of the best free templates on the web. Thanks for dropping by. Enjoy your stay!

 Posted by at 12:55 pm
Jan 292014
 

http://www.odrive.com/home.html

odrive makes file servers useful again

odrive installs on your Windows or Mac file server. You invite users to link to your server with a simple email. Invitees get an instant-on desktop folder that keeps them connected to their content.

3 db website images
odrive lets you quickly browse entire directories of your storage and sync the files you need with a double click. Once your content is synced, you can access everything anytime, even when you’re offline! odrive keeps you up-to-date whether you’ve update the file on another machine or if you’re collaborating with others.

 Posted by at 8:17 am
Dec 022013
 

http://www.raymond.cc/blog/

Read more: http://www.raymond.cc/blog/permanently-delete-and-remove-sensitive-files-to-prevent-data-recovery/#ixzz2mKkoyvyk

 Posted by at 4:00 pm
Oct 032013
 

https://support.google.com/mail/answer/6594?hl=en&ctx=mail

Keyboard shortcuts

Keyboard shortcuts help you save time by allowing you to never take your hands off the keyboard to use the mouse. You’ll need a Standard 101/102-Key or Natural PS/2 Keyboard to use the shortcuts.

Tip: Press ? in Gmail to see a list of keyboard shortcuts.

Some keyboard shortcuts can be used immediately, and others need to be enabled before you can use them.

Shortcuts that are always turned on

These navigational and formatting shortcuts all work whether or not you’ve enabled the keyboard shortcuts setting.

Use arrow keys to view messages and start composing

While viewing your messages, use your keyboard’s arrow keys to move your cursor to a conversation, label or the compose button. Press Enter to select.

Move between messages in a conversation

While viewing a conversation, use n and p to go the next and previous messages in a conversation thread. Hit Enter to open or collapse a message.

Navigate in compose

Use the following combinations of keys when you have compose windows or chats open.

Shortcut Key Definition Action
Ctrl + Enter
Mac: + Enter
Send message After composing your message, use this combination to send it.
Ctrl + .
Mac: + .
Advance to next window Use this shortcut to move the cursor to the next chat or compose window, or to the main window.
Ctrl + ,
Mac: + ,
Go to previous window Use this shortcut to move the cursor to the previous chat or compose window, or to the main window.
Ctrl + Shift + c
Mac: + Shift + c
Add Cc recipients While composing, takes you to the Cc field to add new recipients.
Ctrl + Shift + b
Mac: + Shift + b
Add Bcc recipients While composing, takes you to the Bcc field to add new blind recipients.
Ctrl + Shift + f
Mac: + Shift + f
Change “from” address While composing, takes you to the From field to change your sending address. This shortcut only works if you have configured additional sending addresses.

To format your text quickly, check out these formatting shortcuts.

Shortcuts that need to be turned on

Before you can use these keyboard shortcuts, you’ll need to enable keyboard shortcuts in your settings:

  1. Click the gear in the top right and select Settings.
  2. Find the “Keyboard shortcuts” section and select Keyboard shortcuts on.
  3. Click Save Changes at the bottom of the page.
Shortcut Key Definition Action
c Compose Allows you to compose a new message. Shift + c allows you to compose a message in a new window.
d Compose in a new tab Opens a compose window in a new tab.
/ Search Puts your cursor in the search box.
k Move to newer conversation Opens or moves your cursor to a more recent conversation. You can hit Enter to expand a conversation.
j Move to older conversation Opens or moves your cursor to the next oldest conversation. You can hit Enter to expand a conversation.
n Newer message In ‘Conversation view’, moves your cursor to the newer message. You can hit Enter to expand or collapse a message.
p Previous message In ‘Conversation view’, moves your cursor to the older message. You can hit Enter to expand or collapse a message.
` Go to next inbox section If you use an inbox style with tabs or sections, you can quickly navigate to the next section.
~ Go to previous inbox section If you use an inbox style with tabs or sections, you can quickly navigate to the previous section.
o or Enter Open Opens your conversation. Also expands or collapses a message if you are in ‘Conversation View.’
u Return to conversation list Refreshes your page and returns you to the inbox, or list of conversations.
e Archive Archive your conversation from any view.
m Mute Archives the conversation, and all future messages skip the Inbox unless sent or cc’d directly to you. Learn more.
x Select conversation Automatically checks and selects a conversation so that you can archive, apply a label, or choose an action from the drop-down menu to apply to that conversation.
s Star a message or conversation Adds or removes a star to a message or conversation. Stars allow you to give a message or conversation a special status.
+ Mark as important Helps Gmail learn what’s important to you by marking misclassified messages. (Specific to Priority Inbox)
Mark as unimportant Helps Gmail learn what’s not important to you by marking misclassified messages. (Specific to Priority Inbox)
! Report spam Marks a message as spam and removes it from your conversation list.
r Reply Replies to the message sender. Shift + r allows you to reply to a message in a new window. (Only applicable in ‘Conversation View.’)
a Reply all Replies to all message recipients. Shift + a allows you to reply to all message recipients in a new window. (Only applicable in ‘Conversation View.’)
f Forward Forwards a message. Shift + f allows you to forward a message in a new window. (Only applicable in ‘Conversation View.’)
Esc Escape from input field Removes the cursor from your current input field.
Ctrl + s
Mac: + s
Save draft Saves the current text as a draft when composing a message. Hold the Ctrl/⌘ key while pressing s and make sure your cursor is in one of the text fields — either the composition pane, or any of the To, CC, BCC, or Subject fields — when using this shortcut.
# Delete Moves the conversation to Trash.
l Label Opens the Labels menu to label a conversation.
v Move to Moves the conversation from the inbox to a different label, Spam or Trash.
Shift + i Mark as read Marks your message as ‘read’ and skip to a newer message.
Shift + u Mark as unread Marks your message as ‘unread’ so you can go back to it later.
[ Removes from current view and previous Removes the current view’s label from your conversation and moves to the older one.
] Removes from current view and next Removes the current view’s label from your conversation and moves to the newer one.
{ Archive and previous Archives the current conversation and moves to the older one.
} Archive and next Archives the current conversation and moves to the next one.
z Undo Undoes your previous action, if possible (works for actions with an ‘undo’ link).
Shift + n Update current conversation Updates your current conversation when there are new messages.
q Move cursor to chat search Moves your cursor directly to the chat search box.
y Remove from Current View* Automatically removes the message or conversation from your current view.

  • From ‘Inbox,’ ‘y’ means Archive
  • From ‘Starred,’ ‘y’ means Unstar
  • From ‘Trash,’ ‘y’ means Move to inbox
  • From any label, ‘y’ means Remove the label

* ‘y’ has no effect if you’re in ‘Spam,’ ‘Sent,’ or ‘All Mail.’

. Show more actions Displays the ‘More Actions’ drop-down menu.
, Moves cursor to the first button in your Gmail toolbar Displays the ‘More Actions’ drop-down menu.
Ctrl + Down arrow
Mac: + Down arrow
Opens options in Chat
  • Ctrl/⌘ + Down arrow moves from edit field in your chat window to select the ‘Video and more’ menu
  • Next, press Tab to select the emoticon menu
  • Press Enter to open the selected menu
k Move up a contact Moves your cursor up in your contact list
j Move down a contact Moves your cursor down in your contact list
o or Enter Open Opens the contact with the cursor next to it.
u Return to contact list view Refreshes your page and returns you to the contact list.
e Remove from Current Group Removes selected contacts from the group currently being displayed.
x Select contact Checks and selects a contact so that you can change group membership or choose an action from the drop-down menu to apply to the contact.
Esc Escape from input field Removes the cursor from the current input
# Delete Deletes a contact permanently
l Group membership Opens the groups button to group contacts
z Undo Reverses your previous action, if possible (works for actions with an ‘undo’ link)

Combo-keys

Use the following combinations of keys to navigate through Gmail.

Shortcut Key Definition Action
Tab then Enter Send message After composing your message, use this combination to send it.
y then o Archive and next Archives your conversation and moves to the next one.
g then a Go to ‘All Mail’ Takes you to ‘All Mail,’ the storage site for all mail you’ve ever sent or received (and have not deleted).
g then s Go to ‘Starred’ Takes you to all conversations you have starred.
g then c Go to ‘Contacts’ Takes you to your Contacts list.
g then d Go to ‘Drafts’ Takes you to all drafts you have saved.
g then l Go to ‘Label’ Takes you to the search box with the “label:” operator filled in for you.
g then i Go to ‘Inbox’ Returns you to the inbox.
g then t Go to ‘Sent Mail’ Takes you to all mail you’ve sent.
* then a Select all Selects all mail.
* then n Select none Deselects all mail.
* then r Select read Selects all mail you’ve read.
* then u Select unread Selects all unread mail.
* then s Select starred Selects all starred mail.
* then t Select unstarred Selects all unstarred mail.

How helpful is this article:

Please tell us why you didn’t find this answer helpful:

1000
* Required field
 Posted by at 8:21 pm
Jul 172013
 

 

Windows Sysinternals

The Sysinternals web site was created in 1996 by Mark Russinovich and Bryce Cogswell to host their advanced system utilities and technical information. Whether you’re an IT Pro or a developer, you’ll find Sysinternals utilities to help you manage, troubleshoot and diagnose your Windows systems and applications.

Get up to speed fast!


Sysinternals Live

Sysinternals Live is a service that enables you to execute Sysinternals tools directly from the Web without hunting for and manually downloading them. Simply enter a tool’s Sysinternals Live path into Windows Explorer or a command prompt as http://live.sysinternals.com/<toolname> or  \\live.sysinternals.com\tools\<toolname>.

You can view the entire Sysinternals Live tools directory in a browser at http://live.sysinternals.com.

What’s New What's New

What’s New (June 20, 2013)

 Posted by at 7:29 pm
Jun 272013
 

http://tylerneylon.com/a/learn-lua/

Learn Lua in 15 Minutes

more or less


-- Two dashes start a one-line comment.

--[[
     Adding two ['s and ]'s makes it a
     multi-line comment.
--]]

----------------------------------------------------
-- 1. Variables and flow control.
----------------------------------------------------

num = 42  -- All numbers are doubles.
-- Don't freak out, 64-bit doubles have 52 bits for
-- storing exact int values; machine precision is
-- not a problem for ints that need < 52 bits.

s = 'walternate'  -- Immutable strings like Python.
t = "double-quotes are also fine"
u = [[ Double brackets
 Posted by at 8:26 pm
Mar 272013
 
http://jsgl.org/doku.php?id=home

JavaScript Graphics Library (JSGL)

JSGL is an Open-Source, browser independent 2D vector graphics library for JavaScript.

It is designed for, and well tested on most major web browsers:

 

Internet Explorer 6.0+,

Firefox 3.0+,

Opera 9.0+,

Safari 3.0+,

Google Chrome

It provides a well-designed, object-oriented API for creating interactive graphics applications in JavaScript.

In integrates VML/SVG vector markup languages. However, the API provided is cross-browser, leaving all the hard work to JSGL.

Drawing interactive graphics in JavaScript has never been easier :-D

JSGL 2.0 Released!

 

What JSGL 2.0 offers?

  • well-designed, browser-independent API for working with dynamically updatable graphic shapes, such as
    • line, polyline, Bezièr curve,
    • rectangle, circle, ellipse, polygon,
    • raster image, text label, group,
    • general SVG path,
  • support for mouse events, allowing you to create interactive Web 2.0 applications,
  • tools for animation of shapes, and other utilities,
  • JSGL is FREE of charge and can also be used in commercial applications under the terms of LGPLv3 license.

 

Gallery

 Posted by at 10:40 am
Mar 132013
 
http://www.idsystem.cz/kindle/#xmpl

Formatting HTML for Kindle

last update: 29.2.2012 – Dictionary support

Why another page about Kindle ?

After buying Amazon Kindle and reading a couple of books on it I began to use the Kindle also for creating my own documents.

I found some information about preparing documents for Kindle here and there and I realized that the best way of formatting document for Kindle is using HTML markup language which is the internal represenation of mobi-pocket documents used by Kindle. Kindle uses a subset of the HTML 3.2 and CSS so that no exotic HTML techniques will be needed.

 Posted by at 6:48 am
Mar 062013
 
http://wiht.link/python-guide

Python for Beginners

Lesson 1 : Introduction to Python – Overview
Welcome to the LearnStreet beginner course on Python. The Python programming language is a high level programming language that is used in a wide spectrum of applications — from web design and game programming to scientific research. Its simple and flexible syntax makes it easy to learn and understand, but still powerful and expressive. By the end of this course, you’ll have a solid understanding of the Python language, and be able to complete some cool projects in the Code Garage section. Keep in mind this course uses Python version 2.7. Python 2.7 is more widely used in industry, and therefore more valuable to learn. The most recent version is 3.2, which has some key syntax differences. We have designed this course for people who have no prior programming background. In this course, we will teach you some fundamental programming concepts through Python. Throughout this course, you will write code to apply what you’ve learned to solve programming problems. In addition to the instructional course content, you will be working towards building an event planner in Python which will be fully functional and ready for you to use by the end of this course. Now, click on the big black box – the Python interpreter – below this to start coding away!
Have a question?

lesson badge Python for Beginners

You have completed 0/9 lessons in this course
Lesson 1: Introduction to Python
 Posted by at 8:06 pm