BASIC Computer Games

In 1981, I was 13 years old and teaching myself BASIC on my TRS-80 Model III from official Radio Shack manuals – accurate, comprehensive, and terminally bland.

Into that gray scene came the book Basic Computer Games: Microcomputer Edition (edited by David Ahl of Creative Computing magazine). It changed my life.

I can’t remember now where it came from. Neither my parents, nor my friends, nor my teachers knew much about the home computer scene. It’s possible that I found out about it in Creative Computing magazine and ordered it by mail, or “borrowed” it from somewhere and forgot to return it. The book, subtitled “101 great games to play on your home computer,” was 8-bit-nerd heaven. Pages and pages of program listings in tiny, all-caps, dot matrix type, with brief introductory paragraphs. Plus, funny illustrations of strangely plausible robots. Don’t underestimate the appeal of the robots.

book cover

I spent many, many hours typing in programs from that book. Many of the games inspired variants of my own. For better or worse I became a prolific teenage BASIC programmer. I played some with Z-80 assembly and Logo and Pascal too, but the evidence of the book told me that BASIC was where the fun was at.

Fast forward to 2005. My copy of the book has long since disappeared. David Ahl has more or less retired from the computer scene, but he still has a website where he is clearing out old copies of his books and magazines. But no more copies of Basic Computer Games – my hopes are dashed. I email him anyway to ask about something else; he writes back and says that he does have one copy left. Cheap, too.

It arrived last week. The illustrations alone take me right back to those 8-bit days. The notes on the individual programs mean more to me now, as I can see where they connect with various threads of computing history (the original, pre-microcomputer edition of the book came out in 1973). The coding style is, well, mostly horrible by modern standards, but there’s an inspiring bright spark of fun and creativity there. And many of these programs are classics.

290 PRINT "TURN NO.";T;"WHAT IS YOUR GUESS";
300 INPUT M,N
310 FOR I=1 TO 4
320 IF P(I,1)=-1 THEN 400
330 IF P(I,1)<>M THEN 380
340 IF P(I,2)<>M THEN 380
350 P(I,1)=-1
360 PRINT "YOU HAVE FOUND MUGWUMP";I
370 GOTO 400
380 D=SQR((P(I,1)-M)^2+(P(I,2)-N)^2)
390 PRINT "YOU ARE";(INT(D*10))/10;"UNITS FROM MUGWUMP";I
400 NEXT I

Looking at certain pages gives me an almost physical pang. I suspect the severity of each pang is directly proportional to the number of hours I spent typing, debugging, and possibly even playing the game in question.

In a way, this book was my first open-source experience. It’s not at all clear what the licensing terms of the programs are, beyond the obvious fact that the whole book is copyrighted by Creative Computing. But redistribution was not my concern then. I wanted to see real, working code that did something. Something real. And what’s more real than a game of Mugwump?

My copy of the book is inscribed in the front by Ahl: “Hi Paul – Learn from the past, live for the future.” That’s a deal.

Update: I re-wrote one of these old games in a handful of other languages, and readers have contributed versions as well.

Jim Storch commented on Thu Jan 19 09:50:44 2006:
I remember checking out of copy of that book from the libray and typing games into an Apple II, making minor adjustments so Applebasic would be happy. Sometimes, I still think of Eliza when chatting on an IM client: “Come come, elucidate your thoughts.” Or those darn wild berbers, hidden in the sand…


regeya commented on Tue Jan 24 23:03:15 2006:
I have Volume 2 on my bookshelf, but not the first. I also wasted far too much time typing from that. :-)


José Santos commented on Wed Mar 1 18:55:06 2006:
Hi Paul! I also had a BASIC book, back in the days, don’t remember the title anymore. Those were fun times. I hope to eventually locate it. I’ve found “BASIC Computer Games” online (scanned), as well as volume 2 and lots of others. I suppose you knew about it, cause its the first hit on “basic computer games” on Google. Anyway here it is: http://www.atariarchives.org/basicgames/ , great site. Now i’m going to have fun writing some of those good old games in Lisp. Sweet! :)


Greg Brondo commented on Fri Jan 26 00:29:00 2007:
I’ve got the same book (around the same time). It’s on my bookshelf at the office. It’s Priceless!


M.L. commented :
I had a similar book in german discovering how to program a little text adventure. Don’t remember the name. But it was the starting point to program bigger programs and games - not just number guess. ;-)


