Thursday, 20 November 2014

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.

Wednesday, 19 November 2014

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.

Wednesday, 12 November 2014

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.

Tuesday, 11 November 2014

Random Walk 2

Continuing our Random Walk program, here is an example that uses coloured lines for the walk.  A new line is drawn to a random position of maximum radius no more than the square root of (2*size% squared).  The thickness of the line is controlled by the thickness% variable.

     REM random walker
     REM T Street
     
MODE 10 : OFF

     
x% = 720
     y% = 576

     size% = 300
     thickness% = 20

     col% = 0

     MOVE x%, y%

     REPEAT
       
REM find new coordinate
       REM within the bounds of the screen
       
REPEAT
         
plusx% = RND(size%) - size% DIV 2
         plusy% = RND(size%) - size% DIV 2
       UNTIL (x%+plusx%)>=0 AND (x%+plusx%)<1440 AND (y%+plusy%)>=0 AND (y%+plusy%)<1152

       REM get a new colour
       
COLOUR 1, 0, col%, 200
       col% += 1
       GCOL 0,1 : REM draw in this colour

       REM draw a new line
       
*refresh off
       FOR i% = 1 TO thickness%
         MOVE x%+i%, y%
         DRAW x%+plusx%+i%, y%+plusy%
       NEXT
       
* refresh on

       REM move to the end of the line
       REM ready for the next line
       
x% += plusx%
       y% += plusy%
       MOVE x%, y%

       REM wait a 'mo
       
WAIT 5

       REM should clear screen?
       
IF col%>255 THEN
         
col% = 0
         WAIT 50
         CLS
       ENDIF

     UNTIL FALSE




The following code produces THREE walkers.  Each start at random positions and have different thicknesses, colours and random lengths.

     REM three random walkers
     
MODE 10 : OFF

     
REM set up the walkers
     
DIM walker{(2) x%, y%, red%, green%, blue%, size%, thickness%, age% }

     screenwidth% = 1440 :
     screenheight% = 1152
     maxSize% = 400
     maxWidth% = 40

     REM initial positions
     
FOR i% =0 TO 2
       PROC_setInitialPosition( walker{(i%)} )
     NEXT

     
walker{(0)}.green% = 1 : walker{(0)}.blue% = 1
     walker{(1)}.green% = 1
     walker{(2)}.blue% = 1

     REPEAT
       
REM draw each walker
       
FOR i% = 0 TO 2
         PROC_drawNew( walker{(i%)} )
       NEXT
       
REM wait a 'mo
       
WAIT 5
     UNTIL FALSE


     
DEFPROC_setInitialPosition( this{} )
     REM random starting state for a walker
     
this.x% = RND(screenwidth%)
     this.y% = RND(screenheight%)
     this.size% = RND(maxSize%) +20
     this.thickness% = RND(maxWidth%) + 4
     this.age% = RND(255)
     ENDPROC


     
DEFPROC_drawNew( this{} )
     LOCAL plusx%, plusy%, x%, y%, i%
     x% = this.x%
     y% = this.y%
     REM get new position
     
REPEAT
       
plusx% = RND(this.size%) - this.size% DIV 2
       plusy% = RND(this.size%) - this.size% DIV 2
     UNTIL (x%+plusx%)>=0 AND (x%+plusx%)<screenwidth% AND (y%+plusy%)>=0 AND (y%+plusy%)<screenheight%

     COLOUR 1, this.red%*(255-this.age%), this.green%*(255-this.age%), this.blue%*(255-this.age%)
     GCOL 0,1

     REM draw line
     REM draw a new line
     
*refresh off
     FOR i% = 1 TO this.thickness%
       MOVE x%+i%, y%
       DRAW x%+plusx%+i%, y%+plusy%
     NEXT
     
* refresh on
     REM move to the end of the line
     REM ready for the next line
     
x% += plusx%
     y% += plusy%
     MOVE x%, y%

     this.x% = x%
     this.y% = y%

     this.age% += 1
     IF this.age% > 255 this.age% = 0
     ENDPROC


Random walker program with 3 walkers.


Three walker program shortly after the initial state.

Sunday, 9 November 2014

Random Walk

This program produces a pattern by randomly drawing a coloured disk either abover, below, left or right of the previous disk.

     REM random walk
     REM T Street (superdecade Games)
     
MODE 10 : OFF
     
REM greyish background
     
COLOUR 1, 220, 220, 220
     COLOUR 129 : CLS
     
REM black outline
     
COLOUR 2, 0,0,0

     size% = 42
     REM start position
     
x% = 720
     y% = 576

     REM main loop
     
REPEAT
       
*refresh off
       REM get a new random colour
       
COLOUR 1, 0, RND(255), RND(255)
       REM draw black border
       
GCOL 0,2
       REM draw a circle
       
CIRCLE FILL  x%, y%, size% DIV 2
       REM draw coloured center
       
GCOL 0,1
       CIRCLE FILL  x%, y%, size% DIV 2 - 4
       *refresh on
       REM make a random walk
       
CASE RND(4) OF
         WHEN 
1 x% += size%
         WHEN 2 x% -= size%
         WHEN 3 y% += size%
         WHEN 4 y% -= size%
       ENDCASE

       
REM wait a mo'
       
WAIT 5

     UNTIL FALSE


A random walk.  Note, it is possible for the disks to 'walk' off the edge of the screen.
The following program prevents the disks from walking off the edge of the screen, by 'nudging' them back on if they cross the line.

     REM random walk 2
     REM T Street (superdecade Games)
     
MODE 10 : OFF
     
REM greyish background
     
COLOUR 1, 220, 220, 220
     COLOUR 129 : CLS
     
REM black outline
     
COLOUR 2, 0,0,0

     size% = 42
     REM start position
     
x% = 720
     y% = 576

     REM main loop
     
REPEAT
       
*refresh off
       REM get a new random colour
       
COLOUR 1, 0, RND(255), RND(255)
       REM draw black border
       
GCOL 0,2
       REM draw a circle
       
CIRCLE FILL  x%, y%, size% DIV 2
       REM draw coloured center
       
GCOL 0,1
       CIRCLE FILL  x%, y%, size% DIV 2 - 4
       *refresh on
       REM make a random walk
       
CASE RND(4) OF
         WHEN 
1 x% += size%
         WHEN 2 x% -= size%
         WHEN 3 y% += size%
         WHEN 4 y% -= size%
       ENDCASE

       
REM check disk hasn't walked off the screen
       
IF x%<0 THEN x% += (size%*2)
       IF x%>1440 THEN x% -= (size%*2)
       IF y%<0 THEN y% += (size%*2)
       IF y%>1152 THEN y% -= (size%*2)
       REM wait a mo'
       
WAIT 5

     UNTIL FALSE


Another random walk.  How would you change the size of the disks?  How would you change the size of the border?  How would you speed up the walk?
Another version of the program.  This time, the current disk momentarily blinks red as it is drawn.  Also, the process speed is increased and the size of disk has been increased.

     REM random walk 3
     
MODE 10 : OFF
     
REM greyish background
     
COLOUR 1, 220, 220, 220
     COLOUR 129 : CLS
     
REM black outline
     
COLOUR 2, 0,0,0
     REM red highlight
     
COLOUR 3, 255, 0, 0

     size% = 100
     REM start position
     
x% = 720
     y% = 576

     REM main loop
     
REPEAT
       
*refresh off
       REM get a new random colour
       
COLOUR 1, 0, RND(255), RND(255)
       REM draw black border
       
GCOL 0,2
       REM draw a circle
       
CIRCLE FILL  x%, y%, size% DIV 2
       REM draw coloured center
       
GCOL 0,3
       CIRCLE FILL  x%, y%, size% DIV 2 - 4
       *refresh on
       WAIT 2
       GCOL 0,1
       CIRCLE FILL  x%, y%, size% DIV 2 - 4

       REM make a random walk
       
CASE RND(4) OF
         WHEN 
1 x% += size%
         WHEN 2 x% -= size%
         WHEN 3 y% += size%
         WHEN 4 y% -= size%
       ENDCASE

       
REM check disk hasn't walked off the screen
       
IF x%<0 THEN x% += (size%*2)
       IF x%>1440 THEN x% -= (size%*2)
       IF y%<0 THEN y% += (size%*2)
       IF y%>1152 THEN y% -= (size%*2)
       REM wait a mo'
       
WAIT 1

     UNTIL FALSE


Red marks the current position of the 'walker'
In the following program, the random walk is determined not by a random number, but by the ASCII value of the string the user types in at the beginning, thus repeating patterns can be generated.

     REM random walk 4
     REM T Street (superdecade Games)
     
MODE 10 : OFF
     REPEAT
       INPUT 
"Enter a string ( more than 2 characters ) : " astring$
     UNTIL LEN(astring$) > 2

     REM greyish background
     
COLOUR 1, 220, 220, 220
     COLOUR 129 : CLS
     
REM black outline
     
COLOUR 2, 0,0,0

     size% = 36
     REM start position
     
x% = 720
     y% = 576

     n% = 1 : REM poition in string
     REM main loop
     
REPEAT
       
*refresh off
       REM get a new random colour
       
COLOUR 1, 0, RND(255), RND(255)
       REM draw black border
       
GCOL 0,2
       REM draw a circle
       
CIRCLE FILL  x%, y%, size% DIV 2
       REM draw coloured center
       
GCOL 0,1
       CIRCLE FILL  x%, y%, size% DIV 2 - 4
       *refresh on
       REM make a random walk
       
a% = ASC(MID$(astring$, n%, 1)) MOD 4 + 1
       n% += 1
       IF n% > LEN(astring$) n% = 1
       CASE a% OF
         WHEN 
1 x% += size%
         WHEN 2 x% -= size%
         WHEN 3 y% += size%
         WHEN 4 y% -= size%
       ENDCASE

       
REM wait a mo'
       
WAIT 5

     UNTIL FALSE