Jump to content
Hans23

Forth advice sought

Recommended Posts

Hi,

 

I am struggling with doing things the Forth way, maybe someone here can help me out or point me to an material that'd help.  I'm attempting to write a game in TurboForth.  It will be a two person game where the objective of each player is to reach the base of the other player.  Consider it to be a programming exercise more than the attempt at a good game, as it is my first.  Anyway, here is what it looks like right now:

 

 

The vertical walls with the moving gates are updated every few frames, and the code that does it looks like this:

$A6 value gate-char
22 value wall-height
variable gates 3 cells allot
variable gate-width 5 gate-width !
variable gate-speed 10 gate-speed !
: update-gate ( n -- )
    >r
    [email protected] 1 and if
        [email protected] [email protected]
        dup [email protected] gate-x swap gotoxy gate-char emit
        dup gate-width @ + wall-height mod [email protected] gate-x swap gotoxy space
        1+
    else
        [email protected] [email protected]
        dup [email protected] gate-x swap gotoxy space
        dup gate-width @ + wall-height mod [email protected] gate-x swap gotoxy gate-char emit
        1-
    then
    wall-height mod [email protected] gate!
    r> drop ;

: update-gates ( -- )
    4 0 do i update-gate loop ;

 

The word that concerns me is obviously UPDATE-GATE, which moves the gate in one of the walls up or down, depending on whether its index is even or odd - I find it really hard to understand what the code does.  By using the return stack to hold the gate number, things get a little easier, yet there still is a lot of stack value juggling that one needs to follow.  Also, the code duplication between the up and down movement of the gate concerns me, but how could those two branches be combined into one parameterized word that, in itself, does not need to deal with many opaque stack parameters?

 

I'm seeing it as a reoccuring issue when I write words that need to deal with multiple associated values, like the X and Y coordinate of one or multiple objects.  Many of the operations involved are very simple, but the required mechanics to access values on the stack get complicated and confusing quickly.

 

Any help or pointers would be much appreciated!

Thank you,

Hans

Edited by Hans23
Typo
  • Like 2

Share this post


Link to post
Share on other sites
5 hours ago, Hans23 said:

Any help or pointers would be much appreciated!

 

Without screwing with your logic (yet!), the following changes save some code—the first 4 lines, by placement, and the last 2, by removing the return-stack value one step sooner:

$A6 value gate-char
22 value wall-height
variable gates 3 cells allot
variable gate-width 5 gate-width !
variable gate-speed 10 gate-speed !
: update-gate ( n -- )
   >r
   [email protected] 1 and if
      [email protected] [email protected]
\      dup [email protected] gate-x swap gotoxy gate-char emit
      [email protected] gate-x over gotoxy gate-char emit   
\      dup gate-width @ + wall-height mod [email protected] gate-x swap gotoxy space
      [email protected] gate-x over gate-width @ + wall-height mod gotoxy space            
      1+
   else
      [email protected] [email protected]
\      dup [email protected] gate-x swap gotoxy space
      [email protected] gate-x over gotoxy space
\      dup gate-width @ + wall-height mod [email protected] gate-x swap gotoxy gate-char emit
      [email protected] gate-x over gate-width @ + wall-height mod gotoxy gate-char emit
      1-
   then
\   wall-height mod [email protected] gate!
\   r> drop ;
   wall-height mod r> gate! ;

: update-gates ( -- )
    4 0 do i update-gate loop ;

...lee

  • Like 1

Share this post


Link to post
Share on other sites

Hi Lee,

 

thank you for looking at my code!  I had considered working with the data stack more, but the issue that I really have is that I then have one more value on the stack that I need to keep track of in my head in order to understand the code.  I don't know if this is difficult for me because I am not used to it or if it is and just stays difficult, being the price of the simplicity of Forth.

 

It also seems to me that my words are just too long, and making them generally smaller would make sense.  What keeps me from trying to go that way is that I also find it hard to invent meaningful names, and my intuition is to keep that namespace clean.  I guess that this is one of the things I need to overcome :)

 

