Machine learning on a 1.023 MHz processor, 64KB of RAM, and a pair of 140KB floppy drives.
Modern AI has transformed industries from medicine to agriculture, but global chip shortages have put a real squeeze on available compute. As Wired reported, "Carmakers are using semiconductors taken from washing machines, rewriting code to use less silicon and even shipping their products without some chips while promising to add them in later."
In times like these, we have to be creative. The Apple ][+ may be old, but it can add and multiply arrays of numbers. As such, it can do machine learning.
It is our duty, for the betterment of humanity, to make our best effort to deploy these machines in the service of artificial intelligence.
A K-Means clustering implementation written entirely in Applesoft BASIC, running on a refurbished Apple ][+ from 1983. The program:
- Generates synthetic 2D data sampled from bivariate Gaussian distributions
- Runs K-Means clustering multiple times to convergence (analyzing algorithm behavior across random initializations)
- Visualizes each clustering result (data points, centroids, and decision boundaries) in Apple II+ high-resolution graphics (280×160 pixels)
- Reports accuracy and iteration counts for each run
The code is split across two programs that communicate via a disk-resident data file:
k-means.bas— Main clustering engine (loads or generates data, runs clustering, displays results)generate.bas— Data generation utility (creates synthetic 2D dataset, saves to disk)
See CLAUDE.md for architecture details and memory management rationale.
-
Load
k-means.basand typeRUN- The program checks for a DATA file
- If DATA doesn't exist, it automatically runs
generate.basto create it - Once data is loaded, K-Means executes NI% times (default 5 runs)
- Results are visualized and a summary table is printed
-
Alternatively, load
generate.basand typeRUNto regenerate the dataset from scratch- After generation, the program automatically runs K-Means to cluster the new data
The workflow uses a DATA file stored on disk to communicate between programs. This allows the ~14KB BASIC program space to be split into two focused utilities:
generate.bascreates the DATA file with synthetic samplesk-means.basloads DATA, clusters it, and visualizes results
If you manually delete the DATA file, the next K-Means run will regenerate it automatically.
Normal samples are generated using the Box-Muller transform, which produces mathematically exact standard normal variables (not an approximation like Irwin-Hall).
Benchmarked on AppleWin and physical Apple II+ hardware:
- Box-Muller: ~3 minutes for 1000 iterations
- Irwin-Hall: ~3 minutes for 1000 iterations
Performance is equivalent; Box-Muller chosen for mathematical exactness.
K-Means declares convergence when the sum of squared centroid displacements drops below 0.01. This is checked after each centroid update (line 730 in k-means.bas).
- Data points: '+' for class 0, box for class 1
- Centroids: Connected by white lines
- Decision boundaries: Perpendicular bisectors between centroids, clipped to a 260×140 window to avoid overwriting axes
- Text output: Iteration count, accuracy, and convergence status printed at bottom
Each execution of k-means.bas runs K-Means multiple times (configurable via NI%, default 5) from different random centroid initializations. This reveals:
- Convergence instability (some runs take more iterations)
- Accuracy variation (clustering quality depends on luck)
- Modal separation difficulty (how often each class is recovered)
The Apple II's hi-res graphics (HGR) lives at $2000–$3FFF to maintain backward compatibility with 16K machines from 1977. This leaves only $0800–$1FFF for BASIC program text—about 6KB—making single-file programs impossible once you add clustering + graphics + statistics.
Solution: Program chaining via disk-resident data.
- k-means.bas + generate.bas: Each ~6KB, share data via disk file
- Memory layout: LOMEM = $4000 (above HGR), HIMEM = $C000 (below DOS)
- Available RAM: $0800–$3FFF for program text + variables (~14KB total)
This constraint drove the two-file architecture and is documented in detail in CLAUDE.md.
This is part of a larger project to bring an Apple ][+ back to life. The full story—hardware restoration, data recovery, memory constraints, and the road to getting ML running in BASIC—is documented at mdcramer.github.io/apple-2-blog.