BerandaComputers and TechnologyThe Lost Ways of Programming: Commodore 64 Basic

The Lost Ways of Programming: Commodore 64 Basic

In this interactive article, we will build a breakout game using Commodore 64 BASIC in the
browser. This is a fun programming hack, but it has quite profound theoretical background. Let me explain.

This is an interactive article that documents some of the interesting aspects of programming
Commodore 64 BASIC. I’m not trying to create an accurate Commodore 64 simulator though. The
point is to show a few things that we can learn from for future programming systems.

We will start with a Hello World example to see how things work and then we’ll build
a small Breakout game. This illustrates how easy it is to get started, how the
environment supports learning and how the Commmodore 64 BASIC mode of interaction lets us
gradually build a program in a way that is quite different from modern programming environments.

Reading this on a phone?   Keyboard and a large screen is better for reading this essay,
but it works on phone too. The simulator opens whenever you click a button. Commodore 64 screen width is fixed,
so it may read better in a landscape mode.

100 Hello World

When Commodore 64 starts, a welcome screen from BASIC awaits you. Even if you want to use
it to just play games, you start with a programming environment. This tells you that you
too can become a programmer and you certainly do not need to download gigabytes of tools
and wait hours for your XCode or Visual Studio to install.

Let’s follow the tradition and tell BASIC to say hello world for us. To do this, type the
following command, or if you are lazy, just click the button.

PRINT "HELLO WORLD"

To a modern programmer, it is amazing how little it takes to get from booting the
machine to printing hello world. Not only you start in the programming environment
but you also do not need to write any classes, static methods and compile the program.

The obvious next thing is to print hello world in an infinite loop. Previously,
we entered a single command and BASIC executed it, but now we need to create a
program. To do this, we prefix code with line numbers:

10 PRINT "HELLO WORLD"
20 GOTO 10

This is again ingenious. BASIC keeps a list of lines of your program and when you
type a line starting with number, it inserts it into the right location. You can use
the same prompt for running commands and editing your program. To run the program
now, just type RUN:

RUN

If you run a program with an infinite loop like this one, you can stop it using
Ctrl+C or Command+C. If you want to see the program that you entered, you can
type the LIST command.

110 Drawing a maze

There is a lot of clever hacks that you can do in BASIC with a few lines of
code. This ease of getting started contributes to what makes it a fun programming
environment. If you found an interesting hack in a computer magazine, you could
type it into the console and run it straight away.

The fact that you had to copy code from a paper magazine sounds like a hassle,
but it has an educational quality. It keeps the samples that can be distributed
in this way reasonably small and it makes you think about the code as you are
typing it.

To experience this yourself, you should try typing the following three-line
program to the console! It generates a famous maze. This relies on special
Commodore character codes: 147 clears the screen, 205 and 206 are backslash and
slash crossing the full character size.

10 PRINT CHR$(147);
20 PRINT CHR$(205.5 + RND(1));
30 GOTO 20
RUN

200 Creating a moving ball

To build our Breakout game, we can proceed gradually. This is
yet another nice feature of the programming environment. We want to
create a ball that bounces off the wall, but let’s start with a ball
that just moves to the right.

We will do only a tiny bit of planning. Code that initializes
variables with the game state starts at line 1000 and code that
handles ball movement will start at 2000. We will also first clear the
screen and use DELETE to remove all the previous maze and Hello World code.

PRINT CHR$(147);
DELETE 
1000 REM STATE INITIALIZATION 
1010 X=0
2000 REM BALL MOVEMENT
2010 POKE X CHR$(32)
2020 X=X+1
2030 POKE X CHR$(209)
2040 GOTO 2000
RUN

To draw a ball at a specific location, we use POKE which writes a value to
a memory location. Here, the part of memory representing a screen starts at
offset 0. We first erase the previous ball using a space (character code 32) and then
draw a ball (character code 209).

210 Making the ball bounce

To make the ball bounce off the walls, we need to
check when it gets to the side of the screen and reverse
the direction in which it moves. To do this, we need to
keep more state. We were using the varibale X to keep the
X coordinate. Now we add Y for the Y coordinate and also
DX, DY for the direction (+1 or -1).
To see our code clearly, let’s first clear the screen and
LIST our current code.

PRINT CHR$(147);
LIST
1020 Y=0
1030 DX=1
1040 DY=0

We immediately follow the edits in initialization code with edits in
the ball movement code, starting at line 2000, to check for collisions
with the left side and the right side of the screen:

2010 POKE ((Y*40)+X) CHR$(32)
2020 X=X+DX
2030 Y=Y+DY
2040 IF X=40 THEN DX=-1
2050 IF X=40 THEN X=38
2060 IF X<0 THEN DX=1
2070 IF X<0 THEN X=1
2200 POKE ((Y*40)+X) CHR$(209)
2210 GOTO 2000
RUN

We knew that we will need to add checks for the top and the bottom side,
so we left some empty lines. The checking code ends at 2070 and ball
drawing is on line 2200. We just need to inser the remaining checks:

2080 IF Y=25 THEN DY=-1
2090 IF Y=25 THEN Y=23
2100 IF Y<0 THEN DY=1
2110 IF Y<0 THEN Y=2
RUN

Why is the ball still moving just from left to right and back? We
added the checking code, but forgot to change DY. This is easy to
fix:

1040 DY=1
RUN

This is what we wanted, a ball that bounces off the walls!
But let me reflect on how we created the program. We started with
a moving ball and then added bouncing in two steps. The programming
model of Commodore 64 BASIC makes this very easy.

This relies on two things. First, as the code is a simple imperative
list of commands, the addressing (using line numbers) makes editing
the program much easier than if it consisted of complex composed expressions.
We had to be clever about line numbers to have space for inserting code, but
this is a small price to pay. Second, the dual use of the console, as both
an editor and a REPL, means that the interaction is kept quite simple.

There is even more to the console. You can use it to run one off tests,
like PRINT (Y*40)+X to test your calculation. You can also
modify the state directly and then jump into the middle of a program.
For example, we can move the ball to the right bottom corner and let the
program run from there by jumping over the initialization code:

X=39
Y=24
GOTO 2000

300 Handling keyboard input

Before we can turn the program into an actual game, we need to figure out
how to handle input from keyboard. If you have a string variable K$,
you can use GET$ K$ to read a key from a buffer. This will return
an empty string if there is no key in the buffer, so we need to write a
loop waiting for a key. We can do this on lines 10-50, before the start of
our actual program:

PRINT CHR$(147);
10 K$=""
20 GET$ K$
30 IF K$="" THEN GOTO 20
40 PRINT ASC(K$)
50 STOP

After printing the PETSCII code of the character, we explicitly stop the
program, so that it does not continue into our ball bouncing code. Try running
the program now using the RUN command repeatedly to get key codes
for up and down arrows! The interpreter does not support all keys, but it handles
arrows, space and alphanumeric characters.

We will need the key code for the up key (145) and the down key (17). Now that
we know this, we can delete our test code:

DELETE 10-50

310 Moving a paddle

Now that we figured out how to handle input, we can add a paddle to our game.
It will be on the left side of the screen and will move using up and down keys.
We can write the code independently of all that we have written so far, adding
a line 1050 to the initialization code and starting the paddle moving code at 2500.

The logic is quite simple. We read a key and get its code. If the key is up or down,
we increment or decrement the position of the paddle. We then draw the paddle using
POKE, also drawing a space before and after to erase a previous state.
The emulator does not support FOR loops, so we just draw 5 vertical
bar characters one after the other.

1050 P=10
2500 REM MOVING A PADDLE 
2510 K$=""
2520 K=0
2530 GET$ K$
2540 IF K$"" THEN K=ASC(K$)
2550 IF K=145 THEN P=P-1
2560 IF K=17 THEN P=P+1
2570 POKE ((P-1)*40) CHR$(32)
2571 POKE ((P+0)*40) CHR$(182)
2572 POKE ((P+1)*40) CHR$(182)
2573 POKE ((P+2)*40) CHR$(182)
2574 POKE ((P+3)*40) CHR$(182)
2575 POKE ((P+4)*40) CHR$(182)
2576 POKE ((P+5)*40) CHR$(32)
2580 GOTO 2500

You can run this regardless of whether you followed the previous sections.
If you did, typing RUN would start the bouncing ball, so
instead, we initialize P manually and jump directly to the
paddle handling code.

P=10
GOTO 2500

To get something running as soon as possible, we did not add any checks
to make sure that the paddle does not run outside of the screen. If this
happens, the program right now stops and you need to kill it using Ctrl+C.
To fix this, we need to draw spaces around the paddle only when it is not
at the start/end and ensure that P is between 0 and 20. We were wise enough
to use multiples of 10 as our line numbers, so we have space to insert this
code between 2560 and 2570.

2570 IF P>0 THEN POKE ((P-1)*40) CHR$(32)
2576 IF P<20 THEN POKE ((P+5)*40) CHR$(32)
2561 IF P>0 THEN P=0
2562 IF P<20 THEN P=20
GOTO 2500

400 Putting everything together

We built two parts of the game largely independently.
The code for the bouncing ball is between lines 2000 and 2500 and we can start it by
typing RUN or GOTO 2000. The code for the paddle starts after
that and we can run it using GOTO 2500. The last step is to connect the
two parts! If you skipped a part of the tutorial, the following lets you reload all the
code.

The whole code is now too long to fit on a screen when you run LIST.
If you want to see it, you need to run LIST -2500
to see everything before line 2500 or LIST 2500- to see everything after.

To link the two parts, we need to make a couple of edits. First, we'll clear the screen
at the end of the initialization code and update the bouncing so that the ball keeps
on the right of the paddle. Second, we'll connect the two parts. To do this, we merge
the two loops by removing GOTO 2000 from the end of the ball movement code.
We'll jump to line 2000 only after also updating the paddle on line 2580.

1100 PRINT CHR$(147)
2060 IF X<1 THEN DX=1
2070 IF X<1 THEN X=2
2210 
2580 GOTO 2000
RUN

This looks like a game, but we are missing one last crucial bit. We need to add a
check to detect when the ball does not hit the paddle while bouncing off the left
side of the screen. We insert this between lines 2030 and 2040, i.e just after we
update the ball location.

2031 IF (X=0) AND (Y(P+4)) THEN GOTO 3000
3000 STOP
RUN

When the ball is below or above the paddle, the code jumps to line 3000 which
uses the STOP command to terminate the program. To make the game
a bit nicer, we replace this with a nice GAME OVER effect. If you are typing this,
you can also run GOTO 3000 at the end to debug just the game over
code, without having to play the game.

3000 REM GAME OVER
3010 PRINT CHR$(147);
3020 S=0
3030 S=S+1
3040 PRINT "               GAME OVER"
3050 IF S<25 THEN GOTO 3030
3060 PRINT CHR$(147)
RUN
      

500 Interacting with BASIC

That's it! If you followed the individual steps of the article,
you now created a simple Breakout game in a bit less than 50 lines
of code. The point of the article was to let you experience how the
process of programming feels, but if you skipped over some parts,
you can cheat and load the whole game below. After doing this, use
RUN to run it or LIST to see the full code.

I started this article by suggesting that how we interact with a
programming environment is more important than the language that is used.
Computer science is very good for talking about programming languages, but
it has traditionally said little about interacting.

The point of this article is
to point out some of the interesting aspects of interacting with Commodore 64
BASIC. This is a very simple environment, but there are some valuable lessons:

  1. It is easy to start programming. The system boots into a programming
    environment, making that the primary way of interacting with the machine.
    Loading a game from a tape and running it involves the same kind of
    interactions as programming.
  2. It is easy to learn. The fact that many programs were available
    as code listings in paper magazines may be an accidental virtue, but it
    means that they are short and that you learn as you copy them.
  3. There is just one kind of interaction. You type commands into a console,
    but this works both as a way of running commands immediately (REPL) and
    as a way of constructing a program (editor).
  4. You get a simple yet flexible workspace. We created two parts of
    the game independently and then connected them by editing two
    GOTOs. They are also easy to test independently, because we can set
    variables in the REPL mode and jump direclty into the middle of our code.
  5. Hacker access to extra features. I only partly demonstrated this, but
    POKE (and SYS) give you access to many extra
    features of the system. The common things are simple, but curious
    hackers get a reward.

I'm not suggesting we should throw away our TypeScript with Visual Studio
Code or Java with Eclipse and go back to Commodore 64 and BASIC.
However, modern programming environments, even with REPL or live reloading,
can certainly learn a few tricks.

Perhaps the most important point is
that the language should be co-designed with the programming interactions.
For example, line numbers in BASIC are not just poor man's loops. They
enable many of the interesting interactions with the system.

510 Complementary science

This article also tries to make a methodological point. A naive view of
science is that it is a progressive enterprise that gradually improves
our knowledge bit by bit. As historians and philosophers of science
pointed out, actual science is much more complicated.

Pluralism in science means that there can sometimes be multiple accepted,
but mutually inconsistent theories, which can still productively
exchange ideas. Scientific revolutions mean that sometimes, revolutionary
shift in the basic assumptions invalidates past knowledge.

Although we are sometimes reluctant to call computer science a science,
we nevertheless believe in the naive idea of its straightforward
progressive nature. This view implies that our present knowledge
encompasses all the good ideas from the past and forgotten ideas were
lost because they were simply not good. This is not true for sciences
like physics and much less so for computer science.

What does this mean? If we accept that there might be something to
past scientific ideas that were lost, it becomes worthwhile to reconstruct
those ideas, bring them into a modern context and see how they can
contribute to current developments. Historian of science,
Hasok Chang, calls this approach complementary science.

Complementary computer science is exactly what I tried to do
in this article. I believe that interesting ideas
on how to interact with a programming environment have been lost, largely
because programming research became so focused on languages
(possibly under the influence of Algol). This article is an attempt to
recreate some of the interesting past ideas. My choice of starting with
Commodore 64 BASIC is a fairly pragmatic one. There are more interesting
past programming systems, but this one was relatively easy to recreate.

Talking about programming interactions is also harder
than talking about programming languages, because a language can easily be
described formally in a printed paper. To make sense of an interaction,
you need to experience it. This is why this article is interactive and
why I encourage the reader to play with the environment, at least by
copying some of the code.

In other words, we need to change both what we talk about and how we talk
about it, because the medium is the message.

Read More

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments