Life Simulator

Life Simulator

So I coded a life simulator. The rules: starting with about 20 critters in a world of vegetation critters can (a) move randomly each turn, (b) eat vegetation if they can, (c) reproduce if a male meets a female.

video

Critters can die of malnutrition and old age.  In this video you see a slow start to the colony, followed by a population explosion after about 56 seconds.  The colony dies off after it has eaten most of the vegetation available.

Source code: coming soon!

New images for Spellunker coming soon

Ever wondered what a Semanticore looks like?  How about a Lexicorn?  I've just heard from Pob, the artist responsible for the graphics in Spellunker and he tells me that he is working on some new graphics for each level of Spellunker - the spelling game from superdecade games.  At this point we will also make the wild speculation that the next release will feature new artwork, as well as new levels, including some REALLY DIFFICULT ones for the truly hard core spellunkers of you out there.

Thanks to everyone who has downloaded and played Spellunker, so far.  If you haven't then proceed to the downloads page and get Spellunking soon!

Pob's wonderful artwork depicting Wordsworth Spellunker and his adventures.  We are excited to see his new additions.

Solar System Simulator

Solar System Simulator

I'm still waiting for my supper to cook, so I've written a simple solar system simulator.  Create any number of 'planets' and put them into random orbits around a star.  Sure, some of the planets are going to be ejected into deep space, never to been seen again, but for the lucky few - you may see a stable orbit, and who knows, if the conditions are right maybe life will flourish?

video

Again, keen students will want to change a few parameters.  The solar gravity is a good one to modify, as is the number of planets created.  Have fun, and as always, this program will run under the free version of BB4Win, and Windows executables are available on demand.

Source code follows:

     REM Solar System Simulator
     REM T Street
     REM 2014-11-25
     
MODE 10  : OFF
     
REM screen dimensions
     
SCREEN_WIDTH% = 1440
     SCREEN_HEIGHT% = 1152

     REM -------------------------------------------
     REM STUFF TO MUCK AROUND WITH
     REM -------------------------------------------
     
SUN_RADIUS% = 100 : REM pixels
     
SUN_MASS% = 100   : REM relative units
     
PLANETS% = 30
     REM -------------------------------------------

     
BLACK% = 1 : COLOUR BLACK%, 0, 0, 0
     SUN_COL% = 2 : COLOUR SUN_COL%, 255, 255, 0
     PLANET_COL% =  3 : REM colour pot for planets
     
PLANET_MULT% = 4 : REM size of planet per unit of mass

     REM create the planet structure
     
DIM planet{(PLANETS%-1) x, y, dx, dy, mass, green%, blue% }

     REM randomly create planets
     
PROC_createPlanet( planet{()} )

     REM MAIN LOOP
     
REPEAT
       
*refresh off
       PROC_drawSun
       PROC_drawPlanets( planet{()} )
       *refresh
       WAIT 5
       *refresh off
       PROC_removePlanets( planet{()} )
       *refresh
       PROC_move( planet{()} )
       PROC_gravity( planet{()} )
     UNTIL FALSE



     
DEFPROC_createPlanet( this{()} )
     REM creates random planets
     
LOCAL i%
     FOR i% = 0 TO PLANETS%-1
       this{(i%)}.x  = RND(SCREEN_WIDTH%)
       this{(i%)}.y  = RND(SCREEN_HEIGHT%)
       this{(i%)}.dx = RND(10)+5
       this{(i%)}.dy = RND(10)+5
       this{(i%)}.green% = RND(256)-1
       this{(i%)}.blue% = RND(256)-1
       this{(i%)}.mass = RND(10)
     NEXT
     ENDPROC


     
DEFPROC_drawSun
     REM draws the yellow star in center of screen
     
GCOL 0, SUN_COL%
     CIRCLE FILLSCREEN_WIDTH% DIV 2, SCREEN_HEIGHT% DIV 2, SUN_RADIUS%
     ENDPROC


     
DEFPROC_drawPlanets( this{()} )
     REM draw each planet
     
LOCAL i%
     FOR i% = 0 TO PLANETS% -1
       COLOUR PLANET_COL%, 0, this{(i%)}.green%, this{(i%)}.blue%
       GCOL 0, PLANET_COL%
       CIRCLE FILL this{(i%)}.x, this{(i%)}.y, this{(i%)}.mass * PLANET_MULT%
     NEXT
     ENDPROC

     
DEFPROC_removePlanets( this{()} )
     REM remove planets from the screen
     
