Jump to content
IGNORED

Schooner - a forth project


Retrospect

Recommended Posts

2 minutes ago, TheBF said:

we are handling 1/2 the numbers and so less math

When I was trying to do a "screen scan" in my game , Cattle Battle, to check how many cows were alive, I found having to scan using X and Y (incrementing Y until 32 then Y=1 and increment X by 1) was far far too slow.  I pondered how John Plaster had done this , for Tombstone, to check for adjacent cacti in his case, and it dawned on me then, that Assembly was using just one number for the address and it was doing it very fast.  So I had to have an array for the cow's "alive" status instead :)   VPEEK() and VPOKE() will be looked into though, for sure.  

  • Like 2
Link to comment
Share on other sites

9 minutes ago, Retrospect said:

When I was trying to do a "screen scan" in my game , Cattle Battle, to check how many cows were alive, I found having to scan using X and Y (incrementing Y until 32 then Y=1 and increment X by 1) was far far too slow.  I pondered how John Plaster had done this , for Tombstone, to check for adjacent cacti in his case, and it dawned on me then, that Assembly was using just one number for the address and it was doing it very fast.  So I had to have an array for the cow's "alive" status instead :)   VPEEK() and VPOKE() will be looked into though, for sure.  

Bringing it back home to Forth.

 

Forth does everything involving single memory elements with PEEK and POKE equivalents called  @ (fetch)  and ! (store)

And for TI99 the Forth authors have added the equivalent for Video memory.  V@ V! in FbForth and TurboForth.

In Camel99 I used VC@ VC!  because they are for characters. (bytes) 

Camel99 also has V@ and V! for integers which means you can store numbers in VDP RAM if you want to.

 

When you declare variables in Forth they are not like BASIC. The give you an address, Not the number they are holding. 

 

VARIABLE X 

VARIABLE Y 

 

99 X !    ( Put 99 into X) 

X @      ( get the number held in X and print with .) 

 

It can get "wordy" so there are some other ways to do this but learn about variables first.   

  • Like 1
Link to comment
Share on other sites

Yo

3 minutes ago, Retrospect said:

I set X to 1000 and Y to 100, then attempted a loop to supposedly count down from X to Y.  I'm taking it, that it didn't lock up, or loop forever, that this succeeded.

 

 

 

You forgot to "fetch" X and Y to get their numbers on the stack.

so

 

: TEST   X @  Y @ DO  ....   ;

  • Like 1
Link to comment
Share on other sites

The code makes dot work processes the number on the stack into a string, then types the string starting wherever the cursor is.

It assumes you know where you want the output to go.

 

You are getting pretty handy with this Forth thing. 

I can hear the wheels turning all the way over 'ere.

 

Link to comment
Share on other sites

15 minutes ago, TheBF said:

You are getting pretty handy with this Forth thing. 

I can hear the wheels turning all the way over 'ere.

😄 I will be eventually thank you though!

So to ask a noob question ( i can't believe I'm asking this )
Say I've declared variable X , and then I do 0 X ! to declare it nill afterwards ... what is the way to do x=x+1 within a loop?

Link to comment
Share on other sites

18 minutes ago, Retrospect said:

😄 I will be eventually thank you though!

So to ask a noob question ( i can't believe I'm asking this )
Say I've declared variable X , and then I do 0 X ! to declare it nill afterwards ... what is the way to do x=x+1 within a loop?

You can do it the long way.

 

X @  1+  X !  

 

Or with the +! operator that adds a number to the contents of a variable 

 

1 X +!  

-4 X +!   \ add a negative number is legal. 

 

Or in Camel99 I used the native 9900 machine instructions called INC  and DEC like this.

X 1+! 

X 1-! 

These are the fastest. 

 

You also have

 X OFF   \ set to zero 

X ON     \ set to true. All bits on. 

 

Link to comment
Share on other sites

20 minutes ago, Retrospect said:

Or should I say, I'm attempting to do a simple program, that has X declared as null to begin with, and a delay loop.  

once the delay loop has hit maximum number, X is incremented (only until 15) 

Then we can do X SCREEN ? to make the screen color change?

 

Break it into small pieces that are too small to get wrong.  That's Chuck's thinking. 

VARIABLE X


 

: DELAY   500 MS ; 

: TEST
       X OFF 
       BEGIN  
          DELAY 
          X @ SCREEN 
           1 X +! 
         ?TERMINAL 
     UNTIL ; 

 

 But we would never use a variable for something so trivial in Forth. 

