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.
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