Hacker News
12 days ago by haunter

The GameBoy emulator's code also looks like the GameBoy. Slow clap this is insane, definitely my favorite entry.

https://github.com/ioccc-src/winner/blob/master/2025/ncw1/pr...

The author, Nick Craig-Wood, is the creator of rclone!

11 days ago by nickcw

Glad you enjoyed it :-)

If you want to see how the sausage was made, here is the source:

https://github.com/ncw/ioccc-gameboy

You'll find an unobfuscated version (kind-of) there too. This the the one I actually worked on then I had a program squash all the variable names and squeeze it into the gameboy shape

The size limit for the entry was the killer. You are allowed 2503 non white space characters (a simplification - the rules are complicated) in IOCCC entries and 4K total code size. This isn't a lot to fit a Z80 processor and a GameBoy hardware emulator in!

I first wrote a full Gameboy emulator in C. It started out at about 6000 non white space characters. I then spent about about 100 hours work trying to get it to fit into the 2503 limit. For a long time I wasn't sure it was going to fit.

I decided making the emulator play Tetris (which is a fairly simple game) was the target so I stripped out features like the half carry flag in the Z80 emulator and the windowing system in the Gameboy emulation which Tetris didn't need. I also abused the C code terribly doing things with implicit int I can never un-see. I also got creative with the IOCCC rules which are implemented in a C program which checks your source and I spent some time reverse engineering that looking for loopholes! I discovered that the operators defined in <iso646.h> only count for one token which was very useful.

Once I had it small enough I had to supply some games to run with it. I created 4, a test program written in z80 assembler, a pi calculator (written in assembler), a 3d tic tac toe game (written in C with gbdk-2020) and a chess program also written in C. I discovered that quite a few open source games ran on the emulator too so I added a downloader for those where I could. Apparently not many games use BCD arithmetic - who would have thought!

It was a fun project.

11 days ago by binji

Very cool! Clearly I had a long way to go with mine to get it under the IOCCC requirements :) Though my goal was specifically PokƩmon... curious how much more you would need to be able to run that.

11 days ago by kees99

Uh... is this supposed to be valid standalone C?

GCC says there are a bunch of undefined symbols, first one being "R" right in the beginning:

  typedef  unsigned  char u;
  u w,X,T,D[1<<16],t[]=R,U=255;
11 days ago by dezgeg

That's defined in Makefile

10 days ago by taneq

Considering that one historical entry (winner maybe?) consisted of a source file that simply contained the character ā€˜c’, plus a makefile, I’d say it’s in the ball park.

11 days ago by sourcecodeplz

Damn, that is cool! Looking at me typing css & php...

11 days ago by trumpdong

It's an overdone trope in obfuscated programming contests - to make the code look like a picture.

11 days ago by qingcharles

It's a trope, I would not say it's overdone! :)

11 days ago by Waterluvian

There’s a company that’s become very successful selling basic sponges shaped like smiley faces.

11 days ago by s-macke

My favorite is the 366-byte C program emulator that can run Linux and Doom [0]. The VM implements an OISC - a One Instruction Set Computer [1].

[0] https://github.com/ioccc-src/winner/blob/master/2025/cable/p...

[1] https://github.com/ioccc-src/winner/blob/master/2025/cable/R...

11 days ago by cpldcpu

Wow! And it also implements a very interesting variant of SUBLEQ that is turing complete.

>This VM implements an OISC - a One Instruction Set Computer. That instruction takes three signed 32-bit operands, a, b and c, and runs a program from memory m[] as follows:

1 PC (program counter) starts at 0

2 Fetch the next instruction (32-bit signed operands a, b and c)

3 If the low bit on any operand is set, remove it, and replace that operand with m[operand] i.e., a dereference of that address

4 Set m[b] = m[b] - m[a]

5 If m[b] is 0 or negative, set the PC to c, otherwise increment PC by 3 words

6 Go to step 2

10 days ago by jpegqs

> 3 If the low bit on any operand is set, remove it, and replace that operand with m[operand] i.e., a dereference of that address

This dereference option makes a second instruction, this is not OISC.

9 days ago by cpldcpu

CISC view: Its another adressing mode.

RISC view: SUBLEQ is already four instructions (2x memory access, alu, branch)

11 days ago by stevekemp

I've spent the past few weeks coming up with my own simple programming language, which compiles to linux/amd64 assembly.

I could have gone all out writing standard library routines for opening files, running shell commands, coding strstr, strcpy, and similar. And to be honest I did implement some things I didn't need as part of the learning process (for example print(getenv("HOME")) works). But I soon realized I needed some example programs to test things and show off.

So of course the first real program I implemented was a brainfuck interpreter. Which means my language is now, indirectly, turing complete!

My early versions took 9 minutes to output the famous mandelbrot program, so I had to make a bunch of optimizations, and later implemented support for switch/case statements to speed things up. Now I can generate the same output in two minutes - so room for improvement, but also a good bit of progress!

Cheating by implementing another language in my own was very very satisfying. Though of course this is all for fun/learning and not intended to be used seriously by anybody, not even myself!

https://github.com/skx/s-lang

10 days ago by gsliepen

Nice! What surprised my about the IOCCC submission though was how fast it ran. Sure, subleq can at least do some useful arithmetic in one instructions, but it still requires a lot of instructions to do an integer multiplication, let alone a floating point operation. But DOOM was actually playable with a decent FPS.

11 days ago by ralferoo

I think I like this idea, but the linked-to Eternal Software Initiative [1] is a bit confusing. There are several different versions of the instructions to decode this, all conflicting.

There's the one here: Set m[b] = m[b] - m[a]

Then it links to the reference implementation on github [2] which says you just need the napkin notes [3], which is dividing everything read by 4, which is corroborated by the reference implmentation [4], but it's not clear why 4 is chosen here rather than 2, as it seems to waste a bit. Was this bit needed, or is it reserved for future expansion?

I presume the original implementation didn't do the divide by 4 and it was added later, but I don't see why it was needed, other than perhaps just making LLVM code gen a little easier. I'd need to work through lots of examples to work out if the system as described is impossible without dividing by 4 (although you'd presumably only be able to access even addresses, and the PC increases by 3 each time, so it would definitely be annoying to refer to code locations).

Then the reference implementation starts doing magic when location 64 is accessed, overwriting locations 64-67 with the current time, which is mentioned in the napkin description, but not the description on the main page.

Both descriptions mention the magic -1 address, so it seems strange that the very implementation-dependent UTC clock isn't also implemented with -ve addresses rather than trashing memory that is otherwise free for the implementation to use as desired.

Both descriptions also mention the regular timer interrupt process, which also seems disappointing, reusing address 0 as the interrupt handler location and 1 as the saved PC, which means that you have to overwrite the initial entry point at location 0 as soon as the program starts.

[1] https://eternal-software.org/

[2] https://github.com/adriancable/eternal

[3] https://github.com/adriancable/eternal/blob/main/docs/napkin...

[4] https://github.com/adriancable/eternal/blob/main/vm/vm.c

11 days ago by ralferoo

Maybe answering my own question, but I'm now wondering if the reason that the divide by 4 was chosen (so essentially using byte addressing instead of word addressing) is so that the linker can do symbol fixup / relocation.

4 days ago by adriancable

Hi - author of the VM here! The whole LLVM stack (including codegen at the start, all the way through to symbol fixup on the linker side) assumes that addresses are byte addresses. And indeed for the VM to be useful, we want to be able to compile and run software written for POSIX C (e.g. Linux), which assumes an 8-bit byte. This conflicts with the architecture of the VM where the smallest directly addressable unit is a 32-bit word.

We manage this at the MIR level - we have for example LW, LH and LB MIR instructions that load (aligned) 32-bit words, 16-bit halfwords and 8-bit bytes from byte addresses that LLVM generates, respectively. LW is implemented as a simple assembly instruction (since we can load 32-bit words directly), whereas LH and LB are a lot more complicated since they need to load the whole 32 bit word and then compute individual bits depending on the subaddress within the word. But the end result is always that generated instructions reference only (32-bit aligned) byte addresses.

So this means:

- that the VM has to divide those byte addresses by 4 to obtain word addresses (i.e. indexes into our 32-bit word memory)

- the bottom two bits of each byte address are guaranteed to be 0, since all byte addresses in generated code are 32-bit aligned, therefore we can repurpose the low bit to indicate the indirect addressing mode

Hope this helps!

11 days ago by yayitswei

In case anyone was wondering, the IOCCC specifically permits LLM use in their guidelines.

"The IOCCC has a rich history of remarkable winning entries created by authors who skillfully employed various techniques (often their own tools) to develop their code."

11 days ago by tgv

I'm in the no-AI camp, but for this case, I find it interesting, especially since there's little obfuscated C online, and LLMs cannot infer intention from the actual code. Did you spot any entries with LLM support?

Also, the reverse is interesting: how well can they guess the function of the obfuscated code?

11 days ago by Catloafdev

If you're talking about frontier AI, they have no issue de-obfuscating any of these accurately.

10 days ago by Chu4eeno

Yeah, Claude, Grok and Gemini immediately recognized it as a SUBLEQ VM (and worked out from there all the details), only chatgpt got stumped and just said it was a "visual simulator".

All the big labs have plenty of proprietary (i. e. paying PhD holders good money for writing stuff) and synthetic training data now compensating for the lack of "naturally occuring" SUBLEQ and similar stuff.

11 days ago by undefined
[deleted]
11 days ago by omoikane

This primarily affects the judges who are opening themselves up to potentially a flood of shoddy code, but given the nature of the contest, I suspect they are very good at differentiating interesting code from low quality code.

I think it's great that IOCCC accepts code that might have been built with machine assistance, because it makes the purely handcrafted winners seem even more valuable.

11 days ago by zerr

So it turned into an LLM-gymnastics competition?

11 days ago by asfjhq

Rule 7 would be self-contradictory if "tools" include AI.

https://www.ioccc.org/2025/rules.html

It seems to refer to custom code generators. Why would they mean AI if they explicitly talk about a "rich history" (when AI wasn't available)?

11 days ago by GTP

I don't think rule 7 would be self-contradictory since you indeed don't own the output of an LLM, but crucially, also no one else owns it. I read that rule as don't submit someone else's code without permission, which isn't violated by using an LLM.

The long tradition refers to the use of tooling in general, and could mean that, since past tools were accepted, recent tools like LLMs can be fair game as well.

But, since there can be doubts about this interpretation, them saying explicitly if LLMs are permitted or not could be beneficial. But then again, maybe they don't want to commit to an hard rule and have more freedom to decide on a case by case basis, or just don't advertise that LLMs are welcome to prevent a flood of vibe-coded submissions.

11 days ago by rtk_asp

Either you view LLM code as stolen, in which case you cannot get permission of the original owners, or you accept that LLM code is not copyrightable and has no original owners.

In both cases you cannot get permission.

12 days ago by aquir

The website itself is obfuscated, it’s not easy to find the C sources at all!

11 days ago by lifebeyondfife
11 days ago by crazygringo

Even that requires clicking on unintuitive username links... scrolling to the very bottom of what are sometimes very long pages... and locating the "entry source code" file out of a sometimes very large list of files.

When most visitors obviously just want to glance at the programs and see what they do, this is horrifically organized.

11 days ago by layer8

The first sentence links to the section that lists the winning entries, each of which have a ā€œC codeā€ link in the top right.

11 days ago by hugh-avherald

It's really hard to navigate. I cannot work out what the contest is; it seems to assume you know what it is already.

11 days ago by drfloyd51

Apparently, if your not cool enough to know how to get in the club, you are not cool enough to be in the club.

11 days ago by TuringTourist

Alternatively, I wouldn't want to be in a club that was lame enough to accept me. :)

11 days ago by ollybee

I with the Underhanded C Contest would come back, it was far more interesting to me. No disrespect intended to the Obfuscated C competitors.

10 days ago by ASalazarMX

I miss it too, and think of it every year. This is also very nice, though.

11 days ago by roer

There's a Frieren [1] reference in there! https://www.ioccc.org/2025/yang2/index.html

One of the main characters is called Fern, and she almost exclusively uses the common offensive magic of Zoltraak.

[1] https://en.wikipedia.org/wiki/Frieren

11 days ago by omoikane

There are two Frieren references, the other one is https://www.ioccc.org/2025/yang1/index.html

11 days ago by normanthreep

[flagged]

11 days ago by roer

Going through your comment history makes me wish for a way to ignore hn users

11 days ago by normanthreep

[flagged]

11 days ago by undefined
[deleted]
11 days ago by undefined
[deleted]
11 days ago by perching_aix

baby's first insults

11 days ago by msk-lywenn

OMG, my game boy game of life implementation is included in one of the winning entries!

11 days ago by nickcw

After I made the emulator I trawled GitHub to try to find games it could play within the 32K limit. I found yours - thank you :-) - and the ./try.sh script has an option to download it from GitHub for the user to test.

11 days ago by bbbbbr

It's after the fact now, but I maintain a list of 32K Game Boy games on itch.io here: https://itch.io/c/3521183/game-boy-32k-roms

Great project btw

11 days ago by locao

Back in 2000 I was being interviewed for my first internship, to join a team of C programmers. They showed me one of the winner entries of the prior years, asked me to review the code and left the room. About 5 minutes later they came back:

– And?

– I'm sorry I wasted your time. I just can't understand it.

They burst into laughs and asked me to start the joining process.

I wonder if people still make fun of interns. I still have a good laugh when I remember myself freaking out.

Daily Digest

Get a daily email with the the top stories from Hacker News. No spam, unsubscribe at any time.