Showing posts with label Random walk. Show all posts
Showing posts with label Random walk. Show all posts

More groovy patterns for Raspberry Pi

Following on from the last post about groovy patterns for Raspberry Pi, I present my latest program, another random walk.

It is a random walk similar to last time, however with this one there are three degrees of freedom (rather than horizontal and vertical) and rather than a line, the object displayed in a coloured 3D box.
This code is for BASIC V running under RISCOS on the Raspberry Pi. Copy the code, or download directly.

The code:

   10 REM Blocks
   20 REM T Street
   30 REM 2017-05-21
   40 :
   50 MODE 19
   52 delay = 0
   55 colcyc = 0
   60 angle1 = RAD(45): angle2 = RAD(20)
   70 size = 16
   72 LIMIT = 50
   73 DENSITY = 40
   80 xo=500:yo=500
   90 x = xo: y=yo
  100 dir = RND(5)
  110 PROCsetdir
  112 lc = 0
  114 dc = 0
  120 REPEAT
  140   PROCbox(x,y,size,angle1,angle2)
  141   t=TIME:REPEAT UNTIL TIME>t+delay
  150   x = x + dx: y = y + dy
  151   lc = lc + 1
  160   IF RND(6) = 1 THEN PROCchangeDir
  170   IF x<0 OR x>1000 OR y<0 OR y>1000 OR lc>LIMIT THEN
  180     x=xo:y=yo
  181     colcyc = colcyc+2: IF colcyc > 127 colcyc = 0
  182     lc = 0
  183     dc = dc + 1
  190   ENDIF
  191   IF dc>DENSITY THEN
  192     dc = 0:CLS:x=xo:y=yo:lc = 0
  193   ENDIF
  200 UNTIL FALSE
  210 END
  220 :
  230 DEFPROCbox(x,y,s,ar,au)
  240 REM draws a box at coords x,y
  250 REM where the coords are the lower left corner
  260 REM and s is the size of box
  270 REM and ar and au are angles
  280 MOVE x,y
  290 LOCAL up, right
  300 up = s*SIN(au)
  310 right = s*COS(ar)
  320 REM front side
  330 GCOL 2+colcyc
  340 MOVE x,y+s
  350 PLOT 85,x+s,y
  360 MOVE x+s, y:MOVE x, y+s
  370 PLOT 85, x+s, y+s
  380 REM right hand side
  390 GCOL 1+colcyc
  400 MOVE x+s+right, y+up: MOVE x+s, y+s
  410 PLOT 85, x+s, y
  420 MOVE x+s+right, y+up: MOVE x+s, y+s
  430 PLOT 85, x+s+right, y+s+up
  440 REM top
  450 GCOL 1+colcyc
  460 MOVE x+right, y+s+up: MOVE x+s, y+s
  470 PLOT 85, x, y+s
  480 MOVE x+right, y+s+up: MOVE x+s, y+s
  490 PLOT 85, x+s+right, y+s+up
  491 GCOL 0
  492 MOVEx,y:DRAW x+s,y:DRAW x+s,y+s:DRAWx,y+s:DRAW x,y
  500 ENDPROC
  510 :
  520 DEFPROCsetdir
  530 CASE dir OF
  540   WHEN 1
  550   dx = 0: dy = size
  560   WHEN 2
  570   dx = size: dy = 0
  580   WHEN 3
  590   dx = 0: dy = -size
  600   WHEN 4
  610   dx = -size: dy = 0
  620   WHEN 5
  630   dx = -(size*COS(angle2)): dy = -(size*SIN(angle2))
  635   WHEN6
  636   dx = (size*COS(angle2)): dy = (size*SIN(angle2))
  640 ENDCASE
  650 ENDPROC
  660 :
  670 DEFPROCchangeDir
  680 dir=RND(6)
  690 PROCsetdir
  700 ENDPROC
  710 :


Groovy patterns for Raspberry Pi

In a spare moment whilst I was waiting for some food to cook, I decided to play with the BASIC on the Raspberry Pi. I'm using the brilliant RISCOS for the Pi which comes with BASIC V and about a gigabyte of RAM.

I decided to create a 'random walk' in an attempt to create something that would look like an abstract map of a city. I am quite pleased with the results.

Pictures first, and then the code.

It's supposed to look sort of 3D, sort of.

It really pelts along on my Raspberry Pi
When the line wanders off the screen it starts again in the middle of the pattern with a slight offset and a new colour. Lines sometimes quit and start again (controlled by the variable LIMIT%, and after a while the pattern will refresh (controlled by the DENSITY% variable).

Here is the source code for RISCOS BASIC V, which will require only minor modification to run in BBC BASIC for Windows, or on a BBC Master.

Copy the code below, or download the file directly.

   10 REM Draws a 'city scape'
   20 REM T Street
   30 REM 2017-05-10
   40 MODE 19
   50 ONERROR IF ERR=17 OSCLI("*DESKTOP")
   60 colCycle%= 0
   70 GCOLRND(4)+colCycle%
   80 REPEAT
   90   refresh%=FALSE
   99   REM Origin
  100   xo = 500 :yo = 500
  109   REM start at origin
  110   x = xo :y = yo
  119   REM distance moved each step
  120   dx=0:dy=0
  130   m = 16
  139   REM counts number of steps
  140   c = 0
  150   l=0
  160   LIMIT% = 400
  170   DENSITY% = 32
  180   MOVE x,y
  190   REPEAT
  200     c=c+1:l=l+1
  210     x=x+dx
  220     y=y+dy
  230     DRAW x,y
  240     r = RND(4)
  250     IF r=1 dx = 0:dy=m
  260     IF r=2 dx = m:dy=0
  270     IF r=3 dx = 0:dy=-m
  280     IF r=4 dx = -m:dy=0
  290     IF x<0 OR x>1000 OR y<0 OR y>1000 OR c>LIMIT%  THEN
  300       xo = xo+2:yo=yo+2
  310       x=xo
  320       y=yo
  330       c=0
  340       MOVE x,y
  350       GCOLRND(4)+colCycle%
  360     ENDIF
  370     IF l>LIMIT%*DENSITY% THEN
  380       refresh% = TRUE
  390     ENDIF
  400   UNTIL refresh%
  410   colCycle% = colCycle% + 4: IF colCycle% > 128: colCycle% = 0
  420   CLS
  430 UNTIL FALSE


Modern art is rubbish

Can a computer create artwork? Well, the experts are working on it.  While they work that out (and while I wait for my supper to cook) here is my first (rather random) attempt.

The program simply generates random points and moves them around the screen, bouncing off the edges as they go; connecting points into different shapes of various colour.  Run the program and you will see a moving modern art display on your screen. Click the mouse to reset to a new initial configuration.

Rubbish!

Call THAT artwork?

No, not really, but it is a fun project and there is plenty to tweak in the code below.
There is a random element which slowly transforms each shape into another shape as it goes.

BB4Win Source code below:

     REM modern art is rubbish
     REM T Street
     REM 2015-11-26
     
MODE 12:OFF
     
SW_MAXIMIZE = 3
     SYS "ShowWindow", @hwnd%, SW_MAXIMIZE
     VDU 26
     NUM% = 300
     _WIDTH% = 1920
     _HEIGHT% = 1640
     MAX_SPEED% = 100
     _CHANGE_RATE% = 12

     DIM point{(NUM%) x, y, dx, dy, pmode%, tmode%, cmode% }
     REPEAT
       PROC
_createPoints( point{()} )
       REPEAT
         PROC
_movePoints( point{()} )
         PROC_drawPoints( point{()} )
         WAIT 1
         MOUSE x%, y%, click%
       UNTIL click% = 4 OR click% = 1
     UNTIL FALSE


     
DEFPROC_drawPoints( point{()} )
     LOCAL i%
     *refresh off
     CLS
     FOR
i% = 0 TO NUM%
       GCOL point{(i%)}.tmode%, point{(i%)}.cmode%
       PLOT point{(i%)}.pmode%, point{(i%)}.x, point{(i%)}.y
     NEXT
     
*refresh on
     *refresh
     ENDPROC


     
DEFPROC_createPoints( point{()} )
     LOCAL i%
     FOR i% = 0 TO NUM%
       point{(i%)}.x = RND(_WIDTH%)
       point{(i%)}.y = RND(_HEIGHT%)
       point{(i%)}.dx = RND(MAX_SPEED%)-(MAX_SPEED% DIV 2)
       point{(i%)}.dy = RND(MAX_SPEED%)-(MAX_SPEED% DIV 2)
       point{(i%)}.pmode% = RND(254)
       point{(i%)}.tmode% = RND(5)-1
       point{(i%)}.cmode% = RND(17)-1
     NEXT
     ENDPROC


     
DEFPROC_movePoints( point{()} )
     LOCAL i%
     FOR i% = 0 TO NUM%
       IF point{(i%)}.x + point{(i%)}.dx >= _WIDTH% OR  point{(i%)}.x + point{(i%)}.dx<=0 THEN
         
point{(i%)}.dx = point{(i%)}.dx *-1
       ELSE
         
point{(i%)}.x += point{(i%)}.dx
       ENDIF
       IF
point{(i%)}.y + point{(i%)}.dy >= _HEIGHT% OR  point{(i%)}.y + point{(i%)}.dy<=0 THEN
         
point{(i%)}.dy = point{(i%)}.dy *-1
       ELSE
         
point{(i%)}.y += point{(i%)}.dy
       ENDIF

       IF NOT
(-SGN(RND(_CHANGE_RATE%) MOD _CHANGE_RATE%)) point{(i%)}.tmode% -= 1
       IF point{(i%)}.tmode% < 0 point{(i%)}.tmode% = 5

       IF NOT(-SGN(RND(_CHANGE_RATE%*100) MOD (_CHANGE_RATE%*100))) point{(i%)}.pmode% -= 1
       IF point{(i%)}.pmode% <= 0 point{(i%)}.pmode% = 254

     NEXT
     ENDPROC


Particles

There are loads of cool particle systems out there: we even a post on it last week.  So I decided to write my own today and here is the video.  The particles follow your mouse as though your mouse pointer was a source of gravity.



Here is the BB4W code for you to play with.

     REM Particles
     REM version 1.0.0.1
     REM T Street
     REM 2015-11-08
     REM Particles acting under gravity
     
MODE 12 : OFF
     OSCLI
"escape off"
     ON ERROR ERROR 0, "Ooops! Something went wrong. A particle probably left the edge of the known universe."
     REM global constants
     
NumParticles% = 200 : REM increase if you have a fast machine
     
GravityConstant% = 50 : REM increase for stronger gravity
     
ParticleSize% = 16 : REM size of each particle

     REM set up the initial positions of particles
     
DIM part{(NumParticles%) x, y, dx, dy, red%, green%, blue% }
     PROC_randomPositions( part{()}, NumParticles%)
     PROC_randomColours( part{()}, NumParticles%)

     REM main loop
     
REPEAT
       OSCLI
"refresh off"
       CLS
       PROC
_showParticles( part{()}, NumParticles%)
       MOUSE x, y, click : REM get current position of the mouse
       
PROC_moveParticles( part{()}, NumParticles%, x, y )
       OSCLI "refresh on"
       OSCLI "refresh"
     UNTIL FALSE


     
DEFPROC_moveParticles( particle{()}, n%, x, y )
     REM find the current distance from the mouse
     REM and apply effect on motion of particle
     
LOCAL i%
     LOCAL d : REM distance
     
FOR i% = 0 TO n%
       REM find distance from mouse
       
d = SQR( ((particle{(i%)}.x - x )^2) +  ((particle{(i%)}.y - y )^2) )
       IF d<>0 THEN
         
REM add new velocity
         
particle{(i%)}.dx += (GravityConstant% *  (x - particle{(i%)}.x) / d^2 )
         particle{(i%)}.dy += (GravityConstant% *  (y - particle{(i%)}.y) / d^2 )
       ENDIF
       
REM change particle's position by speed factor
       
particle{(i%)}.x += particle{(i%)}.dx
       particle{(i%)}.y += particle{(i%)}.dy
     NEXT
     ENDPROC

     
DEFPROC_showParticles( particle{()}, n% )
     REM show particles on screen
     
LOCAL i%
     FOR i% = 0 TO n%
       COLOUR 1, particle{(i%)}.red%, particle{(i%)}.green%, particle{(i%)}.blue%
       GCOL 0,1
       CIRCLE FILL particle{(i%)}.x, particle{(i%)}.y, ParticleSize%
     NEXT
     ENDPROC

     
DEFPROC_randomPositions( particle{()}, n% )
     REM assign a new position to the particles at random
     
LOCAL i%
     FOR i% = 0 TO n%
       particle{(i%)}.x  = RND(2000)
       particle{(i%)}.y  = RND(2000)
     NEXT
     ENDPROC

     
DEFPROC_randomColours( particle{()}, n% )
     REM assign a new position to the particles at random
     REM (blue not used)
     
LOCAL i%
     FOR i% = 0 TO n%
       particle{(i%)}.red% = RND(255)
       particle{(i%)}.green% = RND(255)
     NEXT
     ENDPROC



...And here is version 2 which forbids the particles from leaving the confines of the screen.

     REM Particles
     REM version 1.0.0.2
     REM T Street
     REM 2015-11-08
     REM Particles acting under gravity
     
MODE 12 : OFF
     OSCLI
"escape off"
     ON ERROR ERROR 0, "Ooops! Something went wrong. A particle probably left the edge of the known universe."
     REM global constants
     
NumParticles% = 100 : REM increase if you have a fast machine
     
GravityConstant% = 100 : REM increase for stronger gravity
     
ParticleSize% = 16 : REM size of each particle

     REM set up the initial positions of particles
     
DIM part{(NumParticles%) x, y, dx, dy, red%, green%, blue% }
     PROC_randomPositions( part{()}, NumParticles%)
     PROC_randomColours( part{()}, NumParticles%)

     REM main loop
     
REPEAT
       OSCLI
"refresh off"
       CLS
       PROC
_showParticles( part{()}, NumParticles%)
       MOUSE x, y, click : REM get current position of the mouse
       
PROC_moveParticles( part{()}, NumParticles%, x, y )
       OSCLI "refresh on"
       OSCLI "refresh"
       *|wait 1 : rem optional pause
     UNTIL FALSE



     
DEFPROC_moveParticles( particle{()}, n%, x, y )
     REM find the current distance from the mouse
     REM and apply effect on motion of particle
     
LOCAL i%
     LOCAL d : REM distance
     
FOR i% = 0 TO n%
       REM find distance from mouse
       
d = SQR( ((particle{(i%)}.x - x )^2) +  ((particle{(i%)}.y - y )^2) )
       IF d<>0 THEN
         
REM add new velocity
         
particle{(i%)}.dx += (GravityConstant% *  (x - particle{(i%)}.x) / d^2 )
         particle{(i%)}.dy += (GravityConstant% *  (y - particle{(i%)}.y) / d^2 )
       ENDIF
       
REM change particle's position by speed factor
       
particle{(i%)}.x += particle{(i%)}.dx
       particle{(i%)}.y += particle{(i%)}.dy
       IF particle{(i%)}.x < 0 OR particle{(i%)}.x > 1920 particle{(i%)}.dx = particle{(i%)}.dx *-1
       IF particle{(i%)}.y < 0 OR particle{(i%)}.y > 1536 particle{(i%)}.dy = particle{(i%)}.dy *-1
     NEXT
     ENDPROC


     
DEFPROC_showParticles( particle{()}, n% )
     REM show particles on screen
     
LOCAL i%
     FOR i% = 0 TO n%
       COLOUR 1, particle{(i%)}.red%, particle{(i%)}.green%, particle{(i%)}.blue%
       GCOL 0,1
       CIRCLE FILL particle{(i%)}.x, particle{(i%)}.y, ParticleSize%
     NEXT
     ENDPROC



     
DEFPROC_randomPositions( particle{()}, n% )
     REM assign a new position to the particles at random
     
LOCAL i%
     FOR i% = 0 TO n%
       particle{(i%)}.x  = RND(1920)
       particle{(i%)}.y  = RND(1536)
     NEXT
     ENDPROC


     
DEFPROC_randomColours( particle{()}, n% )
     REM assign a new position to the particles at random
     REM (blue not used)
     
LOCAL i%
     FOR i% = 0 TO n%
       particle{(i%)}.red% = RND(255)
       particle{(i%)}.green% = RND(255)
     NEXT
     ENDPROC

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

Random Walk 3 - snakes!!

Remember the old Nokia game "SNAKE"?  Well, I decided to make a snake-like program in BB4W for today's random walk.  The program produces a number of snakes on the screen which then move randomly around.  Yes, you can have more than one snake.  Yes, they don't walk off the edge (that bit was quite tricky which is why this program took over an hour to code).  The snakes are different random colours, with the strongest colours indicated the heads.  Oh, and two other rules: snakes CAN move over each other, and themselves, but they cannot turn immediately back on themselves.

Enjoy!

Indiana: There's a big snake in the plane, Jock!
Jock: Oh, that's just my pet snake Reggie.
Indiana: I hate snakes, Jock! I hate 'em!
Jock: Come on! Show a little backbone, will ya!


     REM Snake Walk 1
     REM T Street
     REM 2014-11-12
     
MODE 10  : OFF
     
SCREEN_WIDTH% = 1440
     SCREEN_HEIGHT% = 1152

     REM snake parameters
     
SNAKE_RADIUS% = 16 : REM size of the segments
     
SEGMENTS% = 20 : 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{}

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

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

       PROC_moveSnake( snake1{} )
       PROC_moveSnake( snake2{} )
       PROC_moveSnake( snake3{} )
       PROC_moveSnake( snake4{} )
       PROC_moveSnake( snake5{} )

       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.head%
     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% <0 THEN i% = SEGMENTS%-1
       IF i% = this.tail% 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


Five Nokia snakes moving randomly around the screen.  Have fun changing the size and lengths of the snakes.

Label