If you’re programming on a modern computer, you typically make use of lots of work done by other people. There’s operating systems to abstract away the complexities of modern hardware, standard libraries to implement common tasks, and tons of third-party libraries that prevent you from having to reinvent the wheel all the time: you’re definitely not the first one trying to draw graphics onto a screen or store data in a file.
But if it’s the wheels you’re most interested in, then there’s nothing wrong with inventing new ones now and then. [Michal Zalewski], for instance, has made a beautiful Tetris clone in just 1000 lines of C, without using anyone else’s code.
The purpose of this exercise is to show that it’s possible to make a game with graphics comparable to modern, complex computing systems, without relying on operating systems or third-party libraries. The hardware consists of not much more than an ARM Cortex-M7 MCU, a 240×320 LCD screen and a few buttons soldered onto a piece of prototyping board, all powered by a set of AAA batteries.
The software is similarly spartan: just pure C code running directly on the CPU core. Graphic elements, some generated by AI and others hand-drawn, are stored in memory as plain bitmaps. They are manipulated by 150 lines of code that shuffles sprites around the display at a speed high enough to generate smooth motion. Game mechanics take up about 250 lines, while sound consists of simple square-wave chiptunes written in just 50 lines of code.
[Michal]’s code is very well documented, and his blog post gives even more details about all the problems he had to solve. One example is the length of keypresses: when do you interpret a keypress as a single “press”, and when does it become “press and hold”? Apparently, waiting 250 ms after the first press and 100 ms after subsequent ones does the trick. [Michal] is a bit of an expert on bare-bones game programming by now: he has previously pushed several 8-bit micros to their very limits. Third-party libraries can make your programming life a lot easier, but it’s good to reflect on the dangers of relying too much on other people’s code.
Beautiful.
Love it!
That said when you said 1000 lines of C “and nothing else” I was hoping to see something procedurally generated not separate assets. Let alone AI generated assets.
I, too, thought the graphics were somehow being created on-the-fly, and that’s the bit I was reading through for.
They’re bitmaps – what difference does it make whether he drew them or an AI did? The point was figuring out how to make it work directly on the bare metal with the tightest self-reliant code possible.
i think the point isn’t tightness but rather just plain old self-reliance. one of the things i have come to enjoy about working without libraries is you can elegantly state the algorithm without crudding everything up with hacks to make it tiny, and still save a bunch of space compared to using an over-generalized library.
but anyways the difference it makes is it disappointed readers who read too much into “and nothing else” in the headline. upon reading the article, i would have headlined it “tetris clone uses 1000 lines of code, a pile of bitmaps, an ARM, an LCD, and some buttons” :)
I’m the author of the original project – and yeah, the headline goes a tad too far.
As I explain in the intro, my goal was to show the relative ease of building fairly complex and good-looking stuff on 32-bit bare-metal platforms; the vast majority of handheld game projects you see either resort to a Linux SoC, or to really crummy black-and-white graphics on some post-stamp-sized I2C display.
But yeah, this is obviously still building on top of other stuff. ARM CMSIS and Microchip DFPs don’t do anything complex, but without them, the code would be less readable and less portable. The newlib standard C library doesn’t do a whole lot of heavy lifting, but I use it for pow(). There is some firmware running on the EEPROM chip and the FFC-mounted LCD controller chip… the MCU itself is a marvel of engineering, and the code can be simpler because of extra amenities such as the SPI controller or the PWM circuitry… etc.
Anyway, all I’m saying was, there are quite a few other dependencies. Just no OS and no third-party black-box drivers for stuff like the LCD. And the point is: it’s simpler than it sounds.
:+1:
The headline is a little misleading, honestly I thought this was all done by single eeprom LUT just by the headline alone. And yes, AI generated images kinda takes away from the entire concept, relying not just on others work but stolen work at that.
Stolen? Did the developer whizz in your Wheaties? What are you on about?
This is so well made – I love the retro vibe/the CRT look and the level of detail that went into the graphics! Great project!
Amber CRTs in color where such a rarity (0). The level of wrong detail is astonishing.
As they say – if you want something doing right, do it yourself. Excellent job!
I can write any code in one line.
Glad to see this being said, ‘cause the irrational fear of wheel-reinvention has become a scourge in the world of coding. It’s good to reuse effort, but some folks spend weeks learning a bloated immature framework rather than spend a day writing the part they need from scratch. Especially with web dev, where 90% of Stack Overflow questions are about React or Angular or jQuery when a plain JS answer would be simpler and help more people for longer.
It seems like game developers have the same problem – obviously you can’t make a AAA title from scratch, but even 2D pixel art games are routinely made in Unity, so that 5 minutes of play heats my phone to 450°C and browns out the power grid of Western Europe, I have to believe these games could have been built the way actual retro games were. (Also: how’s Unity working out for you?)
I’m probably preaching to the converted on HaD, but I think most developers could make their lives easier by reinventing more wheels.
Either you’re wiser than a world of indie devs, or there’s something more on their end that makes using an existing engine worth it, even if it’s more resource intensive on the player’s end.
I’m the author of the device in question, popping in… and yes, there are many good reasons. First, there’s really no such thing as “bare metal” development for mobile phones anyway: when it comes to the levels of abstraction, you’re just choosing between some n or n+1. So it’s not like some sort of “engineering purity” in that environment is even a meaningful goal.
Then, a major consideration for indie game devs is portability. If there’s an engine they can use that lets their game run with minimal changes on Android, iOS, and desktop devices, it’s a no-brainer. If it scales seamlessly for different screen sizes and device generations, even better.
Last but not least, there are far more people who know “userspace” development than there are people skilled with embedded systems and “bare metal” / kernel development. So it’s just a path of least resistance: you can ship an acceptable product without spending months learning about a new domain.
I do have a mild gripe here, but not with the developers of commodity apps, but with the tendency – very evident on Hack-a-Day too! – for hobbyists to reach for Linux SoCs if all they really need is to blink some LEDs, toggle some output ports, and maybe display simple graphics on a small screen. And even there, my gripe isn’t that it’s a less dignified way of doing things. It’s just that quite often, they don’t realize that the alternative may be a lot simpler to use than what they’re subjecting themselves to.
Very nice! It is fun to ‘twiddle’ the bits once in awhile without the weight of ‘libraries’ of code behind it. Cool beans! Just you, the processor, memory, storage, a screen, a few buttons and a host cross compiler/assembler to build a binary. I don’t care for the AI part, but that was only to build bitmaps (as written anyway).
(Author here.) Yeah, FWIW, it wasn’t my intention to somehow promote ML or ride on the coattails of that. It’s just that I was looking for usable stock images of computer terminals, and right now, stock “photography” is overrun with AI-generated stuff. As it happens, two of these images were a good baseline for what I wanted to do, and as a bonus, they’re not copyrightable, so I can pirate from the pirates with clean conscience.