Anyway, thanks again!  Any further hints, or maybe pointers to good source code to study, would be appreciated.


Cheers,

Hans

  • Like 1

Share this post


Link to post
Share on other sites
14 minutes ago, Hans23 said:

thank you for looking at my code!  I had considered working with the data stack more, but the issue that I really have is that I then have one more value on the stack that I need to keep track of in my head in order to understand the code.  I don't know if this is difficult for me because I am not used to it or if it is and just stays difficult, being the price of the simplicity of Forth.

 

When stack-robatics get the least bit complicated, I keep track of the stacks (“S:” for the parameter stack and “R:” for the return stack) in comments at the right of each code line, keeping the lines simple at the expense of space:

: update-gate ( n -- )
   >r                         \ S: R:n
   [email protected] [email protected]                   \ S:ny R:n
   [email protected] 1 and if                
      [email protected] gate-x over          \ S:ny nx ny R:n
      gotoxy gate-char emit   \ S:ny R:n
      [email protected] gate-x over          \ S:ny nx ny R:n
      gate-width @ +          \ S:ny nx ny+gw R:n
      wall-height mod         \ S:ny nx ny' R:n
      gotoxy space            \ S:ny R:n
      1+                      \ S:ny+1 R:n
   else
      [email protected] gate-x over          \ S:ny nx ny R:n
      gotoxy space            \ S:ny R:n
      [email protected] gate-x over          \ S:ny nx ny R:n
      gate-width @ +          \ S:ny nx ny+gw R:n
      wall-height mod         \ S:ny nx ny' R:n
      gotoxy gate-char emit   \ S:ny R:n
      1-                      \ S:ny-1 R:n
   then
   wall-height mod r>         \ S:ny" n R:
   gate! ;                    \ S: R:

[Note that I hoisted the redundant [email protected] [email protected] out of the if construct.]

 

14 minutes ago, Hans23 said:

It also seems to me that my words are just too long, and making them generally smaller would make sense.  What keeps me from trying to go that way is that I also find it hard to invent meaningful names, and my intuition is to keep that namespace clean.  I guess that this is one of the things I need to overcome :)

 

You do want clarity, of course. Name length is not a big problem for the size of a program because a word’s cfa (code field address or execution token) is all that gets stored in the definition of another word. The name length does add 1 byte per character to a word’s header (padded to even cell boundary), but that should not be too onerous.  There are naming guidelines most Forthers try to follow in the spirit of Forth—ideas like reusing the classic, cryptic Forth names: ! @ . ' , etc., while composing new names (as you have done in this instance).

 

...lee

  • Like 2

Share this post


Link to post
Share on other sites

Nice comment style!  I'll try to use that.

 

One thing about names in TurboForth is that they seem to be restricted to 15 characters in length, and it seems to not take it well when one tries to define a word with a long name:

 

image.thumb.png.ec47f47f52a13e1c44a261d4d6b298f4.png

 

This caused me quite some head scratching before I realized that the limit exists.  Anyway, there are some habits from the modern world that don't carry over well when going back to a small system like the TI-99/4A.

 

Thank you again for your comment (style)!

  • Like 1

Share this post


Link to post
Share on other sites
3 hours ago, Hans23 said:

Nice comment style!  I'll try to use that.

 

OK, here is my take on your update-gate :

: update-gate ( n -- )
   >r [email protected] [email protected]                \ S:ny R:n
   [email protected] 1 and if                \ S:ny R:n  **CORRECTION: dup replaced with [email protected] **
      1+                      \ S:ny+1 R:n
      bl gate-char            \ S:ny+1 bl gc R:n
   else
      1-                      \ S:ny-1 R:n
      gate-char bl            \ S:ny-1 gc bl R:n
   then
   [email protected] gate-x                  \ S:ny+-1 gc|bl bl|gc nx R:n
   [email protected] [email protected]                   \ S:ny+-1 gc|bl bl|gc nx ny R:n
   2dup                       \ S:ny+-1 gc|bl bl|gc nx ny nx ny R:n
   gotoxy                     \ S:ny+-1 gc|bl bl|gc nx ny R:n
   rot emit                   \ S:ny+-1 gc|bl nx ny R:n
   gate-width @ +             \ S:ny+-1 gc|bl nx ny+gw R:n
   wall-height mod            \ S:ny+-1 gc|bl nx ny' R:n
   gotoxy emit                \ S:ny+-1 R:n
   wall-height mod r>         \ S:ny" n R:
   gate! ;                    \ S: R:

It could be a little more stack-robatics than you’d like, but there it is!  |:)

 

...lee

Edited by Lee Stewart
CORRECTION in code
  • Like 3

Share this post


Link to post
Share on other sites

Factor factor factor. When it's getting hard it's normally a sign that you need to factor into smaller definitions.

 

And don't be afraid to use global variables to store things in. It may ultimately be faster than wasting cycles just to manipulate the stack.

  • Like 4

Share this post


Link to post
Share on other sites

The drawing block is so similar it could be factored. You could have an array of 2 elements, space and gate-char. The first to be emitted adds the odd-even index. The second to be emitted adds the 1-the index.

 

  • Like 3

Share this post


Link to post
Share on other sites

I have not tested this but to emphasize what Willsy said look how things simplify by just factoring out some of the common code from Lee's re-writes and naming them.

Any time you see the same 4 or more words in a row in your code consider factoring them out into a new word that describes that function. This really is the key to making Forth simpler to use.

I am sure there is more there to factor in such a long (for Forth) definition. 

$A6 value gate-char
22 value wall-height
variable gates 3 cells allot
variable gate-width  5 gate-width !
variable gate-speed 10 gate-speed !

: GATE-XY   ( n -- x y)  gate-x over gate-width @ + wall-height mod ;
: .GATECHAR ( x y -- ) GOTOXY gate-char emit ;

: update-gate ( n -- )
   >r
   [email protected] 1 and if
      [email protected] [email protected]
      [email protected] gate-x over .GATECHAR
      [email protected] gotoxy space
      1+
   else
      [email protected] [email protected]
      [email protected] gate-x over gotoxy space
      [email protected] gate-xy .GATE-CHAR
      1-
   then
   wall-height mod r> gate! ;

: update-gates ( -- )
    4 0 do i update-gate loop ;

 

Chuck Moore's Forth code is 1 line per definition typically.  Extreme perhaps but hey it's his language. :)

 

It's a very different way to think when used as designed. It's more like making a little language of words that solves your problem when you put them together in correct order. 

 

And yes it does take some time to get used to it. 

 

Some things to think about:

1. Never to try managing more than 3 parameters on the data stack.

    Factor out words until that is possible. If it's not possible re-think your solution or use variables.
 

2. Make word names that tell you what the word really does for you. It pays off since you use more function names than conventional languages.

 

3. Forth words can return more than one parameter. Use that as needed.

 

When you get some free time download a copy of Thinking Forth by Leo Brodie.  

 

You have running code. Congratulations!  Keep on it and it will get easier.

  • Like 4

Share this post


Link to post
Share on other sites

I was trying to think of an good example of master level Forth code and I found one.

Sam Falvo's VIBE editor is mostly one liners. A thing of beauty.  :)

 

Vibe editor for Forth blocks

 

(He should have used stack diagram comments if he wanted to get an 'A' grade on the paper) :)

  • Like 2

Share this post


Link to post
Share on other sites

It is rather beautiful isn't it? I love the raw, brutal simplicity of forth. My only criticism would be the lack of stack comments. However, the definitions are so short you can easily understand them.

  • Like 3

Share this post


Link to post
Share on other sites

Chuck Moore's Forth code is 1 line per definition.. really? Wow, well (KISS, keeping it short ), you know coming from other languages, we tend to cram as much as we can quickly and brutefully, this just wants to slap your grandma.

I have a tough time with this, but i find myself coming back to that larger line of code, saying, but if, and adding on..so, your so right or else the WORD becomes a nightmare, like my, uh, you know the rest of the story.

 

Edited by GDMike
  • Like 2

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...