Variables are for things you want the program to remember. 

 

Hang onto to your shorts now. :)

 

: TEST2

        0      \ number of the stack 

      BEGIN 

         DELAY

         DUP SCREEN 

         1+ 

         ?TERMINAL

     UNTIL 

     DROP  ;    \ throw it way now. We're done.

         

Link to comment
Share on other sites

Or

: SCREENS   15 0 DO   I SCREEN  250 MS  LOOP ; 

: RUN     BEGIN  SCREENS   ?TERMINAL UNTIL ; 

 

I  is NOT a variable. It is also a subroutine that knows how to get the loop counter in a DO LOOP onto the DATA stack.

Nesting loops is almost never done. 

  • Like 1
Link to comment
Share on other sites

Just now, Retrospect said:

When I put "DROP ; " it said ? Unfinished

If between  :  and ;   anything was left on the data stack during the compiling, you get that message.

Look over you loop or break out pieces into separate words and try them line by line. 

 

  • Like 1
Link to comment
Share on other sites

1 hour ago, GDMike said:

I was actually trying the starfield by generating pixels at random instead of a constant moving direction. Then if I needed to set a "direction" I could run something like this???

I also suck at programming

Not sure I completely understand what you are trying to get but maybe the existing words can do this. 

 

The RND-STAR word gives you one of the chars that makes a star.

 

The NEW-STARS  re-loads RND vdp addresses into the ]LOCATION array.

.STARS puts a random star at every location that is in the ]LOCATION array.

 

So if you run .STARS over and over the stars are going to change all the time.

 

Let's try it. 

This gives a very crazy effect. 

: TEST2  
    PAGE 
    40 SET# 16 1 COLOR 
    2 SCREEN 
    .STARS
    BEGIN 
       SHIFT-STARS
       .STARS
      ?TERMINAL 
    UNTIL 
    8 SCREEN 
;

 

This sits on the random stars for a bit longer and changes are delayed.


: ?BREAK    
  ?TERMINAL
  IF  
    8 SCREEN  
    TRUE ABORT" *BREAK*" 
  THEN  ;

: TEST3  
    PAGE 
    40 SET# 16 1 COLOR 
    2 SCREEN 
    .STARS
    BEGIN 
      100 0 DO .STARS  100 MS ?BREAK  LOOP 
      100 0 DO  SHIFT-STARS ?BREAK LOOP 
    AGAIN
;

 

Here is the whole thing.

Spoiler
INCLUDE DSK1.TOOLS 
INCLUDE DSK1.GRAFIX
INCLUDE DSK1.RANDOM 
INCLUDE DSK1.ARRAYS 

\ define our stars 
DECIMAL 
S" 0000000100000000" 40 CALLCHAR
S" 0000000200000000" 41 CALLCHAR
S" 0000000400000000" 42 CALLCHAR
S" 0000000800000000" 43 CALLCHAR
S" 0000001000000000" 44 CALLCHAR
S" 0000002000000000" 45 CALLCHAR
S" 0000004000000000" 46 CALLCHAR
S" 0000000000000000" 47 CALLCHAR

: NEXT-STAR ( char -- char') 1+  7 AND 40 +  ; 

 \ : TESTNEXT  40 BEGIN NEXT-STAR SWAP .  UNTIL ;

: RND-STAR ( -- char)  8 RND 40 + ;

: RND-VADDR ( -- Vaddr) 
    C/SCR @ RND     \ get random address from zero to size of screen
    VPG @ + ;       \ get the video page, add to the random number 

32 CONSTANT #STARS   \ lock this down as a constant 

\ array that holds the VDP address of every star 
#STARS ARRAY ]LOCATION 

: NEW-STARS  ( n --) #STARS 0 DO   RND-VADDR I ]LOCATION !  LOOP ;

NEW-STARS   \ initialize the array now 

\ This array FETCHES the star's VDP screen address from ]location
: ]VDPLOC  ( n -- Vaddr) ]LOCATION @ ;

\ Put the stars on the screen at the random LOCATION in our LOCATIONS array 
: .STARS 
    #STARS 0 
    DO   
      RND-STAR I ]VDPLOC VC! \ write star to video memory 
    LOOP 
;

\ Given a screen address, test if we hit the left edge of the screen 
: LEFT-EDGE?  ( n -- ?) C/L @ MOD 0= ; \ modulo divide by "chars per line" 

\ Take the address of a cell in ]LOCATION array. 
\ get the screen location of a star 
\ move it 1 one left, but address can't go below zero so stop that. 
\ If we hit the left edge add 31 to the Vaddr and store it back in Address
: MOVELEFT ( addr -- ) \ decrement a variable to 0 but not below 
    DUP @   ( -- addr Vaddr)  
    BL OVER VC!         \ erase char in old screen location  
    1- 0 MAX  ( -- addr Va)   \ subtract 1 but don't go below 0 
    DUP LEFT-EDGE?      \ test if we are at the edge of the screen  
    IF   31 +           \ yes. Add 31 to go back to right side of screen 
    THEN SWAP ! ;       \ store this new location in the addr of ]LOCATION array 
;

: SHIFT-STARS
    #STARS 0 
    DO  
       I ]VDPLOC VC@        \ read star character from screen location
       NEXT-STAR            \ advance to the next bit character 
       DUP 47 =             ( -- Va c ?)
       IF  
          I ]LOCATION MOVELEFT   
       THEN 
       I ]VDPLOC VC!         \ store the new star at the VDP location 
    LOOP 
;

: TEST  
    PAGE 
    40 SET# 16 1 COLOR 
    2 SCREEN 
    .STARS
    BEGIN 
       SHIFT-STARS
      ?TERMINAL 
    UNTIL 
    8 SCREEN 
;

: TEST2  
    PAGE 
    40 SET# 16 1 COLOR 
    2 SCREEN 
    .STARS
    BEGIN 
       SHIFT-STARS
       .STARS
      ?TERMINAL 
    UNTIL 
    8 SCREEN 
;

: ?BREAK    
  ?TERMINAL
  IF  
    8 SCREEN  
    TRUE ABORT" *BREAK*" 
  THEN  ;

: TEST3  
    PAGE 
    40 SET# 16 1 COLOR 
    2 SCREEN 
    .STARS
    BEGIN 
      100 0 DO .STARS  100 MS ?BREAK  LOOP 
      100 0 DO  SHIFT-STARS ?BREAK LOOP 
    AGAIN
;

 

 

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

I cleaned up this code and removed all the noisy comments.

Also factored out the word WRAP which makes MOVE-LEFT clearer to read.

 

Spoiler

INCLUDE DSK1.TOOLS 
INCLUDE DSK1.GRAFIX
INCLUDE DSK1.RANDOM 
INCLUDE DSK1.ARRAYS 

DECIMAL
32 CONSTANT #STARS
#STARS ARRAY ]LOCATION

: ]VDPLOC    ( n -- Vaddr) ]LOCATION @ ;

S" 0000000100000000" 40 CALLCHAR
S" 0000000200000000" 41 CALLCHAR
S" 0000000400000000" 42 CALLCHAR
S" 0000000800000000" 43 CALLCHAR
S" 0000001000000000" 44 CALLCHAR
S" 0000002000000000" 45 CALLCHAR
S" 0000004000000000" 46 CALLCHAR
S" 0000000000000000" 47 CALLCHAR

: NEXT-STAR ( char -- char') 1+  7 AND 40 +  ;
: RND-STAR  ( -- char)  8 RND 40 + ;
: RND-VADDR ( -- Vaddr) C/SCR @ RND  VPG @ + ;


: NEW-STARS  ( n --) #STARS 0 DO  RND-VADDR I ]LOCATION !  LOOP ;

: .STARS     ( -- )  #STARS 0 DO  RND-STAR I ]VDPLOC VC!  LOOP ;

: LEFT-EDGE? ( n -- ?) C/L @ MOD 0= ;
: WRAP       ( Vaddr -- Vaddr') DUP LEFT-EDGE? IF 31 + THEN ;

: MOVELEFT ( addr -- )
    DUP @   ( -- addr Vaddr)
    BL OVER VC!
    1- 0 MAX WRAP SWAP !
;

: SHIFT-STARS
    #STARS 0
    DO
       I ]VDPLOC VC@
       NEXT-STAR
       DUP 47 =   ( -- Vaddr c ?)
       IF
          I ]LOCATION MOVELEFT
       THEN
       I ]VDPLOC VC!
    LOOP
;

 NEW-STARS ( Init locations)

 : TEST
    PAGE 
    40 SET# 16 1 COLOR 
    2 SCREEN 
    .STARS
    BEGIN
       SHIFT-STARS
      ?TERMINAL 
    UNTIL 
    8 SCREEN 
;

 

 

  • Like 4
Link to comment
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.
Note: Your post will require moderator approval before it will be visible.

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...