One simply cannot escape the incessant chatter about LLM systems – or "AI" as they've rather annoyingly been dubbed, much to the chagrin of anyone with a modicum of precision in their vocabulary. Among the many dubious delights these contraptions have unleashed upon the world is the trendy notion of "vibe coding." This, my dear readers, is where one leans almost entirely upon these digital oracles to churn out lines of code, all through a most drawn-out and conversational tête-à-tête. It’s akin to asking a particularly chatty parrot to build a cuckoo clock; one might eventually get something resembling a timepiece, but it's bound to involve rather a lot of squawking and very little precision.
Now, if you'll permit an old chap to don his cranky old man hat for a moment, I must confess it all strikes me as rather frustrating. Lest you mistake me for some sort of retro-sycophant who scoffs at modern conveniences, let me assure you, I've been dabbling in the delightful world of software for over thirty years. I’ve seen more tools come and go than you've had hot dinners, many of which were once the very height of cool and have since vanished into the digital ether, much like a fleeting fashion trend. Indeed, I've even dabbled with these so-called AI systems myself, and I find they do rather well as a supercharged search engine for documentation, or perhaps as a digital "rubber duck" to bounce ideas off and sketch out a rudimentary outline. Any actual code they spit out rarely works straight off the bat, mind you, but it occasionally sparks a novel idea or unearths some obscure nugget of wisdom I hadn't yet stumbled upon. After all, the complexities of today's technology are such that finding the precise needle in the documentation haystack can be a Herculean task.
But here’s a thought, a rather mischievous one at that: how does this "vibe coding" charade fare with something far, far simpler? I speak, of course, of the very simplest programming language of them all: BASIC.
My suspicion, dear friends, is that this might prove a tad trickier than one might initially imagine. Firstly, the heyday of BASIC rather predates the internet, meaning there's a decided paucity of code for these LLMs to digest. Many of the online tomes and technical manuals for retro BASIC are often little more than scanned copies, rendering them rather indigestible for our digital chums. Furthermore, BASIC isn't a singular entity; it's more of an umbrella term for a veritable family of languages, all sharing the same general "vibe" (if you'll pardon the modern parlance), yet often boasting wildly divergent commands and capabilities. Some of these, bless their cotton socks, rely rather heavily on PEEKs and POKEs to truly exploit their system's peculiarities, and these ancient forms of API calls are, predictably, poorly documented online.
So, this promised to be an intriguing challenge. To add a delightful dash of complexity, I decided to enlist Atari BASIC rather than a more ubiquitous Microsoft variant, such as AppleSoft. Why, you ask? Well, this is an Atari newsletter, and I happen to possess rather a lot of Atari kit to hand for testing. Alas, my Apple II-era systems are, for reasons best left unsaid, rather conspicuous by their absence.
For the sake of convenience, I shall be employing the Atari800MacX emulator, which, happily, makes pasting in the generated code an absolute doddle.
With that rather lengthy preamble out of the way, the burning question remains: which of these LLM AI systems should we unleash upon our unsuspecting BASIC? Given that ChatGPT is the most commonly known and familiar, it seemed only sporting to enlist it for this little experiment, though I must acknowledge that Anthropic Claude is also rather adept at the coding caper.
To ensure a proper "vibe coding" experience, I vowed to resist the urge to correct the generated code or, indeed, to enlighten the AI as to the precise nature of its blunders. One must suffer for one's art, after all.
So, what's first on the agenda? A quintessential inaugural BASIC program, the venerable precursor to "Hello World," seemed an appropriate starting point.
Prompt: Please write me a simple program in Atari BASIC that repeatedly prints “Hello, World” to the screen.
ChatGPT's triumphant retort:
10 PRINT "Hello, World"
20 GOTO 10
One must concede, ChatGPT aced this exceedingly simple test. And I have to say, there's a certain nostalgic charm in beholding a "GOTO 10" in the wild!
Atari BASIC, rather disappointingly, lacks a built-in command for drawing circles, which presented a splendid opportunity for our AI chum to shine.
Prompt: Write me an Atari BASIC program that draws a blue circle in graphics mode 7.
ChatGPT's initial attempt:
10 GRAPHICS 7
20 COLOR 1
30 FOR ANGLE=0 TO 360 STEP 5
40 X=80+30*COS(ANGLE*3.14159/180)
50 Y=48+30*SIN(ANGLE*3.14159/180)
60 PLOT X,Y
70 NEXT ANGLE
80 GOTO 80
So far, the vibes were indeed flowing rather splendidly. This program, bless its digital heart, ran perfectly, albeit producing a somewhat rough, dotted circle. One might even describe it as "rustic."
Naturally, I then requested a solid outline instead of a dotted one, and it promptly returned with this:
10 GRAPHICS 7
20 COLOR 1
30 X=80:Y=48:R=30
40 A=0
50 X1=X+R*COS(A)
60 Y1=Y+R*SIN(A)
70 FOR A=0 TO 6.28 STEP .05
80 X2=X+R*COS(A)
90 Y2=Y+R*SIN(A)
100 DRAWTO X2,Y2
110 X1=X2:Y1=Y2
120 NEXT A
130 GOTO 130
This did draw a solid outline using DRAWTO, which was a step in the right direction, but alas, it rather missed the mark on setting the initial position correctly. A minor oversight, perhaps, but enough to spoil the aesthetic.
Happily, it proved capable of rectifying its error:
The revised code:
10 GRAPHICS 7
20 COLOR 1
30 X=80:Y=48:R=30
40 REM Start drawing from the correct point
50 X1=X+R*COS(0)
60 Y1=Y+R*SIN(0)
70 PLOT X1,Y1
80 FOR A=0 TO 6.28 STEP .05
90 X2=X+R*COS(A)
100 Y2=Y+R*SIN(A)
110 DRAWTO X2,Y2
120 NEXT A
130 GOTO 130
This new code, I'm delighted to report, drew the circle correctly. Splendid!
I then, with a touch of daring, asked it to banish the rather unsightly blue bar at the bottom of the screen, a task it accomplished admirably by employing GRAPHICS 7+16. All in all, a rather successful graphical endeavour!
Continuing our foray into the visual arts, I decided to elevate the challenge. Atari BASIC, rather conveniently, possesses built-in commands for drawing lines and even for accessing the joystick – more than enough, one would think, to fashion a rudimentary drawing program.
Prompt: Write an Atari BASIC program that lets you draw on the screen using a joystick. It should use graphics mode 7 and allow you to rotate between colors by pressing the fire button.
ChatGPT's initial, somewhat flawed, masterpiece:
10 GRAPHICS 7+16
20 X=80:Y=48
30 COLOR=1 ; Initial color
40 POKE 77,0
50 REM === MAIN LOOP ===
60 ST=STICK(0)
70 BT=STRIG(0)
80 IF ST=11 THEN Y=Y-1 ; Up
90 IF ST=7 THEN Y=Y+1 ; Down
100 IF ST=13 THEN X=X-1 ; Left
110 IF ST=14 THEN X=X+1 ; Right
120 IF X<0 THEN X=0
130 IF X>159 THEN X=159
140 IF Y<0 THEN Y=0
150 IF Y>95 THEN Y=95
160 IF BT=0 THEN GOSUB 200
170 COLOR COLOR
180 PLOT X,Y
190 GOTO 60
200 REM === CYCLE COLORS ===
210 COLOR=COLOR+1
220 IF COLOR>3 THEN COLOR=1
230 FOR D=1 TO 20:NEXT D
240 RETURN
END IF
Alas, this attempt was riddled with more errors than a politician's promise. Using COLOR as a variable name requires a LET statement, and the semi-colon (;) for comments is, frankly, an abomination in any BASIC dialect I've ever encountered.
Prompt: Line 30 shows this error: ERROR- COLOR=1. There are also errors on any lines that use ";" for a comment.
It responded by, quite sensibly, changing COLOR to a more amenable C and, thankfully, jettisoning most of the errant semi-colon comments:
10 GRAPHICS 7+16
20 X=80:Y=48
30 C=1
40 POKE 77,0
50 REM === MAIN LOOP ===
60 ST=STICK(0)
70 BT=STRIG(0)
80 IF ST=11 THEN Y=Y-1
90 IF ST=7 THEN Y=Y+1
100 IF ST=13 THEN X=X-1
110 IF ST=14 THEN X=X+1
120 IF X<0 THEN X=0
130 IF X>159 THEN X=159
140 IF Y<0 THEN Y=0
150 IF Y>95 THEN Y=95
160 IF BT=0 THEN GOSUB 200
170 COLOR C
180 PLOT X,Y
190 GOTO 60
200 REM === CYCLE COLORS ===
210 C=C+1
220 IF C>3 THEN C=1
230 FOR D=1 TO 20:NEXT D
240 RETURN
This code, I'm pleased to report, ran without any immediate complaints. However, it quickly became apparent that the joystick directions were, shall we say, rather confused. Up drew right, down drew left, and so on. A minor inconvenience, but one that demanded rectification.
After enlightening it about the joystick's navigational woes, it gallantly presented this revised code:
10 GRAPHICS 7+16
20 X=80:Y=48
30 C=1
40 POKE 77,0
50 REM === MAIN LOOP ===
60 ST=STICK(0)
70 BT=STRIG(0)
80 IF ST=14 OR ST=10 OR ST=6 THEN Y=Y-1 : REM UP
90 IF ST=13 OR ST=9 OR ST=5 THEN Y=Y+1 : REM DOWN
100 IF ST=11 OR ST=10 OR ST=9 THEN X=X-1 : REM LEFT
110 IF ST=7 OR ST=6 OR ST=5 THEN X=X+1 : REM RIGHT
120 IF X<0 THEN X=0
130 IF X>159 THEN X=159
140 IF Y<0 THEN Y=0
150 IF Y>95 THEN Y=95
160 IF BT=0 THEN GOSUB 200
170 COLOR C
180 PLOT X,Y
190 GOTO 60
200 REM === CYCLE COLORS ===
210 C=C+1
220 IF C>3 THEN C=1
230 FOR D=1 TO 20:NEXT D
240 RETURN
The resulting program now works perfectly, though I do suspect line 40 is rather superfluous. Still, one can't be too picky, can one?
Now, for a spot of entertainment! How about a simple game? Using sprites (or player/missiles, as they were rather quaintly called) in Atari BASIC typically requires a machine language subroutine, which is, frankly, beyond the scope of a mere "vibe coding" exercise. However, other games often employ a redefined character set, which only requires a smattering of PEEKs and POKEs. It seemed a reasonable challenge to ask ChatGPT to concoct a rudimentary version of Space Invaders using this method. Given the game's iconic status, I held out hope that I wouldn't need to provide a deluge of prompts.
Prompt: Create a simple version of Space Invaders using Atari BASIC. Use a large text graphics mode with a redefined character set for the aliens, spaceship and missiles. The player’s ship should be controlled with the joystick.
ChatGPT's initial, rather simplistic, offering:
10 GOSUB 1000 :REM Setup custom characters
20 GRAPHICS 0
30 POKE 77,0 :REM Disable cursor
40 DIM AL$(5)
50 FOR I=0 TO 4:AL$(I)="A":NEXT I
60 FOR I=0 TO 4:POKE 752+I*2,ASC(AL$(I)):NEXT I
70 SHIPX=20 :MISSILE=0 :MX=0 :MY=0 :C=0
80 FOR I=5 TO 35 STEP 6
90 POSITION I,5 :PRINT "A"; :NEXT I
100 REM === MAIN LOOP ===
110 ST=STICK(0) :BT=STRIG(0)
120 IF ST=11 AND SHIPX>0 THEN SHIPX=SHIPX-1
130 IF ST=7 AND SHIPX<38 THEN SHIPX=SHIPX+1
140 POSITION 0,22 :PRINT " "
150 POSITION SHIPX,22 :PRINT "S";
160 IF MISSILE=0 AND BT=0 THEN MISSILE=1 :MX=SHIPX :MY=21
170 IF MISSILE=1 THEN
180 POSITION MX,MY :PRINT "|";
190 FOR T=1 TO 100:NEXT T
200 POSITION MX,MY :PRINT " ";
210 MY=MY-1
220 IF MY<0 THEN MISSILE=0:GOTO 240
230 POSITION MX,MY :IF PEEK(PEEK(88)+MX+MY*40)=ASC("A") THEN POSITION MX,MY:PRINT " ";:MISSILE=0
240 END IF
250 GOTO 100
1000 REM === CUSTOM CHARACTER SET ===
1010 CHB=57344 :REM RAM for new charset
1020 FOR I=0 TO 1023
1030 POKE CHB+I,PEEK( CHB+I ) :REM Copy original
1040 NEXT I
1050 POKE 756,CHB/2048 :REM Point to new set
1060 RETURN
Ah, a classic case of presumption! The use of MISSILE as a variable name caused a syntax error, as did the rather brazen employment of END IF. One would think these digital prodigies would have a firmer grasp of BASIC's rather particular syntax.
After I gently pointed out these peccadillos, it returned with this:
10 GRAPHICS 0
20 POKE 77,0 :REM Disable cursor
30 DIM AL$(5)
40 SHIPX=20 :FIRE=0 :MX=0 :MY=0
50 FOR I=5 TO 35 STEP 6
60 POSITION I,5 :PRINT "A"; :NEXT I
100 REM === MAIN LOOP ===
110 ST=STICK(0) :BT=STRIG(0)
120 IF ST=11 AND SHIPX>0 THEN SHIPX=SHIPX-1
130 IF ST=7 AND SHIPX<38 THEN SHIPX=SHIPX+1
140 POSITION 0,22 :PRINT " "
150 POSITION SHIPX,22 :PRINT "S";
160 IF FIRE=0 AND BT=0 THEN FIRE=1 :MX=SHIPX :MY=21
170 IF FIRE=1 THEN GOSUB 300
180 GOTO 100
300 REM === MOVE MISSILE ===
310 POSITION MX,MY :PRINT "|";
320 FOR T=1 TO 75:NEXT T
330 POSITION MX,MY :PRINT " ";
340 MY=MY-1
350 IF MY<0 THEN FIRE=0 :RETURN
360 POSITION MX,MY
370 IF PEEK(PEEK(88)+MX+MY*40)=ASC("A") THEN POSITION MX,MY :PRINT " " :FIRE=0 :RETURN
380 RETURN
This code, rather miraculously, ran without any immediate errors. However, its functionality was, to put it mildly, rather lacking. There was more flicker than a disco ball, and the aliens had an unfortunate habit of scrolling off the top of the screen. Moving the ship and firing did work, though, so a small victory, perhaps.
I then suggested it try Graphics 1 and, crucially, that it not redefine any characters, but instead simply use "A" for alien, "S" for ship, and a vertical bar for the missile.
The code it returned, while superficially appearing to be an improvement, still stubbornly insisted on using Graphics 0:
10 GRAPHICS 1+16
20 POKE 77,0 :REM Disable cursor
30 SHIPX=10 :FIRE=0 :MX=0 :MY=0
40 REM === DRAW ALIEN ROW ===
50 FOR I=2 TO 18 STEP 3
60 POSITION I,5 :PRINT "A"; :NEXT I
100 REM === MAIN LOOP ===
110 ST=STICK(0) :BT=STRIG(0)
120 IF ST=11 AND SHIPX>0 THEN SHIPX=SHIPX-1
130 IF ST=7 AND SHIPX<19 THEN SHIPX=SHIPX+1
140 POSITION 0,22 :PRINT " "
150 POSITION SHIPX,22 :PRINT "S";
160 IF FIRE=0 AND BT=0 THEN FIRE=1 :MX=SHIPX :MY=21
170 IF FIRE=1 THEN GOSUB 300
180 GOTO 100
300 REM === MOVE MISSILE ===
310 POSITION MX,MY :PRINT "|";
320 FOR D=1 TO 50:NEXT D
330 POSITION MX,MY :PRINT " ";
340 MY=MY-1
350 IF MY<0 THEN FIRE=0 :RETURN
360 POSITION MX,MY
370 IF PEEK(PEEK(88)+MX+MY*20)=ASC("A") THEN POSITION MX,MY :PRINT " " :FIRE=0 :RETURN
380 RETURN
The culprit, of course, was its continued reliance on PRINT instead of PRINT #6. I informed ChatGPT that it was still operating in Graphics 0, but, rather disappointingly, it failed to rectify the issue on its first revision.
I reiterated the problem, hoping it might finally grasp the nettle, but instead, it embarked on a rather perplexing tangent about screen memory and character sets, neither of which had any bearing on the matter at hand. It was, frankly, rather exasperating.
At last, I decided to spoon-feed it the answer: "The problem is that you are using PRINT instead of PRINT #6;. You don't need to alter memory or character sets. Please try again."
It eventually coughed up something vaguely approaching correct code, but it took a good many back-and-forths before anything genuinely runnable emerged. And even then, it later succumbed to an ERROR 141, Cursor out of range because it bafflingly chose to use INPUT #6, which, in this context, makes about as much sense as a chocolate teapot. What it should have done, of course, was use LOCATE to check for collisions with the alien ships.
Frankly, this "vibe coding" escapade proved utterly exhausting. I eventually threw in the towel, abandoning my attempts to coerce ChatGPT into producing a fully functional game. While it certainly provided a reasonable program outline, the relentless back-and-forth was simply tedious! I could, without a shadow of a doubt, have fine-tuned the thing myself in a fraction of the time.
So, I did just that. Here, for your amusement, is the fully functional code for this rather simple game:
10 GRAPHICS 1+16
20 POKE 77,0:REM Turn off text cursor
30 SHIPX=10:FIRE=0:MX=0:MY=0
40 REM === DRAW ALIEN ROW ===
50 FOR I=2 TO 18 STEP 3
60 POSITION I,5:PRINT #6;"a";:NEXT I
100 REM === MAIN LOOP ===
110 ST=STICK(0):BT=STRIG(0)
120 IF ST=11 AND SHIPX>0 THEN SHIPX=SHIPX-1
130 IF ST=7 AND SHIPX<19 THEN SHIPX=SHIPX+1
140 POSITION 0,22:PRINT #6;" ";
150 POSITION SHIPX,22:PRINT #6;"S";
160 IF FIRE=0 AND BT=0 THEN FIRE=1:MX=SHIPX:MY=18
170 IF FIRE=1 THEN GOSUB 300
180 GOTO 100
300 REM === MOVE MISSILE ===
310 LOCATE MX,MY,C
315 POSITION MX,MY:PRINT #6;".";
320 FOR D=1 TO 50:NEXT D
330 POSITION MX,MY:PRINT #6;" ";
340 MY=MY-1
350 IF MY<0 THEN FIRE=0:RETURN
355 IF C<>32 THEN S=S+10:FIRE=0
370 POSITION 0,0:PRINT #6;S
390 RETURN
There's not a great deal to it, really. One can use the joystick to shunt the "S" ship left and right at the bottom of the screen. Pressing the fire button launches a "." as a missile. Should you manage to hit an "a" alien, you'll be rewarded with a rather generous ten points. The aliens, I must confess, remain stubbornly motionless. As I said, it’s rather simple.
As straightforward as this little diversion may be, I'm genuinely rather perplexed as to how someone utterly unacquainted with Atari BASIC would ever manage to coax it into working solely through the "vibe coding" method with ChatGPT. It seemed perpetually inclined to generate incorrect code, and even when I knew precisely what was amiss and corrected it, the AI didn't seem to learn all that much. One would, I daresay, find oneself trapped in an endless loop of back-and-forth prompts, never quite reaching the promised land of a functional program.
As I rather shrewdly posited at the outset, perhaps this "vibe coding" business proves more fruitful with modern languages. But when it comes to old-school BASIC, I'm afraid to say, it was ultimately rather a bust. Pip pip!