More snakes

A slightly improved version of the snakes program - now with more snakes.
Snakes are drawn in reverse, so it looks like they are crawling over each other rather than under.  It is the little things in life that matter.
[Upon opening the Well of the Souls and peering down]
Sallah: Indy, why does the floor move?
Indiana: Give me your torch.
[Indy takes the torch and drops it in]
Indiana: Snakes. Why'd it have to be snakes?
Sallah: Asps... very dangerous. You go first.


     REM Snake Walk 2
     REM T Street
     REM 2014-11-12
     REM slightly improved snake program, now
     REM with more snakes!
     
MODE 10  : OFF
     
SCREEN_WIDTH% = 1440
     SCREEN_HEIGHT% = 1152

     REM snake parameters
     
SNAKE_RADIUS% = 16 : REM size of the segments
     
SEGMENTS% = 26 : REM don't change to larger than this

     REM create each snake
     
DIM snake1{ x%(SEGMENTS%-1), y%(SEGMENTS%-1),  head%, tail%, dir%, red%, green% }
     DIM snake2{} = snake1{}
     DIM snake3{} = snake1{}
     DIM snake4{} = snake1{}
     DIM snake5{} = snake1{}
     DIM snake6{} = snake1{}
     DIM snake7{} = snake1{}
     DIM snake8{} = snake1{}

     REM setup the initial conditions for the snake
     
PROC_initialSnake( snake1{} )
     PROC_initialSnake( snake2{} )
     PROC_initialSnake( snake3{} )
     PROC_initialSnake( snake4{} )
     PROC_initialSnake( snake5{} )
     PROC_initialSnake( snake6{} )
     PROC_initialSnake( snake7{} )
     PROC_initialSnake( snake8{} )

     REM main loop
     
REPEAT
       
*refresh off
       PROC_drawSnake( snake1{} )
       PROC_drawSnake( snake2{})
       PROC_drawSnake( snake3{})
       PROC_drawSnake( snake4{})
       PROC_drawSnake( snake5{})
       PROC_drawSnake( snake6{})
       PROC_drawSnake( snake7{})
       PROC_drawSnake( snake8{})

       *refresh on

       PROC_moveSnake( snake1{} )
       PROC_moveSnake( snake2{} )
       PROC_moveSnake( snake3{} )
       PROC_moveSnake( snake4{} )
       PROC_moveSnake( snake5{} )
       PROC_moveSnake( snake6{} )
       PROC_moveSnake( snake7{} )
       PROC_moveSnake( snake8{} )

       WAIT 5 : REM wait a 'mo
       
CLS

     UNTIL FALSE


     
DEFPROC_initialSnake( this{} )
     LOCAL i%
     REM intial position of snake
     
FOR i% = 0 TO SEGMENTS%-1
       this.x%(i%) = i% + 8
       this.y%(i%) = 12
     NEXT
     
this.head% = SEGMENTS%-1
     this.tail% = 0
     this.dir% = RND(4) : REM initial direction
     
this.red% = RND(255-SEGMENTS%*6)   : REM colour of snake
     
this.green% = RND(255-SEGMENTS%*6) : REM colour of snake
     
ENDPROC


     
DEFPROC_drawSnake( this{} )
     REM plots one snake on the screen
     
LOCAL colCycle%
     LOCAL i%
     LOCAL ok%
     i% = this.tail%
     WHILE NOTok%
       COLOUR 2, this.red%+colCycle%*6, this.green%+colCycle%*6, 0
       GCOL 0,2
       colCycle% +=1
       PROC_circle( this.x%(i%), this.y%(i%) )
       i% += 1
       IF i% >= SEGMENTS% THEN i% = 0
       IF i% = this.head% THEN
         
ok% = TRUE
         PROC
_circle( this.x%(i%), this.y%(i%) )
       ENDIF
     ENDWHILE
     ENDPROC


     
DEFPROC_moveSnake( this{} )
     LOCAL dir%, ok%
     LOCAL newHead%, newTail%
     LOCAL checkx%, checky%

     newHead% = this.head% + 1
     IF newHead%=SEGMENTS% THEN
       
newHead% = 0
     ENDIF
     
newTail% = this.tail% + 1
     IF newTail% =SEGMENTS% THEN
       
newTail% = 0
     ENDIF


     REPEAT
       
ok% = TRUE
       
REM check snake is not going back on itself
       
REPEAT
         
dir% = RND(4)
       UNTIL FN_dirOk(dir%, this.dir% )

       REM check that snake will not move off the screen
       
CASE dir% OF
         WHEN 
1
           checkx% = this.x%(this.head%) +1
         WHEN 2
           checkx%  = this.x%(this.head%) -1
         WHEN 3
           checky% = this.y%(this.head%) + 1
         WHEN 4
           checky% = this.y%(this.head%) -1
       ENDCASE

       IF 
dir% = 1 THEN
         IF 
checkx%*SNAKE_RADIUS%*2 > SCREEN_WIDTH% THEN
           
ok% = FALSE
         ENDIF
       ENDIF
       IF 
dir% = 2 THEN
         IF 
checkx%*SNAKE_RADIUS%*2 <= SNAKE_RADIUS%*2 THEN
           
ok% = FALSE
         ENDIF
       ENDIF
       IF 
dir% = 3 THEN
         IF 
checky%*SNAKE_RADIUS%*2 > SCREEN_HEIGHT% THEN
           
ok% = FALSE
         ENDIF
       ENDIF
       IF 
dir% = 4 THEN
         IF 
checky%*SNAKE_RADIUS%*2 <= SNAKE_RADIUS%*2 THEN
           
ok% = FALSE
         ENDIF
       ENDIF

     UNTIL 
ok%

     REM snake has made a valid random move
     
CASE dir% OF
       WHEN 
1
         this.x%(newHead%) = this.x%(this.head%) +1
         this.y%(newHead%) = this.y%(this.head%)
       WHEN 2
         this.x%(newHead%) = this.x%(this.head%) -1
         this.y%(newHead%) = this.y%(this.head%)

       WHEN 3
         this.y%(newHead%) = this.y%(this.head%) +1
         this.x%(newHead%) = this.x%(this.head%)

       WHEN 4
         this.y%(newHead%) = this.y%(this.head%) -1
         this.x%(newHead%) = this.x%(this.head%)

     ENDCASE

     
this.head% = newHead%
     this.tail% = newTail%
     this.dir% = dir%
     ENDPROC


     
DEFFN_dirOk( direction%, current% )
     REM check snake not moving back on itself
     
IF ABS(direction%-current%) = 1 AND direction%+current% <> 5 THEN
       
FALSE
     ELSE
       
TRUE
     ENDIF


     
DEFPROC_circle( x%, y% )
     CIRCLE FILL x%*SNAKE_RADIUS%*2, y%*SNAKE_RADIUS%*2, SNAKE_RADIUS%
     ENDPROC