DOOM, ported to an Arduino Uno (ATmega328P, 2KB SRAM, 32KB flash, 16MHz, no FPU).
The chip itself computes the raycasting: wall distances, fisheye correction, texture hit fractions, sprite visibility, collision detection, enemy AI, hitscan combat, and player health, using 404 real wall segments parsed directly from doom1.wad's E1M1 linedefs. A Python/pygame host receives the computed frame data over UART and renders it using real WAD textures and sprites. The host is a display driver. All the 3D math happens on the chip.
The game is split into independently compiled binary chunks (menu, level, options, save, load, help). When a chunk needs to swap, it sends a REQ over serial and halts. The host reflashes the chip via avrdude and the existing Optiboot bootloader, no custom self-programming code. EEPROM (the only memory that survives a reflash) is used as a cross-chunk message channel for save data and settings.
Performance was tuned entirely on real hardware. The naive version ran at 4.1 seconds per frame. A candidate-list prefilter (compute once per frame which walls could possibly be visible, not once per ray) plus column count reduction brought it down to 0.83 seconds per frame at 16 columns.
The Arduino IDE and .ino sketches were deliberately avoided. A .ino sketch compiles against the Arduino core library which pulls in a setup()/loop() wrapper, Serial (a buffered interrupt-driven UART wrapper), and various other conveniences, all of which cost SRAM on a chip that only has 2KB total. This project instead compiles bare C against avr-libc directly with avr-gcc, writing UART registers by hand. That difference is why level1.c fits in about 800 bytes of RAM with room to spare, instead of not fitting at all.
Built in 3 days.
Codertalha5524