Back to index
Last updated: 14 Aug 2025 (complete changelog since 06 August 2025)

Introduction

This is my first of two winning entries in 2024 IOCCC (28th). I spent many hours on this, in fact every day for two whole months to the day I spent many hours. I was exhausted by the end of it. It was very well worth it and I had a lot of fun. The judges, I know, did too, as they said that exactly.

The judges did something really cool this time - a video showing all the entries. Although I think YouTube ads ruin things I'll link to it anyway as I know Landon will appreciate it. One could always download it if they wished to not be interrupted: IOCCC Prize in diabolical logistics - A Pact With the Devil On the Oregon Trail.

For much more that I wrote see the entry on the IOCCC website: https://www.ioccc.org/2024/ferguson1/index.html.

A few comments of interest. With the submission code that has 134 149 gotos I played it once from start to finish and the lines changed a total of 985 1416 (!!) times, counting function calls in the program (that is, prog.c functions, not libc functions); when only considering the line changes in main() it was still a huge total of 776 1131 (!!) times! This really IS diabolical.

With blank lines, lines with just a brace and lines without code removed, there are only 59 58 (!!) lines. And yet somehow it changed lines well over 1000 times!

Flex and bison do not come close to this. I have never seen anything as sinister as this. The award title is very fitting, even without the theme of the game.

Something that made me proud, somehow, is when Landon said on the video that playing it is almost as diabolical as trying to trace the code.

Another fun thing: it uses a SINGLE FLAT char * as a char **. Yes. You read that right! There is no char **; there is just a flat char *that is used like one. I wrote a program which creates a data file with all the messages and this data file (three versions depending on which one you play) has a blocksize which allows for easy accessing of strings. Each string has an embedded NUL byte and the function getdelim() is used with the delimiter EOF. This allows the entire char * to be read in, NUL bytes, padding and valid text combined. This means that when I index a string (based on the blocksize) it will print the string but it will not print the padding because the NUL byte will stop it. This saves a huge amount of bytes. There would be no way this could have existed as an IOCCC entry if it was in the code. Even if it was not too large (but the strings are way too large) it would remove the tricks that I used so it would not be worth it.

The data file has emojis. In the version that did not win, the encrypted version, the emojis were also encrypted - and not decrypted yet somehow they were still printed fine, as was all the text. I was disappointed that version did not win as the key was used to obtain the key by encrypting a character (known to be at a specific place in the file - with beautiful numerology) and then based on that location and pointer arithmetic, calculate the key.

Nonetheless, I had at first little doubt this one would win. Only when they had a record number of finalists did I start to get worried. But the judges also said something that sounded very much like this: Landon said that some of the finalists need special compilation steps and that is something mine does need, as it builds the data files (and other things but the important part is the data files). I knew then that it HAD to be a finalist. But there is always that lingering fear. Even so it seemed incomprehensible that this would not win.

Something else worth noting is that the entirety of main() is inside a single switch(1) (!). Every single part of it. Yes you can put labels that do not belong to the switch value in a switch. I abused this heavily but I abused labels heavily outside of switch too, as I get to next. Anyway: the C standard says, that for goto, the label must be in the same function (in fact if it's not it should be a compiler error), and more importantly, if you want to avoid UB (undefined behaviour), you MUST NOT skip initialisation!

As everything is global and as when I need certain values before a jump are initialised (see below on this) there are no problems. As you can see, if you have a label in a switch before a case or default, that label is skipped! It is only reached if one does a goto to it.

The way I designed this program is truly horrible. Everything you know about C flow control no longer applies. It is so diabolical that two for() loops actually have the code of the OTHER for loop! What's more, they actually act on the same array with the same iterator but in a different way! There is so much more like that though...blocks of code are no longer what you believed. There is code that is dead but also isn't dead. There is an if() that jumps through several labels only to jump right back to after the initial jump - doing absolutely nothing other than leading you on a wild goose chase!

One switch statement (an inner switch - the events) has a polymorphic case (in fact it has several forms)! A case in the events code actually jumps to part of another case and then exits in the correct path, but it can take multiple different events first. The jumping is ludicrous. You have to look at the code to see it. Try running it through a debugger - if you dare!

I had to do EXTENSIVE testing because of all the gotos. One false jump and everything would come crashing down. In fact earlier on I discovered a mistake I made when extra tired. It caused the entire game loop to go through without any prompting. In other words the game was over in a few seconds after it got to that specific event! Thankfully I found it quickly. If I had not, because of all the gotos, I would have had to revert much more: events as well as the obfuscation, for a fun thing about obfuscation is once it's obfuscated you can fit in more bytes - it just is how it works.

The real joy though comes from the many jokes, the story, with dark and rude jokes included (rude in the British English definition), even cannibalism in hilarious ways. The code took a long time to create but the data file took just as much time if not more time. The title of the award is truly fitting in so many ways, not just the game itself but the tracing of the code.

But the winning entries this year - as everyone else (not me as I explain elsewhere) had almost five years to work on submissions, where I only had a few months - were so amazing that it makes it even more amazing that it won - and that holds for all the winners, not just this one or my other one.