George Beker commented :
I am indeed the guy who did the original “BekerBot” drawings - and went on to run a major PR/media firm (all Fortune 50 clients). I am now putzing with a new version of the vintage book and some new (archly cynical) drawings. Want to stay in touch? Also check me out at http://www.bekers.org


george beker commented :
This is Beker again - now there is a robot site - http://www.bekerbots.com


Phil Conrod commented :
Like you Paul, the first computer program I wrote was from the classic programming book edited by David H. Ahl on an HP 1000. Call me a little nostalgic but I also tracked down David H. Ahl to thank him for inspiring me to become a computer programmer when I was a kid. Then I did something really crazy. I asked David if I could have his permission to republish his classic programming book in a modern computer programming language so a whole new generation of kids could also be inspired by his classic book. He said yes and David then volunteered to write an updated 2010 introduction to the new book. George Beker, who illustrated several of the original books, also came out of retirement and added a few more Robot illustrations to a new Special Illustrated edition of the new 2010 book. You can now relive all those classic games like Super Star Trek, MUGWUP and Lunar LEM Rocket. The 2010 Small Basic Edition includes almost all the classic BASIC games that inspired a generation of programmers but now in Microsoft Small Basic for a new generation of kids. It was published as an E-Book so you can easily cut and paste the Small Basic Source Code right into your Small Basic Compiler. You can find out more about this new edition at http://computerscienceforkids.com/SmallBasicComputerGames.aspx. You can also find out more about Microsoft’s new Small Basic Development environment for Kids at http://www.smallbasic.com.


mr small genius commented :
well im a genius at small basic ive got a cool thing il show you now…

GraphicsWindow.Hide()
gw = 800
gh = 600
GraphicsWindow.CanResize = "False"
GraphicsWindow.Top = (Desktop.Height-gh)/2
GraphicsWindow.Left = (Desktop.Width-gw)/2
GraphicsWindow.Title = "Bouncing balls with realistic collision physics"
GraphicsWindow.Width = gw
GraphicsWindow.Height = gh
GraphicsWindow.BackgroundColor = "LightBlue"
'Reduce gw for options
gw = gw-200
GraphicsWindow.MouseDown = OnMouseDown
Start:
' Gravity, friction and attraction to mouse
grav = 0.0 ' 0 for none
fric = 0 ' 0 for none
follow = 0 'attract to mouse
attract = 0 'attract balls to each other
dt = 1 'timestep (speed)
shape = 0 '0:ball,1 square
elastic = 1 '1 fully elastic collisions
Colour = "Yellow"
'Initialise some balls
radius = 20
diam = 2*radius
nball = Math.Floor(gw/diam)
istart = "True"
reset()
ireset = "False"
istart = "False"
iend = "False"
iselect = "False"
ioptions = "False"
'Show window - an MS comment
GraphicsWindow.Show()
'Main loop
While ("True")
 If (ioptions) Then
   options()
   ioptions = "False"
 EndIf
 energy = 0.0
 isCollision = "False"
 If (iselect) Then
   For i = 1 To nball
     x = Xpos[i]
     y = Ypos[i]
     dist = (xm-x)*(xm-x)+(ym-y)*(ym-y)
     If (dist < radius*radius) Then
       u = 0
       v = 0
       Xvel[i] = u
       Yvel[i] = v
     EndIf
   EndFor
   iselect = "False"
 EndIf
 For i = 1 To nball
   update()
   move()
   u = Xvel[i]
   v = Yvel[i]
   energy = energy+(u*u+v*v)
 EndFor
 energy = dt*dt*energy
 energy = Math.Floor(energy)
 GraphicsWindow.BrushColor = "LightBlue"
 GraphicsWindow.FillRectangle(gw+15,560,190,20)
 GraphicsWindow.BrushColor = "Black"
 GraphicsWindow.DrawText(gw+65,560,"Energy "+energy)
 If (ireset) Then
   reset()
   ireset = "False"
 EndIf
 If (istart) Then
   Goto Start
 EndIf
 If (iend) Then
   Program.End()
 EndIf
' If (isCollision) Then
' Sound.PlayClick()
' EndIf
 Program.Delay(10)
EndWhile
'Update ball positions
Sub update
 u = Xvel[i]
 v = Yvel[i]
 u = Math.Min(100,Math.Max(u,-100))
 v = Math.Min(100,Math.Max(v,-100))
 x = Xpos[i]+dt*u
 y = Ypos[i]+dt*v
 bounce()
 gravity()
 collision()
 attraction()
 Xpos[i] = x
 Ypos[i] = y
