Kuiper Ranger: a familiar game and an AI experiment

While I was at Carnegie Mellon in 1988, two friends and I collaborated on writing an AsteroŃ–ds arcade game knock-off. The game, called aster, was written in C and tried to adhere to strict object-oriented rules where every object, even simple ones such as 2D points, had to be accessed exclusively through accessor functions and macros. Back then, math was slow and floating point was unthinkable. It used exclusively fixed-point integer math (16.16), including trig that was implemented using the CORDIC algorithm.

It ran initially on Sun 2 workstations by memory mapping the sunbw black and white bitmap graphics frame buffer and drawing lines using the Bresenham algorithm. Then it ran on the suncg6 color-mapped monitor (8 bits/pixel = “bytemap”), although it still used only black and white, as it still does today. It had some primitive sound effects even at this early stage.

Next it was ported to the DECstation 3100 with bytemap. Its MIPS CPU was really fast and the game played very smoothly in real time. If I remember correctly, Zalman Stern did that.

When I worked at IBM after college, it was ported to a few IBM displays including the IBM RT/PC (AIWS), Megapixel, APA16 on the HFT (“high function terminal”).

By 1993 it had been ported to the X Window system. At that point, all the other raw display implementations were dropped, along with sound support. The X11 support allowed it to run on virtually every relevant Unix-based platform at the time. It was renamed to xaster. Various work continued at random intervals through 1999 when version xaster-1.17 was done. After that, it sat untouched for a quarter century.

In 2025, I decided it would be a good project to use as a vehicle for learning AI technology for software development, with the ultimate goal as having it run in a web browser in an HTML5 canvas. That seemed like a big task, so I broke it down carefully into several steps:

  • Converted to C++98 so it could remain object-oriented while removing the verbose macro accessors and beautifying the code. AI was actually not very helpful for this at all. It couldn’t do seemingly simple tasks like converting function prototypes from K&R style to ANSI. This ended up being a largely manual process, by which time I was questioning the wisdom of doing it.
  • The Plot module and the Input modules were always strictly-defined APIs that would abstract the graphics and keyboard input. But they really assumed a fixed 4:3 display with static resolution (X11 full screen mode only), and I knew eventually I wanted to be able to run in a variable-sized window with dynamic resizing. At that point I replaced all the fixed-point arithmetic with floating point, CORDIC with libm, etc. I made it so the drawing area was letterboxed as necessary to maintain a 4:3 aspect ratio. That was a lot of labor.
  • Next I considered sound. The code still had calls to a Sound API spread throughout, so that API just needed to be implemented. AI suggested using the SDL2 library for that. Then something quite incredible happened. I wrote sound.hpp, a header file declaring API function definitions like init, term, play a sound specified by an enum (fire, explode, etc), start a continuous sound (thrust, alien) and stop it. Each function had a comment specifying in detail exactly what the API should do. I believe it was Anthropic Claude 4.5 that I was using from vscode when I asked that the API be implemented. Boom! It wrote sound.cpp, complete with waveform generators and a waveform mixer, which compiled without error and the damn thing suddenly had sound! This can’t be what “vibe coding” is, can it? It seems more significant than that.
  • Now, the sounds were kind of crappy. I used AI further to generate better kinds of sounds. For example, I had it create a band-pass filter that I could apply to the output of its noise generator, and improved the decaying sinewave sounds and the alien siren sound. The sound was getting pretty respectable!
  • I’m embarrassed to say it was only at this point that I realized SDL2 was actually a complete and popular cross-platform graphics library, not just a sound interface. The path became clear instantly. I’d replace all X11 graphics with SDL2, and then the application would run on any Linux, whether X11 or Wayland, plus Windows, macOS, and probably other platforms almost for free. Moreover, I found out that SDL2 supported compiled using Emscripten into Web Assembly (WASM) that would theoretically run in an HTML5 canvas!
  • But before undertaking all of this, I knew I needed to reorganize it into a typical event-driven game loop. Again it was quite a bit of work to end up with an outer loop that looked like
    while(1) { Update Game State; Update Display; Process inputs }
    It required refactoring the code into a couple levels of nested state machines that I developed and perfected inefficiently by trial and error.
  • I had AI do most of the conversion to SDL2. It ripped out the X11 code and replaced it with SDL2 code, which unbelievably worked the first time. I’m still reeling over that actually happening. Next I spent a considerable amount of extra time getting the window resizing and full screen mode that had worked under X11 to work seamlessly under SDL2. I used AI often for hints (RIP StackOverflow). I was delighted to replace that Imakefile with a Makefile, removing the last vestige of the X11 legacy. The result actually worked better than X11 because SDL2 has vertical sync support. Under X11, there was some tearing during graphics updates, but SDL2 did not have this problem.
  • Finally, I used hints from AI to get Emscripten working. I had it running in a web browser within maybe an hour. Yet again I was blown away by the existence of such technologies (SDL2 and Emscripten among them) that just work, and the ease of following AI instructions to download it and get it all working.

In vscode, I experienced seeing this: AI ran the build command in the terminal, saw that the Makefile it had generated went into an infinite loop spewing output, recognized the problem, fixed the Makefile, ran the build command again and had it succeed with a binary. The only thing I was doing was pressing an OK button to allow it to run each command. Well it won’t be 5 minutes before that isn’t necessary anymore and the programmer can be out of the loop. And once it’s able to learn dynamically, it’ll be a full-on programmer. Then it’ll be writing code we can’t even understand, and that’s probably the cusp of the Singularity.

At this point I had visions of publishing these results, and decided it might be advisable to rename it so it would be less likely to get a take-down request from the trademark holder. Roid Ranger sounded good to me, but AI advised strongly that Roid is too similar. It was relentlessly insistent on that point. Well, OK. There are already games called that anyway. I had it list 20 possible names, but they were meh. I suggested to it my second idea Kuiper Ranger, and it wrote a two-page essay about how much it loved that and why. So that’s how it got its current name.

I’ll need to update this page as I complete additional phases of this project. These are basically more learning projects below. Then I can wash my hands of this project and maybe use AI for something useful.

  • Packaging it as an RPM for Debian based installers, including desktop icons, and contributing it to distros like Ubuntu.
  • Testing on Windows & macOS and creating installers for those too. Why not? AI will do the grunt work!
  • Keeping secure high scores for the on-line version. Anti-cheat is quite an undertaking for games that run entirely on client machines, but it is doable using even logging and server-side fast-forward game replay to verify scores are actually valid (although someone might use AI to quickly write an AI super-player…)

Ok, without further ado, here is as link to the on-line browser version. Be sure to use a large window and press S to turn on the sound!

Curt
Author

Curt

Leave a Reply

Your email address will not be published. Required fields are marked *