LOCAL i%
     GCOL 0, BLACK%
     FOR i% = 0 TO PLANETS% -1
       CIRCLE FILL this{(i%)}.x, this{(i%)}.y, this{(i%)}.mass * PLANET_MULT%
     NEXT
     ENDPROC


     
DEFPROC_move( this{()} )
     REM move planet due to its own velocity
     
LOCAL i%
     FOR i% = 0 TO PLANETS% -1
       this{(i%)}.x += this{(i%)}.dx
       this{(i%)}.y += this{(i%)}.dy
     NEXT
     ENDPROC


     
DEFPROC_gravity( this{()} )
     REM apply gravity to each planet from the sun
     
LOCAL distance
     LOCAL i% : REM iterator
     
FOR i% = 0 TO PLANETS% - 1
       distance = SQR( (SCREEN_WIDTH% DIV 2 - this{(i%)}.x)^2 + (SCREEN_HEIGHT% DIV 2 - this{(i%)}.y)^2 )
       IF distance<>0 THEN
         
this{(i%)}.dx += ( this{(i%)}.mass * SUN_MASS% * (SCREEN_WIDTH% DIV 2 - this{(i%)}.x) / distance^2 )
         this{(i%)}.dy += ( this{(i%)}.mass * SUN_MASS% * (SCREEN_HEIGHT% DIV 2 - this{(i%)}.y) / distance^2 )
       ENDIF
     NEXT
     ENDPROC

Bouncing balls 2

Continuing our series of short animation programs, or as I will refer to them now - 'programs written while I wait for my tea to cook' - it is a simple hack to change yesterday's program to make the balls bounce off the walls rather than just the floor.  No longer acted on by gravity, the balls are initialized at random positions with random velocities and float around in space like some sort of cosmic blue-green bubbles.

video

Again, the keen student will want to change the parameters for more fun.

Come back soon and I'll have the balls bouncing off each other as well.

These programs are small enough to run in the free version of BB4Win, but contact me if you require the Windows executable versions.

Bouncy balls particle system.  Balls now bounce off the walls of the screen.

Source code follows:

     REM bouncing balls 2
     REM T Street
     REM 2014-11-25
     
MODE 10  : OFF
     
REM screen dimensions
     
SCREEN_WIDTH% = 1440
     SCREEN_HEIGHT% = 1152

     REM --------------------------------------------------
     REM CHANGE THESE PARAMETERS FOR MORE FUN
     REM --------------------------------------------------
     
MAX_BALL_SIZE% = 70 : REM max size of a ball

     REM don't set too high unless you have a fast computer
     
NUM_BALLS% = 30

    
 MAX_SPEED% = 20
     DELAY% = 7
     REM --------------------------------------------------


     REM some colours
     
COLOUR 1, 0, 0, 0 : REM black

     REM the ball object
     
DIM ball{( NUM_BALLS% -1) x, y,      \ coordinates
     
\                         r%,        \ ball radius
     
\                         dx, dy,    \ component of velocity
     
\                         green%,    \ amount of green
     
\                         blue%      \ amounf of blue
     
\ }


     PROC_createBalls( ball{()} )

     REM MAIN LOOP
     
REPEAT
       PROC
_showBalls( ball{()} )
       WAIT DELAY%
       PROC_deleteBalls( ball{()} )
       PROC_moveBalls( ball{()} )
     UNTIL FALSE




     
DEFPROC_createBalls( this{()} )
     REM give each ball a random position and velocity
     
LOCAL i%
     FOR i% = 0 TO NUM_BALLS% - 1
       this{(i%)}.x = RND(SCREEN_WIDTH%)
       this{(i%)}.y = RND(SCREEN_HEIGHT%)
       this{(i%)}.dx = RND(MAX_SPEED%)-(MAX_SPEED% DIV 2)
       this{(i%)}.dy = RND(MAX_SPEED%)-(MAX_SPEED% DIV 2)
       this{(i%)}.r% = 10 + RND(MAX_BALL_SIZE%)
       this{(i%)}.green% = RND(255)
       this{(i%)}.blue% = RND(255)
     NEXT
     ENDPROC


     
DEFPROC_showBalls( this{()} )
     REM draw all the balls on the screen
     
LOCAL i%
     *refresh off
     FOR i% = 0 TO NUM_BALLS%-1
       GCOL 0,1
       CIRCLE FILL this{(i%)}.x, this{(i%)}.y, this{(i%)}.r%
       REM get colour for ball
       
COLOUR 2, 0, this{(i%)}.green%, this{(i%)}.blue%
       GCOL 0, 2
       CIRCLE FILL this{(i%)}.x, this{(i%)}.y, this{(i%)}.r% - 4
     NEXT
     
*refresh on
     ENDPROC


     
DEFPROC_deleteBalls( this{()} )
     REM remove all the balls on the screen
     
LOCAL i%
     *refresh off
     FOR i% = 0 TO NUM_BALLS%-1
       GCOL 0,1
       CIRCLE FILL this{(i%)}.x, this{(i%)}.y, this{(i%)}.r%
       REM get colour for ball
     
NEXT
     
*refresh on
     ENDPROC


     
DEFPROC_moveBalls( this{()} )
     REM move the balls
     
LOCAL i%
     FOR i% = 0 TO NUM_BALLS%-1
       this{(i%)}.y += (this{(i%)}.dy)
       this{(i%)}.x += (this{(i%)}.dx)

       REM check for going off the screen
       
IF this{(i%)}.y < 0 OR this{(i%)}.y > SCREEN_HEIGHT% THEN
         
REM bounce!
         
this{(i%)}.dy = this{(i%)}.dy * -1
       ENDIF

       IF 
this{(i%)}.x < 0 OR this{(i%)}.x > SCREEN_WIDTH% THEN
         
REM bounce!
         
this{(i%)}.dx = this{(i%)}.dx * -1
       ENDIF

     NEXT
     ENDPROC
Bouncing balls

Bouncing balls

A simple program in BB4W BASIC featuring some coloured bouncing balls.  Students will like to change the various parameters for more fun!  Will run in the free version of BB4W.

Change the size of the balls; the total number of balls; the height dropped; the strength of gravity and the 'bounciness' of the balls.

video

Source code below:

     REM balls bouncing under gravity
     REM T Street
     REM 2014-11-25
     
MODE 10  : OFF
     
REM screen dimensions
     
SCREEN_WIDTH% = 1440
     SCREEN_HEIGHT% = 1152

     REM --------------------------------------------------
     REM CHANGE THESE PARAMETERS FOR MORE FUN
     REM --------------------------------------------------
     
MAX_BALL_SIZE% = 70 : REM max size of a ball

     REM don't set too high unless you have a fast computer
     
NUM_BALLS% = 30

     Y_OFFSET% = 100 : REM the minimum distance from the ground

     
GRAVITY = 9.8 : REM strength of gravity
     
BOUNCINESS = 0.91 : REM how bouncy the balls are

     
DELAY% = 7
     REM --------------------------------------------------


     REM some colours
     
COLOUR 1, 0, 0, 0 : REM black

     REM the ball object
     
DIM ball{( NUM_BALLS% -1) x, y,    \ coordinates
     
\                         r%,        \ ball radius
     
\                         velocity , \ integer component of velocity
     
\                         green%,    \ amount of green
     
\                         blue%      \ amounf of blue
     
\ }


     PROC_createBalls( ball{()} )

     REM MAIN LOOP
     
REPEAT
       PROC
_showBalls( ball{()} )
       WAIT DELAY%
       PROC_deleteBalls( ball{()} )
       PROC_moveBalls( ball{()} )
     UNTIL FALSE




     
DEFPROC_createBalls( this{()} )
     REM give each ball a random position and velocity
     
LOCAL i%
     FOR i% = 0 TO NUM_BALLS% - 1
       this{(i%)}.x = RND(SCREEN_WIDTH%)
       this{(i%)}.y = RND(SCREEN_HEIGHT%-Y_OFFSET%)+Y_OFFSET%
       this{(i%)}.r% = 10 + RND(MAX_BALL_SIZE%)
       this{(i%)}.green% = RND(255)
       this{(i%)}.blue% = RND(255)
     NEXT
     ENDPROC


     
DEFPROC_showBalls( this{()} )
     REM draw all the balls on the screen
     
LOCAL i%
     *refresh off
     FOR i% = 0 TO NUM_BALLS%-1
       GCOL 0,1
       CIRCLE FILL this{(i%)}.x, this{(i%)}.y, this{(i%)}.r%
       REM get colour for ball
       
COLOUR 2, 0, this{(i%)}.green%, this{(i%)}.blue%
       GCOL 0, 2
       CIRCLE FILL this{(i%)}.x, this{(i%)}.y, this{(i%)}.r% - 4
     NEXT
     
*refresh on
     ENDPROC


     
DEFPROC_deleteBalls( this{()} )
     REM remove all the balls on the screen
     
LOCAL i%
     *refresh off
     FOR i% = 0 TO NUM_BALLS%-1
       GCOL 0,1
       CIRCLE FILL this{(i%)}.x, this{(i%)}.y, this{(i%)}.r%
       REM get colour for ball
     
NEXT
     
*refresh on
     ENDPROC


     
DEFPROC_moveBalls( this{()} )
     REM move the balls
     
LOCAL i%
     FOR i% = 0 TO NUM_BALLS%-1
       this{(i%)}.y += (this{(i%)}.velocity)
       this{(i%)}.velocity -= GRAVITY
       REM check for going off the bottom of the screen
       
IF this{(i%)}.y < this{(i%)}.r% THEN
         
REM bounce!
         
this{(i%)}.velocity = ABS(this{(i%)}.velocity) * BOUNCINESS
       ENDIF
     NEXT
     ENDPROC

Excuse Generator

The excuse generator creates random excuses to get you out of any trouble (not guaranteed).  It is a nice way to show both random numbers and storing data in arrays in BB4Win.  Students will want to add their own data to the program and this is achieved by adding to the "data" statements at the end, and changing the values of LEADS%, PERPS% and DELAYS% accordingly.


Excuses, excuses, excuses....


     REM excuse creator
     REM T Street
     REM 2014-11-24

     
LEADS%  = 6 : REM number of lead-ins
     
PERPS%  = 6 : REM number of perpetrators
     
DELAYS% = 6 : REM number of delaying factors

     REM set up arrays to hold all the excuses
     
DIM lead$( LEADS%-1 )
     DIM perp$( PERPS%-1 )
     DIM delay$( DELAYS%-1 )

     PROC_populateArrays

     PRINT "EXCUSE GENERATOR"
     PRINT "Press any key to get a new excuse"
     PRINT "---------------------------------"''
     REPEAT
       PRINT FN
_getExcuse
       g = GET
     UNTIL FALSE


     
DEFFN_getExcuse
     REM gets three random parts and sticks them together
     
= lead$(RND(LEADS%)-1)+" "+perp$(RND(PERPS%)-1)+" "+delay$(RND(DELAYS%)-1)+"!"


     DEFPROC_populateArrays
     REM puts the data into the arrays
     
LOCAL n%
     FOR n% = 0 TO LEADS%-1
       READ lead$(n%)
     NEXT
     FOR 
n% = 0 TO PERPS%-1
       READ perp$(n%)
     NEXT
     FOR 
n% = 0 TO DELAYS%-1
       READ delay$(n%)
     NEXT
     ENDPROC

     
REM lead-ins
     
DATA "I'm sorry but", "Please forgive me"
     
DATA "I apologize, however", "I'm never usually like this, but"
     
DATA "You're never going to believe this, but", "So, I was minding my own business when boom!..."

     
REM perpetrators
     
DATA "your mum", "my mum"
     
DATA "Godzilla", "the ghost of Hitler"
     
DATA "Darth Vader", "Kevin Specey"

     
REM delaying factors
     
DATA "tried to kill me", "ate my homework"
     
DATA "stole my bycyle", "stole my identity"
     
DATA "kept asking me 'why?' and wouldn't stop", "came after me"

Happy Birthday Windows 1.0

Windows is 29 years old today.  Here is a timeline showing some of the versions of Windows (that I have used).

It begins!  Oooh look, Reversi!
Windows 3.1. I remember this version fondly, from a time when playing on the computer meant drawing a picture in MS-Paint or getting killed in Minesweeper.  No World Wide Web yet...
Windows 95.  How do I uninstall Internet Explorer?
Windows 98.  How else would I play Lemmings?
Windows ME.  Again fondly remembered, and I think I still have a working machine tucked away in the back of a cupboard somewhere.
Windows XP - totally mind-blowing at the time.
Vista.  Enough said.
Windows 7.  My first two win 7 laptops are still soldiering on.
Windows 8.1.  Perfect for tablets and phones.  Works well on my desktop computer.  Where is the start button?
Windows 10.  The start button is back!
Visit our larger interactive timeline of computing history by following this link.

Timeline of computing history

We have updated our timeline of computing history to include a dozen new (historic) events; now including a new category for 'operating systems' - for example, did you know that Linux was released before Windows 3.1 ?

The 3D view of the computing timeline.

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

Label