EndSub
'Check for edge bounces
Sub bounce
 If (x < radius) Then
   Xvel[i] = -Xvel[i]
   x = radius
 EndIf
 If (x > gw-radius) Then
   Xvel[i] = -Xvel[i]
   x = gw-radius
 EndIf
 If (y < radius) Then
   Yvel[i] = -Yvel[i]
   y = radius
 EndIf
 If (y > gh-radius) Then
   Yvel[i] = -Yvel[i]
   y = gh-radius
 EndIf
EndSub
'Check for collisions
Sub collision
 'Only check each pair once
 For j = i+1 To nball
   xi = x
   yi = y
   xj = Xpos[j]
   yj = Ypos[j]
   dx = xi-xj
   dy = yi-yj
   dist = Math.SquareRoot(dx*dx+dy*dy)
   If (dist < diam) Then
     isCollision = "True"
     'Get ball vectors
     ui = Xvel[i]
     vi = Yvel[i]
     uj = Xvel[j]
     vj = Yvel[j]
     'Move backwards (forwards if dt < 0) in time until balls are just touching
     CoefA = (ui-uj)*(ui-uj)+(vi-vj)*(vi-vj)
     CoefB = 2*((ui-uj)*(xi-xj)+(vi-vj)*(yi-yj))
     CoefC = (xi-xj)*(xi-xj)+(yi-yj)*(yi-yj)-diam*diam
     If (CoefA = 0) Then
       t = -CoefC/CoefB
     Else
       If (dt >= 0) Then
         t = (-CoefB-Math.SquareRoot(CoefB*CoefB-4*CoefA*CoefC))/(2*CoefA)
       Else
         t = (-CoefB+Math.SquareRoot(CoefB*CoefB-4*CoefA*CoefC))/(2*CoefA)
       EndIf
     EndIF
     xi = xi+t*ui
     yi = yi+t*vi
     xj = xj+t*uj
     yj = yj+t*vj
     'Centre of momentum coordinates
     mx = (ui+uj)/2
     my = (vi+vj)/2
     ui = ui-mx
     vi = vi-my
     uj = uj-mx
     vj = vj-my
     'New centre to centre line
     dx = xi-xj
     dy = yi-yj
     dist = Math.SquareRoot(dx*dx+dy*dy)
     dx = dx/dist
     dy = dy/dist
     'Reflect balls velocity vectors in centre to centre line
     OB = -(dx*ui+dy*vi)
     ui = ui+2*OB*dx
     vi = vi+2*OB*dy
     OB = -(dx*uj+dy*vj)
     uj = uj+2*OB*dx
     vj = vj+2*OB*dy
     'Back to moving coordinates with elastic velocity change
     e = Math.SquareRoot(elastic)
     ui = e*(ui+mx)
     vi = e*(vi+my)
     uj = e*(uj+mx)
     vj = e*(vj+my)
     'Move to new bounced position
     xi = xi-t*ui
     yi = yi-t*vi
     xj = xj-t*uj
     yj = yj-t*vj
     'Set velocities
     Xvel[i] = ui
     Yvel[i] = vi
     Xvel[j] = uj
     Yvel[j] = vj
     'Set position
     Xpos[j] = xj
     Ypos[j] = yj
     x = xi
     y = yi
   EndIf
 EndFor
EndSub
'Gravity and friction and follow mouse
Sub gravity
 xm = GraphicsWindow.MouseX-x
 ym = GraphicsWindow.MouseY-y
 dist = xm*xm+ym*ym
 dist = Math.Max(dist,radius*radius)
 'dist = dist*Math.SquareRoot(dist)
 u = Xvel[i]
 v = Yvel[i]
 fricscale = (1-fric/Math.SquareRoot(1+u*u+v*v))
 Xvel[i] = follow*xm/dist+fricscale*u
 Yvel[i] = follow*ym/dist+fricscale*v+grav
EndSub
'Attract-repell balls to each other
Sub attraction
 If (attract <> 0) Then
   For j = i+1 To nball
     xm = Xpos[j]-x
     ym = Ypos[j]-y
     dist = xm*xm+ym*ym
     dist = Math.Max(dist,radius*radius)
     'dist = dist*Math.SquareRoot(dist)
     Xvel[i] = attract*xm/dist+Xvel[i]
     Yvel[i] = attract*ym/dist+Yvel[i]
     Xvel[j] = attract*xm/dist+Xvel[j]
     Yvel[j] = -attract*ym/dist+Yvel[j]
   EndFor
 EndIf
EndSub
'Move ball
Sub move
 ball = balls[i]
 Shapes.Move(ball,x-radius,y-radius)
EndSub
'Update options display
Sub options
 GraphicsWindow.PenColor = "Black"
 GraphicsWindow.DrawLine(gw,0,gw,gh)
 GraphicsWindow.BrushColor = "LightBlue"
 GraphicsWindow.FillRectangle(gw+10,10,190,gh-20)
 For i = 0 To 5
   GraphicsWindow.DrawLine(gw+10,100*i+10,gw+190,100*i+10)
 EndFor
 GraphicsWindow.DrawLine(gw+100,10,gw+100,510)
 GraphicsWindow.BrushColor = "Black"
 GraphicsWindow.DrawBoundText(gw+15,20,70,"Gravity")
 GraphicsWindow.DrawBoundText(gw+15,40,70,grav)
 GraphicsWindow.DrawBoundText(gw+15,120,70,"Friction")
 GraphicsWindow.DrawBoundText(gw+15,140,70,fric)
 GraphicsWindow.DrawBoundText(gw+15,220,70,"Follow")
 GraphicsWindow.DrawBoundText(gw+15,240,70,follow)
 GraphicsWindow.DrawBoundText(gw+15,320,70,"Size")
 GraphicsWindow.DrawBoundText(gw+15,340,70,radius)
 GraphicsWindow.DrawBoundText(gw+15,420,70,"Count")
 GraphicsWindow.DrawBoundText(gw+15,440,70,nball)
 GraphicsWindow.DrawBoundText(gw+15,520,170,"Click coloured options or a ball to stop it")
 GraphicsWindow.BrushColor = "Red"
 GraphicsWindow.DrawBoundText(gw+15,580,50,"RESET")
 GraphicsWindow.DrawBoundText(gw+115,580,50,"QUIT")
 GraphicsWindow.DrawBoundText(gw+15,60,70,"More")
 GraphicsWindow.DrawBoundText(gw+15,160,70,"More")
 GraphicsWindow.DrawBoundText(gw+15,260,70,"More")
 GraphicsWindow.DrawBoundText(gw+15,360,70,"More")
 GraphicsWindow.DrawBoundText(gw+15,460,70,"More")
 GraphicsWindow.BrushColor = "Blue"
 GraphicsWindow.DrawBoundText(gw+15,80,70,"Less")
 GraphicsWindow.DrawBoundText(gw+15,180,70,"Less")
 GraphicsWindow.DrawBoundText(gw+15,280,70,"Less")
 GraphicsWindow.DrawBoundText(gw+15,380,70,"Less")
 GraphicsWindow.DrawBoundText(gw+15,480,70,"Less")
 GraphicsWindow.BrushColor = "Black"
 GraphicsWindow.DrawBoundText(gw+115,20,70,"Speed")
 GraphicsWindow.DrawBoundText(gw+115,40,70,dt)
 GraphicsWindow.DrawBoundText(gw+115,120,70,"Attraction")
 GraphicsWindow.DrawBoundText(gw+115,140,70,attract)
 GraphicsWindow.DrawBoundText(gw+115,220,70,"Elastic")
 GraphicsWindow.DrawBoundText(gw+115,240,70,elastic)
 GraphicsWindow.DrawBoundText(gw+115,320,70,"Colour")
 GraphicsWindow.BrushColor = "Red"
 GraphicsWindow.DrawBoundText(gw+115,60,70,"More")
 GraphicsWindow.DrawBoundText(gw+115,160,70,"More")
 GraphicsWindow.DrawBoundText(gw+115,260,70,"More")
 GraphicsWindow.BrushColor = "Blue"
 GraphicsWindow.DrawBoundText(gw+115,80,70,"Less")
 GraphicsWindow.DrawBoundText(gw+115,180,70,"Less")
 GraphicsWindow.DrawBoundText(gw+115,280,70,"Less")
 GraphicsWindow.BrushColor = "Red"
 GraphicsWindow.DrawBoundText(gw+115,340,70,"Red")
 GraphicsWindow.BrushColor = "Blue"
 GraphicsWindow.DrawBoundText(gw+115,360,70,"Blue")
 GraphicsWindow.BrushColor = "Yellow"
 GraphicsWindow.DrawBoundText(gw+115,380,70,"Yellow")
 GraphicsWindow.BrushColor = "Black"
 GraphicsWindow.DrawBoundText(gw+115,420,70,"Shape")
 GraphicsWindow.BrushColor = "Red"
 GraphicsWindow.DrawBoundText(gw+115,440,70,"Circle")
 GraphicsWindow.DrawBoundText(gw+115,460,70,"Square")
EndSub
'Change settings
Sub OnMouseDown
 xm = GraphicsWindow.MouseX
 ym = GraphicsWindow.MouseY
 'Left column settings
 If (xm > gw+15 And xm < gw+85) Then
   If (ym > 60 And ym < 75) Then
     grav = grav+0.01
   EndIf
   If (ym > 80 And ym < 95) Then
     grav = grav-0.01
   EndIf
   If (ym > 160 And ym < 175) Then
     fric = fric+0.001
   EndIf
   If (ym > 180 And ym < 195) Then
     fric = fric-0.001
   EndIf
   If (ym > 260 And ym < 275) Then
     follow = follow+1
   EndIf
   If (ym > 280 And ym < 295) Then
     follow = follow-1
   EndIf
   If (ym > 360 And ym < 375) Then
     radius = radius+1
     diam = 2*radius
     ireset = "True"
   EndIf
   If (ym > 380 And ym < 395) Then
     radius = radius-1
     radius = Math.Max(1,radius)
     diam = 2*radius
     ireset = "True"
   EndIf
   If (ym > 460 And ym < 475) Then
     nball = nball+1
     ireset = "True"
   EndIf
   If (ym > 480 And ym < 495) Then
     nball = nball-1
     nball = Math.Max(1,nball)
     ireset = "True"
   EndIf
   If (ym > 580 And ym < 595) Then
     istart = "True"
   EndIf
 EndIf
 'Right column settings
 If (xm > gw+115 And xm < gw+185) Then
   If (ym > 60 And ym < 75) Then
     dt = dt+0.1
   EndIf
   If (ym > 80 And ym < 95) Then
     dt = dt-0.1
   EndIf
   If (ym > 160 And ym < 175) Then
     attract = attract+1
   EndIf
   If (ym > 180 And ym < 195) Then
     attract = attract-1
   EndIf
   If (ym > 260 And ym < 275) Then
     elastic = elastic+0.01
   EndIf
   If (ym > 280 And ym < 295) Then
     elastic = elastic-0.01
   EndIf
   If (ym > 340 And ym < 355) Then
     Colour = "Red"
     ireset = "True"
   EndIf
   If (ym > 360 And ym < 375) Then
     Colour = "Blue"
     ireset = "True"
   EndIf
   If (ym > 380 And ym < 395) Then
     Colour = "Yellow"
     ireset = "True"
   EndIf
   If (ym > 440 And ym < 455) Then
     Shape = 0
     ireset = "True"
   EndIf
   If (ym > 460 And ym < 475) Then
     Shape = 1
     ireset = "True"
   EndIf
   If (ym > 580 And ym < 595) Then
     iend = "True"
   EndIf
 EndIf
 'Select a ball
 If (xm < gw) Then
   iselect = "True"
 EndIf
 ioptions = "True"
EndSub
'Reset new balls
Sub reset
 mball = Array.GetItemCount(balls)
 For i = 1 To mball
   balls[i] = ""
   If (istart Or i > nball) Then
     Xpos[i] = ""
     Ypos[i] = ""
     Xvel[i] = ""
     Yvel[i] = ""
   EndIf
 EndFor
 GraphicsWindow.Clear()
 options()
 GraphicsWindow.BrushColor = Colour
 For i = 1 To nball
   If (shape = 0) Then
     ball = Shapes.AddEllipse(diam,diam)
   EndIf
   If (shape = 1) Then
     ball = Shapes.AddRectangle(diam,diam)
   EndIf
   balls[i] = ball
   If (istart Or i > mball) Then
     x = Math.GetRandomNumber(gw)
     y = Math.GetRandomNumber(gh)
     u = Math.GetRandomNumber(500)/100-3
     v = Math.GetRandomNumber(500)/100-3
     Xpos[i] = x
     Ypos[i] = y
     Xvel[i] = u
     Yvel[i] = v
   EndIf
 EndFor
EndSub

this does work please leave a comment!!!


Comments


Share: