From 77fb0f11a2ddc8584a1ebe8d68fb0cccf3b959a6 Mon Sep 17 00:00:00 2001 From: Cody Boone Ferguson <53008573+xexyl@users.noreply.github.com> Date: Wed, 8 Feb 2023 05:05:34 -0800 Subject: [PATCH] Remove hint.html and index.html As per discussions on GitHub the index.html and hint.html files should be deleted in favour of README.md files (from any .text/.txt/.markdown/.md files which will be turned into README.md in an upcoming commit). --- 1984/anonymous/index.html | 183 ----- 1984/decot/index.html | 187 ----- 1984/index.html | 178 ----- 1984/laman/index.html | 191 ------ 1984/mullender/index.html | 201 ------ 1985/applin/index.html | 180 ----- 1985/august/index.html | 184 ----- 1985/index.html | 179 ----- 1985/lycklama/index.html | 187 ----- 1985/shapiro/index.html | 185 ----- 1985/sicherman/index.html | 198 ------ 1986/applin/index.html | 186 ----- 1986/august/index.html | 189 ------ 1986/bright/index.html | 189 ------ 1986/hague/index.html | 190 ------ 1986/holloway/index.html | 190 ------ 1986/index.html | 186 ----- 1986/marshall/index.html | 191 ------ 1986/pawka/index.html | 184 ----- 1986/stein/index.html | 192 ------ 1986/wall/index.html | 195 ------ 1987/biggar/index.html | 203 ------ 1987/heckbert/index.html | 190 ------ 1987/hines/index.html | 195 ------ 1987/index.html | 187 ----- 1987/korn/index.html | 211 ------ 1987/lievaart/index.html | 202 ------ 1987/wall/index.html | 195 ------ 1987/westley/index.html | 192 ------ 2011/akari/hint.html | 159 ----- 2011/blakely/hint.html | 246 ------- 2011/borsanyi/hint.html | 106 --- 2011/dlowe/hint.html | 329 --------- 2011/eastman/hint.html | 110 --- 2011/fredriksson/hint.html | 307 --------- 2011/goren/hint.html | 112 --- 2011/hamaji/hint.html | 242 ------- 2011/hou/hint.html | 137 ---- 2011/konno/hint.html | 77 --- 2011/richards/hint.html | 104 --- 2011/toledo/hint.html | 283 -------- 2011/vik/hint.html | 187 ----- 2011/zucker/hint.html | 186 ----- 2012/blakely/hint.html | 142 ---- 2012/deckmyn/hint.html | 114 ---- 2012/dlowe/hint.html | 145 ---- 2012/endoh1/hint.html | 203 ------ 2012/endoh2/hint.html | 166 ----- 2012/grothe/hint.html | 152 ----- 2012/hamano/hint.html | 114 ---- 2012/hou/hint.html | 124 ---- 2012/kang/hint.html | 193 ------ 2012/konno/hint.html | 89 --- 2012/omoikane/hint.html | 176 ----- 2012/tromp/hint.html | 486 ------------- 2012/vik/hint.html | 169 ----- 2012/zeitak/hint.html | 151 ----- 2013/birken/hint.html | 287 -------- 2013/cable1/hint.html | 121 ---- 2013/cable2/hint.html | 145 ---- 2013/cable3/hint.html | 264 -------- 2013/dlowe/hint.html | 140 ---- 2013/endoh1/hint.html | 246 ------- 2013/endoh2/hint.html | 117 ---- 2013/endoh3/hint.html | 234 ------- 2013/endoh4/hint.html | 142 ---- 2013/hou/hint.html | 142 ---- 2013/mills/hint.html | 152 ----- 2013/misaka/hint.html | 295 -------- 2013/morgan1/hint.html | 129 ---- 2013/morgan2/hint.html | 162 ----- 2013/robison/hint.html | 130 ---- 2014/birken/hint.html | 159 ----- 2014/deak/hint.html | 107 --- 2014/endoh1/hint.html | 74 -- 2014/endoh2/hint.html | 78 --- 2014/maffiodo1/hint.html | 321 --------- 2014/maffiodo2/hint.html | 108 --- 2014/morgan/hint.html | 120 ---- 2014/sinon/hint.html | 146 ---- 2014/skeggs/hint.html | 258 ------- 2014/vik/hint.html | 112 --- 2014/wiedijk/hint.html | 83 --- 2015/burton/hint.html | 210 ------ 2015/dogon/hint.html | 136 ---- 2015/duble/hint.html | 215 ------ 2015/endoh1/hint.html | 201 ------ 2015/endoh2/hint.html | 88 --- 2015/endoh3/hint.html | 234 ------- 2015/endoh4/hint.html | 74 -- 2015/hou/hint.html | 121 ---- 2015/howe/hint.html | 155 ----- 2015/mills1/hint.html | 175 ----- 2015/mills2/hint.html | 149 ---- 2015/muth/hint.html | 143 ---- 2015/schweikhardt/hint.html | 805 ---------------------- 2015/yang/hint.html | 144 ---- 2018/algmyr/hint.html | 154 ----- 2018/anderson/hint.html | 91 --- 2018/bellard/hint.html | 105 --- 2018/burton1/hint.html | 246 ------- 2018/burton2/hint.html | 428 ------------ 2018/ciura/hint.html | 308 --------- 2018/endoh1/hint.html | 78 --- 2018/endoh2/hint.html | 80 --- 2018/ferguson/hint.html | 1198 --------------------------------- 2018/giles/hint.html | 80 --- 2018/hou/hint.html | 64 -- 2018/mills/hint.html | 753 --------------------- 2018/poikola/hint.html | 157 ----- 2018/vokes/hint.html | 227 ------- 2018/yang/hint.html | 189 ------ 2019/adamovsky/hint.html | 273 -------- 2019/burton/hint.html | 101 --- 2019/ciura/hint.html | 183 ----- 2019/diels-grabsch1/hint.html | 84 --- 2019/diels-grabsch2/hint.html | 210 ------ 2019/dogon/hint.html | 169 ----- 2019/duble/hint.html | 196 ------ 2019/endoh/hint.html | 124 ---- 2019/giles/hint.html | 192 ------ 2019/karns/hint.html | 105 --- 2019/lynn/hint.html | 298 -------- 2019/mills/hint.html | 651 ------------------ 2019/poikola/hint.html | 185 ----- 2019/yang/hint.html | 229 ------- 2020/burton/index.html | 122 ---- 2020/carlini/index.html | 326 --------- 2020/endoh1/index.html | 191 ------ 2020/endoh2/index.html | 87 --- 2020/endoh3/index.html | 80 --- 2020/ferguson1/index.html | 549 --------------- 2020/ferguson2/index.html | 771 --------------------- 2020/giles/index.html | 178 ----- 2020/index.html | 117 ---- 2020/kurdyukov1/index.html | 109 --- 2020/kurdyukov2/index.html | 143 ---- 2020/kurdyukov3/index.html | 83 --- 2020/kurdyukov4/index.html | 149 ---- 2020/otterness/index.html | 185 ----- 2020/tsoj/index.html | 151 ----- 2020/yang/index.html | 185 ----- index.html | 371 ---------- 143 files changed, 28606 deletions(-) delete mode 100644 1984/anonymous/index.html delete mode 100644 1984/decot/index.html delete mode 100644 1984/index.html delete mode 100644 1984/laman/index.html delete mode 100644 1984/mullender/index.html delete mode 100644 1985/applin/index.html delete mode 100644 1985/august/index.html delete mode 100644 1985/index.html delete mode 100644 1985/lycklama/index.html delete mode 100644 1985/shapiro/index.html delete mode 100644 1985/sicherman/index.html delete mode 100644 1986/applin/index.html delete mode 100644 1986/august/index.html delete mode 100644 1986/bright/index.html delete mode 100644 1986/hague/index.html delete mode 100644 1986/holloway/index.html delete mode 100644 1986/index.html delete mode 100644 1986/marshall/index.html delete mode 100644 1986/pawka/index.html delete mode 100644 1986/stein/index.html delete mode 100644 1986/wall/index.html delete mode 100644 1987/biggar/index.html delete mode 100644 1987/heckbert/index.html delete mode 100644 1987/hines/index.html delete mode 100644 1987/index.html delete mode 100644 1987/korn/index.html delete mode 100644 1987/lievaart/index.html delete mode 100644 1987/wall/index.html delete mode 100644 1987/westley/index.html delete mode 100644 2011/akari/hint.html delete mode 100644 2011/blakely/hint.html delete mode 100644 2011/borsanyi/hint.html delete mode 100644 2011/dlowe/hint.html delete mode 100644 2011/eastman/hint.html delete mode 100644 2011/fredriksson/hint.html delete mode 100644 2011/goren/hint.html delete mode 100644 2011/hamaji/hint.html delete mode 100644 2011/hou/hint.html delete mode 100644 2011/konno/hint.html delete mode 100644 2011/richards/hint.html delete mode 100644 2011/toledo/hint.html delete mode 100644 2011/vik/hint.html delete mode 100644 2011/zucker/hint.html delete mode 100644 2012/blakely/hint.html delete mode 100644 2012/deckmyn/hint.html delete mode 100644 2012/dlowe/hint.html delete mode 100644 2012/endoh1/hint.html delete mode 100644 2012/endoh2/hint.html delete mode 100644 2012/grothe/hint.html delete mode 100644 2012/hamano/hint.html delete mode 100644 2012/hou/hint.html delete mode 100644 2012/kang/hint.html delete mode 100644 2012/konno/hint.html delete mode 100644 2012/omoikane/hint.html delete mode 100644 2012/tromp/hint.html delete mode 100644 2012/vik/hint.html delete mode 100644 2012/zeitak/hint.html delete mode 100644 2013/birken/hint.html delete mode 100644 2013/cable1/hint.html delete mode 100644 2013/cable2/hint.html delete mode 100644 2013/cable3/hint.html delete mode 100644 2013/dlowe/hint.html delete mode 100644 2013/endoh1/hint.html delete mode 100644 2013/endoh2/hint.html delete mode 100644 2013/endoh3/hint.html delete mode 100644 2013/endoh4/hint.html delete mode 100644 2013/hou/hint.html delete mode 100644 2013/mills/hint.html delete mode 100644 2013/misaka/hint.html delete mode 100644 2013/morgan1/hint.html delete mode 100644 2013/morgan2/hint.html delete mode 100644 2013/robison/hint.html delete mode 100644 2014/birken/hint.html delete mode 100644 2014/deak/hint.html delete mode 100644 2014/endoh1/hint.html delete mode 100644 2014/endoh2/hint.html delete mode 100644 2014/maffiodo1/hint.html delete mode 100644 2014/maffiodo2/hint.html delete mode 100644 2014/morgan/hint.html delete mode 100644 2014/sinon/hint.html delete mode 100644 2014/skeggs/hint.html delete mode 100644 2014/vik/hint.html delete mode 100644 2014/wiedijk/hint.html delete mode 100644 2015/burton/hint.html delete mode 100644 2015/dogon/hint.html delete mode 100644 2015/duble/hint.html delete mode 100644 2015/endoh1/hint.html delete mode 100644 2015/endoh2/hint.html delete mode 100644 2015/endoh3/hint.html delete mode 100644 2015/endoh4/hint.html delete mode 100644 2015/hou/hint.html delete mode 100644 2015/howe/hint.html delete mode 100644 2015/mills1/hint.html delete mode 100644 2015/mills2/hint.html delete mode 100644 2015/muth/hint.html delete mode 100644 2015/schweikhardt/hint.html delete mode 100644 2015/yang/hint.html delete mode 100644 2018/algmyr/hint.html delete mode 100644 2018/anderson/hint.html delete mode 100644 2018/bellard/hint.html delete mode 100644 2018/burton1/hint.html delete mode 100644 2018/burton2/hint.html delete mode 100644 2018/ciura/hint.html delete mode 100644 2018/endoh1/hint.html delete mode 100644 2018/endoh2/hint.html delete mode 100644 2018/ferguson/hint.html delete mode 100644 2018/giles/hint.html delete mode 100644 2018/hou/hint.html delete mode 100644 2018/mills/hint.html delete mode 100644 2018/poikola/hint.html delete mode 100644 2018/vokes/hint.html delete mode 100644 2018/yang/hint.html delete mode 100644 2019/adamovsky/hint.html delete mode 100644 2019/burton/hint.html delete mode 100644 2019/ciura/hint.html delete mode 100644 2019/diels-grabsch1/hint.html delete mode 100644 2019/diels-grabsch2/hint.html delete mode 100644 2019/dogon/hint.html delete mode 100644 2019/duble/hint.html delete mode 100644 2019/endoh/hint.html delete mode 100644 2019/giles/hint.html delete mode 100644 2019/karns/hint.html delete mode 100644 2019/lynn/hint.html delete mode 100644 2019/mills/hint.html delete mode 100644 2019/poikola/hint.html delete mode 100644 2019/yang/hint.html delete mode 100644 2020/burton/index.html delete mode 100644 2020/carlini/index.html delete mode 100644 2020/endoh1/index.html delete mode 100644 2020/endoh2/index.html delete mode 100644 2020/endoh3/index.html delete mode 100644 2020/ferguson1/index.html delete mode 100644 2020/ferguson2/index.html delete mode 100644 2020/giles/index.html delete mode 100644 2020/index.html delete mode 100644 2020/kurdyukov1/index.html delete mode 100644 2020/kurdyukov2/index.html delete mode 100644 2020/kurdyukov3/index.html delete mode 100644 2020/kurdyukov4/index.html delete mode 100644 2020/otterness/index.html delete mode 100644 2020/tsoj/index.html delete mode 100644 2020/yang/index.html delete mode 100644 index.html diff --git a/1984/anonymous/index.html b/1984/anonymous/index.html deleted file mode 100644 index d7b9011a6..000000000 --- a/1984/anonymous/index.html +++ /dev/null @@ -1,183 +0,0 @@ - - -
- - - -Anonymous
-make all
-The author was too embarrassed that he/she could write such trash, so -I promised to protect their identity. I will say that the author of this -program has a well known connection with the C programming language.
-This program is a unique variation on the age old “Hello, world” -program. What reads like a read may be written like a write!
-Copyright (c) 1984, Landon Curt Noll. All Rights Reserved. Permission -for personal, educational or non-profit use is granted provided this -this copyright and notice are included in its entirety and remains -unaltered. All other uses must receive prior permission in writing from -both Landon Curt Noll and Larry Bassel.
- - diff --git a/1984/decot/index.html b/1984/decot/index.html deleted file mode 100644 index d0d56d788..000000000 --- a/1984/decot/index.html +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - -Dave Decot
- make all
-NOTE: This entry uses non-standard args to main() that do not work -with modern compilers.
-Some new compilers disliked line 15 of the source, so we changed it -from:
-for(signal=0;*k * x * __FILE__ *i;) do {
-to:
-for(signal=0;*k *x * __FILE__ *i;) do {
-This program prints out a string of garbage.
-The judges also offer this one comment: understand comments!
-Copyright (c) 1984, Landon Curt Noll. All Rights Reserved. Permission -for personal, educational or non-profit use is granted provided this -this copyright and notice are included in its entirety and remains -unaltered. All other uses must receive prior permission in writing from -both Landon Curt Noll and Larry Bassel.
- - diff --git a/1984/index.html b/1984/index.html deleted file mode 100644 index 5d325cce9..000000000 --- a/1984/index.html +++ /dev/null @@ -1,178 +0,0 @@ - - - - - - -In 1984, the first contest was held. The name of the contest was -simply ``Obfuscated C Code Contest’’.
-Restrictions against machine dependent code were not in the rules in -1984. The source file size restriction was only 512 bytes. Rules and -results were posted to net.lang.c and net.unix-wizards.
-Copyright (c) 1984, Landon Curt Noll. All Rights Reserved. Permission -for personal, educational or non-profit use is granted provided this -this copyright and notice are included in its entirety and remains -unaltered. All other uses must receive prior permission in writing from -both Landon Curt Noll and Larry Bassel.
- - diff --git a/1984/laman/index.html b/1984/laman/index.html deleted file mode 100644 index 85d7b5959..000000000 --- a/1984/laman/index.html +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - -Mike Laman
- make all
-Some new compilers dislike lines 6 and 10 of the source, so we -changed them from:
-;++f)a[ b<<5|c] =d++,b+ =e;for( f=0;f<O
-<<5|c]^ =a[b<<5 |c]^=a[ (k-(b+1 ))<<5|c]
-to:
-;++f)a[ b<<5|c] =d++,b+= e;for( f=0;f<O
-<<5|c]^= a[b<<5 |c]^=a[ (k-(b+1 ))<<5|c]
-I hope you have the C beautifier! The program accepts ONE positive -argument. Seeing is believing, so try things like:
-laman 4
-laman 9
-laman 16
-This code should run you in circles.
-Copyright (c) 1984, Landon Curt Noll. All Rights Reserved. Permission -for personal, educational or non-profit use is granted provided this -this copyright and notice are included in its entirety and remains -unaltered. All other uses must receive prior permission in writing from -both Landon Curt Noll and Larry Bassel.
- - diff --git a/1984/mullender/index.html b/1984/mullender/index.html deleted file mode 100644 index ceec02042..000000000 --- a/1984/mullender/index.html +++ /dev/null @@ -1,201 +0,0 @@ - - - - - - -Sjoerd Mullender
-Robbert van Renesse
-NOTE: This entry is likely to fail and/or dump core on modern -computers.
-Without question, this C program is the one of the most obfuscated C -program that has ever been received! Like all great contest entries, -they result in a change of rules for the following year. To prevent a -flood of similar programs, we requested that programs be non machine -specific.
-This program was selected for the 1987 t-shirt collection.
---NOTE: If your machine is not a Vax-11 or pdp-11, this program will -not execute correctly. In later years, machine dependent code was -discouraged.
-
The C startup routine (via crt0.o) transfers control to a location -named main. In this case, main just happens to be in the data area. The -array of shorts, which has been further obfuscated by use of different -data types, just happens to form a meaningful set of PDP-11 and Vax -instructions. The first word is a PDP-11 branch instruction that -branches to the rest of the PDP code. On the Vax main is called with the -calls instruction which uses the first word of the subroutine as a mask -of registers to be saved. So on the Vax the first word can be anything. -The real Vax code starts with the second word. This small program makes -direct calls to the write() Unix system call to produce a message on the -screen. Can you guess what is printed? We knew you couldn’t! :-)
-Copyright (c) 1984, Landon Curt Noll. All Rights Reserved. Permission -for personal, educational or non-profit use is granted provided this -this copyright and notice are included in its entirety and remains -unaltered. All other uses must receive prior permission in writing from -both Landon Curt Noll and Larry Bassel.
- - diff --git a/1985/applin/index.html b/1985/applin/index.html deleted file mode 100644 index bfeb60973..000000000 --- a/1985/applin/index.html +++ /dev/null @@ -1,180 +0,0 @@ - - - - - - -Jack Applin [with help from Robert Heckendorn]
- make all
-One liner programs are short but twisted. This “Hello, World” version -certainly takes its time saying hello.
-Copyright (c) 1985, Landon Curt Noll & Larry Bassel. All Rights -Reserved. Permission for personal, educational or non-profit use is -granted provided this this copyright and notice are included in its -entirety and remains unaltered. All other uses must receive prior -permission in writing from both Landon Curt Noll and Larry Bassel.
- - diff --git a/1985/august/index.html b/1985/august/index.html deleted file mode 100644 index 23f8e9eb2..000000000 --- a/1985/august/index.html +++ /dev/null @@ -1,184 +0,0 @@ - - - - - - -Lennart Augustsson <chalmers!augustss>
- make all
-An interesting use of a recursive call to main. Compile and execute -without args. What is the initial value of b, and does it alter the -action of the program?
-If you let it, the program will continue to print a numerical -sequence (can you guess in what base it is printed?) until you run out -of memory or until they sell your computer, which ever comes first.
-Copyright (c) 1985, Landon Curt Noll & Larry Bassel. All Rights -Reserved. Permission for personal, educational or non-profit use is -granted provided this this copyright and notice are included in its -entirety and remains unaltered. All other uses must receive prior -permission in writing from both Landon Curt Noll and Larry Bassel.
- - diff --git a/1985/index.html b/1985/index.html deleted file mode 100644 index d11af2d61..000000000 --- a/1985/index.html +++ /dev/null @@ -1,179 +0,0 @@ - - - - - - -185 marked the second year of the Obfuscated C Code Contest.
-Hints against machine dependent code were added to the rules to avoid -another 1984 style winner. Rules and results were posted to net.lang.c -and net.unix-wizards. Larry Bassel was invited to help in the judging. -Awards were given to 5 classes of programs since we were unable to -select only the best 4.
-Copyright (c) 1985, Landon Curt Noll & Larry Bassel. All Rights -Reserved. Permission for personal, educational or non-profit use is -granted provided this this copyright and notice are included in its -entirety and remains unaltered. All other uses must receive prior -permission in writing from both Landon Curt Noll and Larry Bassel.
- - diff --git a/1985/lycklama/index.html b/1985/lycklama/index.html deleted file mode 100644 index 84c8d00eb..000000000 --- a/1985/lycklama/index.html +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - -Ed Lycklama
- make all
-NOTE: This entry uses non-standard args to main() that do not work -with modern compilers.
-Run the program without any arguments. Type in some very long lines -and notice how it redisplays it.
-The program itself looks like tty noise. Notice that even ‘define’ in -#define can be defined.
-NOTE: This entry requires a non-standard K&R C compiler to -compile.
-Copyright (c) 1985, Landon Curt Noll & Larry Bassel. All Rights -Reserved. Permission for personal, educational or non-profit use is -granted provided this this copyright and notice are included in its -entirety and remains unaltered. All other uses must receive prior -permission in writing from both Landon Curt Noll and Larry Bassel.
- - diff --git a/1985/shapiro/index.html b/1985/shapiro/index.html deleted file mode 100644 index 98243b829..000000000 --- a/1985/shapiro/index.html +++ /dev/null @@ -1,185 +0,0 @@ - - - - - - -Carl Shapiro
- make all
-As submitted, this program was 3 lines (2 of defines and 1 of code). -To make news & mail happy we split the last line into 7. Join them -back without the newlines to get the original version.
-This program was selected for the 1987 t-shirt collection.
-We found this program is be simply amazeing! Run -this program without arguments and notice the output.
-Copyright (c) 1985, Landon Curt Noll & Larry Bassel. All Rights -Reserved. Permission for personal, educational or non-profit use is -granted provided this this copyright and notice are included in its -entirety and remains unaltered. All other uses must receive prior -permission in writing from both Landon Curt Noll and Larry Bassel.
- - diff --git a/1985/sicherman/index.html b/1985/sicherman/index.html deleted file mode 100644 index 86bf21c00..000000000 --- a/1985/sicherman/index.html +++ /dev/null @@ -1,198 +0,0 @@ - - - - - - -Col. G. L. Sicherman
- make all
-NOTE: This entry uses non-standard args to main() that do not work -with modern compilers.
-NOTE: This entry uses non-standard args to main() that do not work -with modern compilers.
-This program abuses the C preprocessor so much that some /lib/cpp’s -fail to strip out all of the comments on the first pass! If you were -able to understand Decot’s entry in 1984, you will have a head start on -this one.
-Be sure to run this program through lint! If your lint works -correctly, it should warn you that the argument ‘Manual’ isn’t used. -Like the program says, what’s that mean?
-Run the program without arguments and enter the letters ‘a’ thru ‘m’ -on a line. Now enter the letters ‘n’ thru ‘z’. But to borrow a quote -from Richard Stallman: If you think you understand what this code does, -then you don’t, so read it again! Explain why:
-sicherman < sicherman.c | sicherman | diff - sicherman.c
-results in diff reporting a difference on some machines.
-NOTE: This entry requires a non-standard K&R C compiler to -compile.
-Copyright (c) 1985, Landon Curt Noll & Larry Bassel. All Rights -Reserved. Permission for personal, educational or non-profit use is -granted provided this this copyright and notice are included in its -entirety and remains unaltered. All other uses must receive prior -permission in writing from both Landon Curt Noll and Larry Bassel.
- - diff --git a/1986/applin/index.html b/1986/applin/index.html deleted file mode 100644 index 9c0a75110..000000000 --- a/1986/applin/index.html +++ /dev/null @@ -1,186 +0,0 @@ - - - - - - -Jack Applin
-Hewlett-Packard
-Ft. Collins
-Colorado
-USA
make all
-Compile and/or execute as directed by the documentation.
-The judges were so amused by this little program that we created an -award just for it. This program is portable to the C and Fortran 77 -compilers as well as executable by the bourne shell!
-Copyright (c) 1986, Landon Curt Noll & Larry Bassel. All Rights -Reserved. Permission for personal, educational or non-profit use is -granted provided this this copyright and notice are included in its -entirety and remains unaltered. All other uses must receive prior -permission in writing from both Landon Curt Noll and Larry Bassel.
- - diff --git a/1986/august/index.html b/1986/august/index.html deleted file mode 100644 index e14786d73..000000000 --- a/1986/august/index.html +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - -Lennart Augustsson
-Dept. of Comp. Sci.
-Chalmers University of Technology,
-412 96 Gothenburg
-Sweden
make all
-This program computes a specific mathematical value. Simply compile -and give it an infinite amount of stack space and cpu time. Otherwise -just be satisfied with the approximation displayed just before the core -dump.
-This program will pass lint on your system assuming your lint is -brave enough to try and parse it correctly.
-Copyright (c) 1986, Landon Curt Noll & Larry Bassel. All Rights -Reserved. Permission for personal, educational or non-profit use is -granted provided this this copyright and notice are included in its -entirety and remains unaltered. All other uses must receive prior -permission in writing from both Landon Curt Noll and Larry Bassel.
- - diff --git a/1986/bright/index.html b/1986/bright/index.html deleted file mode 100644 index b6c31af5c..000000000 --- a/1986/bright/index.html +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - -Walter Bright
- make all
-NOTE: The original entry may be built with “make alt”.
-Compile this program and give filenames as arguments. For example -try:
-bright bright.c
-bright bright
-Mr. Bright exploits the c pre-processor, similar variables and -excessive shifting to obfuscate an otherwise useful binary display -program. This gives you a small example of what it is like to maintain -the Bourne shell! :-}
-NOTE: To compile with modern compilers, you make need to: make -alt.
-Copyright (c) 1986, Landon Curt Noll & Larry Bassel. All Rights -Reserved. Permission for personal, educational or non-profit use is -granted provided this this copyright and notice are included in its -entirety and remains unaltered. All other uses must receive prior -permission in writing from both Landon Curt Noll and Larry Bassel.
- - diff --git a/1986/hague/index.html b/1986/hague/index.html deleted file mode 100644 index e4e8279e5..000000000 --- a/1986/hague/index.html +++ /dev/null @@ -1,190 +0,0 @@ - - - - - - -Jim Hague
-University of Kent at Canterbury
-Canterbury, Kent
-UK
make all
-Compile this program and feed ascii text into standard input. This -program is known to pass lint on some systems and abort lint on -others.
-This program was selected for the 1987 t-shirt collection.
-Think morse code when you ponder this program. Note how use of -similar variables can be obfuscating! The author notes that this program -implements the international morse standard. Now for extra credit, what -morse message does the program spell out?
-Copyright (c) 1986, Landon Curt Noll & Larry Bassel. All Rights -Reserved. Permission for personal, educational or non-profit use is -granted provided this this copyright and notice are included in its -entirety and remains unaltered. All other uses must receive prior -permission in writing from both Landon Curt Noll and Larry Bassel.
- - diff --git a/1986/holloway/index.html b/1986/holloway/index.html deleted file mode 100644 index 0344b2245..000000000 --- a/1986/holloway/index.html +++ /dev/null @@ -1,190 +0,0 @@ - - - - - - -Bruce Holloway
-Digital Research, Inc.
-Monterey, CA
-USA
make all
-NOTE: This entry uses non-standard args to main() that do not work -with modern compilers.
-Believe it or not, this is the old standard “Hello, world” program -performed in a very complex way. The judges and the author defy you do -determine how it does it. It is a good thing that K&R didn’t use -this version as the first C program!
-NOTE: This entry requires a non-standard K&R C compiler to -compile.
-Copyright (c) 1986, Landon Curt Noll & Larry Bassel. All Rights -Reserved. Permission for personal, educational or non-profit use is -granted provided this this copyright and notice are included in its -entirety and remains unaltered. All other uses must receive prior -permission in writing from both Landon Curt Noll and Larry Bassel.
- - diff --git a/1986/index.html b/1986/index.html deleted file mode 100644 index 186143b71..000000000 --- a/1986/index.html +++ /dev/null @@ -1,186 +0,0 @@ - - - - - - -The 1986 contest was named: “The Third International Obfuscated C -Code Contest”
-Copyright (c) 1986, Landon Curt Noll & Larry Bassel. All Rights -Reserved. Permission for personal, educational or non-profit use is -granted provided this this copyright and notice are included in its -entirety and remains unaltered. All other uses must receive prior -permission in writing from both Landon Curt Noll and Larry Bassel.
-The rules for 1986 suggested categories due to the success of the -1985 judging method. The maximum size was increased from 512 to 1024 -bytes. Larry Bassel joined as the second official judge.
-A poll was taken for the worst code for BSD and System V program. The -Bourne Shell (/bin/sh) won for both systems. The BSD finger program took -third place.
-Rules and results were posted to net.lang.c and net.unix-wizards. -Micro/Systems Journal published started regular publishing of the -winners. The practice of making first announcement of the winners at the -Summer Usenix BOF started this year. A notice was posted to -net.announce.
- - diff --git a/1986/marshall/index.html b/1986/marshall/index.html deleted file mode 100644 index 6cfb75c8b..000000000 --- a/1986/marshall/index.html +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - -Eric Marshall
-System Development Corporation, a Burroughs Company
-P.O. Box 517
-Paoli, PA.
-19301
make all
-NOTE: This entry uses non-standard args to main() that do not work -with modern compilers.
-This program prints the name of the picture. The layout is somewhat -pretty through it is not the usual sort of output one would expect from -printing a program!
-This program was selected for the 1987 t-shirt collection.
-This program is known to give some C compilers a problems.
-NOTE: This entry requires a non-standard K&R C compiler to -compile.
-Copyright (c) 1986, Landon Curt Noll & Larry Bassel. All Rights -Reserved. Permission for personal, educational or non-profit use is -granted provided this this copyright and notice are included in its -entirety and remains unaltered. All other uses must receive prior -permission in writing from both Landon Curt Noll and Larry Bassel.
- - diff --git a/1986/pawka/index.html b/1986/pawka/index.html deleted file mode 100644 index 72d2e1887..000000000 --- a/1986/pawka/index.html +++ /dev/null @@ -1,184 +0,0 @@ - - - - - - -Michael H. Pawka
-Naval Ocean Systems Center
-San Diego, Ca
-92152
make all
-The judges found this entry to be one of hardest to read without the
-aid of /lib/cpp and a good editor. When run, the program
-asks if it is obfuscated, of all things!
Copyright (c) 1986, Landon Curt Noll & Larry Bassel. All Rights -Reserved. Permission for personal, educational or non-profit use is -granted provided this this copyright and notice are included in its -entirety and remains unaltered. All other uses must receive prior -permission in writing from both Landon Curt Noll and Larry Bassel.
- - diff --git a/1986/stein/index.html b/1986/stein/index.html deleted file mode 100644 index afe3baf36..000000000 --- a/1986/stein/index.html +++ /dev/null @@ -1,192 +0,0 @@ - - - - - - -Jan Stein
- make all
-NOTE: The original entry may be built with “make alt”.
-Judges’ comments:
---NOTE: to avoid problems with news and mail, the single line was split -into 3 lines. Join all lines into a single line to recreate the original -file.
-
Compile and link to a filename called ‘a.out’. Try the program with -the following argument:
-a.out ^N^N
-(^N is ASCII control-N). One some machines, ML is needed -to get it to output cleanly. Your system may require another set of -characters. In time, you will figure out what it does. :-)
-NOTE: This entry requires a non-standard K&R C compiler to -compile.
-Copyright (c) 1986, Landon Curt Noll & Larry Bassel. All Rights -Reserved. Permission for personal, educational or non-profit use is -granted provided this this copyright and notice are included in its -entirety and remains unaltered. All other uses must receive prior -permission in writing from both Landon Curt Noll and Larry Bassel.
- - diff --git a/1986/wall/index.html b/1986/wall/index.html deleted file mode 100644 index 71bdb14e1..000000000 --- a/1986/wall/index.html +++ /dev/null @@ -1,195 +0,0 @@ - - - - - - -Larry Wall
-System Development Corporation
-Santa Monica
-California
-US of A
make all
-NOTE: This entry uses non-standard args to main() that do not work -with modern compilers.
-The original version did not have a ‘;’ character in the first line. -This caused a number of System V C pre-preprocessors to gripe about a -syntax error.
-This program is a masterpiece of obfuscation and humor. Larry Wall -(the hacker who gave us rn and patch) asks you to compile and consider -the warning message generated by the C compiler. Then execute the -program and type charters into its standard input. You will see why the -compiler documents the program.
-NOTE: This entry requires a non-standard K&R C compiler to -compile.
-Copyright (c) 1986, Landon Curt Noll & Larry Bassel. All Rights -Reserved. Permission for personal, educational or non-profit use is -granted provided this this copyright and notice are included in its -entirety and remains unaltered. All other uses must receive prior -permission in writing from both Landon Curt Noll and Larry Bassel.
- - diff --git a/1987/biggar/index.html b/1987/biggar/index.html deleted file mode 100644 index 95b3db012..000000000 --- a/1987/biggar/index.html +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - -Mark Biggar
-UNiSYS - System Development Group, Santa Monica
-2525 Colorado AV MD 91-01
-Santa Monica, CA
-90406
make all
-cc -DC="R>0" -DI="if(T)O" -DO="c=write(1,&c,1);" -DP="main(){X}"\
--DR="read(0,&c,1)" -DT="c!=015" -DW="while(C)I" -DX="char c;W" markb.c
-Passes BSD and UTS lint. At least one version of lint is thrown into -an infinite loop by this entry.
-... | markb | od -c (remember to compile as indicated above)
-By changing the compile line you can make this program do anything -you want. This is a very efficient way to transfer source, though it -increases the size of Makefiles.
-With only slight variations, this program can be set to many uses. -Consider how easy it would be to release Un*x source in this form; so -what if the make files grow a little! :-)
-One vendor’s lint got hung in an infinite loop over this entry!
---FYI: We will let Mark get away with this truly sick entry this time, -but for the future on we have placed a limit on the size of a compile -line.
-
Also see our comment in Larry Wall’s entry regarding Mark’s -contribution.
-Copyright (c) 1987, Landon Curt Noll & Larry Bassel. All Rights -Reserved. Permission for personal, educational or non-profit use is -granted provided this this copyright and notice are included in its -entirety and remains unaltered. All other uses must receive prior -permission in writing from both Landon Curt Noll and Larry Bassel.
- - diff --git a/1987/heckbert/index.html b/1987/heckbert/index.html deleted file mode 100644 index 8431179e1..000000000 --- a/1987/heckbert/index.html +++ /dev/null @@ -1,190 +0,0 @@ - - - - - - -Paul Heckbert
-Pixar
make all
-NOTE: The original entry may be built with “make alt”.
-ph 40 < ph.c > foo.c; cc foo.c -o ph
-ph 20 < a_C_prog.c > bar.c; cc bar.c
-The judges used this program to fold up very long lines which the BSD -fold(1) was unable to process. This program has been added to the -contest tool chest.
-On System V systems, compile with: -Dindex=strchr To
-compile on a 16 bit machine, change 300000’s to 30000.
NOTE: This entry requires a non-standard K&R C compiler to -compile.
-Copyright (c) 1987, Landon Curt Noll & Larry Bassel. All Rights -Reserved. Permission for personal, educational or non-profit use is -granted provided this this copyright and notice are included in its -entirety and remains unaltered. All other uses must receive prior -permission in writing from both Landon Curt Noll and Larry Bassel.
- - diff --git a/1987/hines/index.html b/1987/hines/index.html deleted file mode 100644 index 01027ade5..000000000 --- a/1987/hines/index.html +++ /dev/null @@ -1,195 +0,0 @@ - - - - - - -Spencer Hines
-OnLine Computer Systems
-4200 Farragut Street
-Hyattsville, MD
-20781
-USA
make all
-NOTE: The original entry may be built with “make alt”.
-hines hines.c
-This program was designed to maximize the bother function for -structured programmers. This program takes goto statements to their -logical conclusion. The layout and choice of names are classic.
-We consider this to be a beautiful counter-example for Frank Rubin’s -letter to ACM form titled: “GOTO Considered Harmful” Considered -Harmful. See the Communications of the ACM, March 1987, Page -195-196.
-NOTE: To compile with modern compilers, you make need to: make -alt.
-Copyright (c) 1987, Landon Curt Noll & Larry Bassel. All Rights -Reserved. Permission for personal, educational or non-profit use is -granted provided this this copyright and notice are included in its -entirety and remains unaltered. All other uses must receive prior -permission in writing from both Landon Curt Noll and Larry Bassel.
- - diff --git a/1987/index.html b/1987/index.html deleted file mode 100644 index ca39da7f4..000000000 --- a/1987/index.html +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - -1987 marked the “The Fourth International Obfuscated C Code -Contest”
-Copyright (c) 1987, Landon Curt Noll & Larry Bassel. All Rights -Reserved. Permission for personal, educational or non-profit use is -granted provided this this copyright and notice are included in its -entirety and remains unaltered. All other uses must receive prior -permission in writing from both Landon Curt Noll and Larry Bassel.
-The rules for 1987 suggested even more categories than in 1986. Hints -for what to do and not to do were also given in the rules. For example, -a simple excessive abuse of /lib/cpp was discouraged unless the abuse -was unusual. The mailboxes for the contest were moved from nsc to -amdahl. The practice of posting a preliminary set of rules for the next -year was started this year.
-Rules and results were posted to comp.lang.c, comp.unix.wizards with -an announcement in news.announce.important. Micro/Systems Journal -published the 1987 winners. Mark Horton included a version of the 1987 -winners in an appendix of his C book. The first announcement of winners -at the Summer 87 Usenix was helped by a small fly that danced all over -the foils.
- - diff --git a/1987/korn/index.html b/1987/korn/index.html deleted file mode 100644 index 2940032e2..000000000 --- a/1987/korn/index.html +++ /dev/null @@ -1,211 +0,0 @@ - - - - - - -David Korn
-AT&T Bell Labs
-MH 3C-526B, AT&T Bell Labs
-Murray Hill, NJ
-07974
-USA
make all
-The Judges believe that this is the best one line entry ever -received. Compile on a UN*X system, or at least using a C implementation -that fakes it. Very few people are able to determine what this program -does by visual inspection. I suggest that you stop reading this section -right now and see if you are one of the few people who can.
-Several points are important to understand in this program:
-What is the symbol ‘unix’ and what is its value in the program? -Clearly ‘unix’ is not a function, and since ‘unix’ is not declared to be -a data type (such as int, char, struct foo, enum, …) what must ‘unix’ -be?
What is the value of the symbol “have”? (hint: the value is NOT 4 -characters, or ‘h’, or a string) Consider the fact that:
- char *x;defines a pointer to a character (i.e. an address), and that the ‘=’ -assigns things is compatible types. Since:
- x = "have";
-is legal C, what type of value is “have”?
-Note that the following expressions yield the same value:
- x[3] *(x+3) *(3+x)
-since addition is communitive. What can be said about the value:
- 3[x]David Korn’s /bin/ksh provides us with a greatly improved version of -the /bin/sh. The source for v7’s /bin/sh greatly inspired this -contest.
-Copyright (c) 1987, Landon Curt Noll & Larry Bassel. All Rights -Reserved. Permission for personal, educational or non-profit use is -granted provided this this copyright and notice are included in its -entirety and remains unaltered. All other uses must receive prior -permission in writing from both Landon Curt Noll and Larry Bassel.
- - diff --git a/1987/lievaart/index.html b/1987/lievaart/index.html deleted file mode 100644 index 9476a239c..000000000 --- a/1987/lievaart/index.html +++ /dev/null @@ -1,202 +0,0 @@ - - - - - - -Roemer B. Lievaart
-VU Informatica
-Churchilllaan 173-IV
-Amsterdam, The Netherlands
make all
-NOTE: The original entry may be built with “make alt”.
-We believe that you too will be amazed at just how much power -Mr. Lievaart packed into 1024 bytes!
-This Plays the game of reversi (Othello)! Compile and run. It then -asks for a playing level. Enter 0-10 (easy-hard). It then asks for your -move. A move is a number within 11-88, or a 99 to pass. Illegal moves -(except for an illegal pass) are rejected. Then the computer does its -move (or a 0 to pass), until the board is full.
-It plays rather well, for such a small program! Lievaart had to leave -out the board printing routine, so you’ll have to take a real game board -to play it. … Also due to space-limitations (the rules for 1987 had a -limit of 1024 byes), Lievaart took out the passing-handler, which makes -its ending-game rather poor. But further it knows all the rules, uses -alpha-beta pruning, and it plays f.i. on mobility(!). Most important: it -can play a pretty good game of Reversi!
-The Author was kind enough to supply the fully functional version of -the program. The file lievaart2.c contains what the program would have -been without the size restriction. This version has the full end game -logic and displays the board after each move!
-NOTE: This entry requires a non-standard K&R C compiler to -compile.
-Copyright (c) 1987, Landon Curt Noll & Larry Bassel. All Rights -Reserved. Permission for personal, educational or non-profit use is -granted provided this this copyright and notice are included in its -entirety and remains unaltered. All other uses must receive prior -permission in writing from both Landon Curt Noll and Larry Bassel.
- - diff --git a/1987/wall/index.html b/1987/wall/index.html deleted file mode 100644 index b241f7cfb..000000000 --- a/1987/wall/index.html +++ /dev/null @@ -1,195 +0,0 @@ - - - - - - -Larry Wall
-Unisys - System Development Group Santa Monica
-9132 Kester Ave
-Panorama City, CA 91402 USA
make all
-lwall | bc | lwall
-input: x*x
-input: c^2
-lwall | bc and lwall | cat
-What we found amazing was how the flow of control was transferred -between subroutines. Careful inspection will show that the array of -pointers to functions named ‘vi’ refers to functions which seem to not -be directly called. Even so, these pointers to functions are being used -as an argument to signal. Can you determine why this is being done and -how it is being exploited?
-Some compilers complained about this file, so we changed: ‘=++I’ to -‘= ++I’.
-Copyright (c) 1987, Landon Curt Noll & Larry Bassel. All Rights -Reserved. Permission for personal, educational or non-profit use is -granted provided this this copyright and notice are included in its -entirety and remains unaltered. All other uses must receive prior -permission in writing from both Landon Curt Noll and Larry Bassel.
- - diff --git a/1987/westley/index.html b/1987/westley/index.html deleted file mode 100644 index 298fbf0cb..000000000 --- a/1987/westley/index.html +++ /dev/null @@ -1,192 +0,0 @@ - - - - - - -Brian Westley (aka Merlyn Leroy on usenet)
-Starfire Consulting
-1121 Hamline Ave. N. #17
-St. Paul, MN
-55108
-USA
make all
-NOTE: This entry requires a non-standard K&R C compiler to -compile.
-Putchar must exist in the C library and not just as a macro. If it
-fails to compile, add the line: #include <stdio.h> at
-the top of the program.
Line by line symmetry performed better than any C beautifier. Think -of if it as a C ink blot. :-)
-NOTE: This entry requires a non-standard K&R C compiler to -compile.
-Copyright (c) 1987, Landon Curt Noll & Larry Bassel. All Rights -Reserved. Permission for personal, educational or non-profit use is -granted provided this this copyright and notice are included in its -entirety and remains unaltered. All other uses must receive prior -permission in writing from both Landon Curt Noll and Larry Bassel.
- - diff --git a/2011/akari/hint.html b/2011/akari/hint.html deleted file mode 100644 index d5fe13df1..000000000 --- a/2011/akari/hint.html +++ /dev/null @@ -1,159 +0,0 @@ - - - - - - -Don Yang
-omoikane@uguu.org
-http://uguu.org/
make akari
-
-
-./akari [input_file_or_- [output_file_or_- [even]]]
-
-
-./akari < example.ppm > odd_output.ppm
-./akari - - even < example.ppm > even_output.ppm
-./akari example.ppm odd_output.ppm
-
-make akari2.c
-cat akari2.c
-
-make akari2
-
-./akari2 < akari2.c
-./akari2 rot13 < akari2.c
-
-make akari3.c
-cat akari3.c
-
-make akari3
-
-./akari3
-
-make akari4.c
-cat akari4.c
-
-./akari4
-
-
-Akari is an image downsampling utility that accepts 3 inout formats:
- -* PGM (netpbm grayscale image). Akari only accept PGM files with this
- header: P5 <width> <height> 255. Images with extra comments such as
- the ones produced by GIMP will not be parsed properly.
-
-* PPM (netpbm RGB image). Only PPM files with this header are
- accepted: P6 <width> <height> 255.
-
-* ASCII art (with end of lines in LF bytes only, not CR-LF)
-
-
-Anything that is not parseable as PGM or PPM will be downsampled as ASCII art.
- -Akari is an image downsampling utility. She accepts up to 3 arguments:
- -First argument is the input image. If it’s “-” or unspecified, Akari -will read from stdin.
- -Second argument is the output image. If it’s “-” or unspecified, -Akari will write to stdout.
- -Third argument, if specified, causes Akari to keep even pixels on even -scanlines. By default Akari will keep odd pixels on odd scanlines.
- -Examples:
- -gcc akari.c -o akari
-./akari < example.ppm > odd_output.ppm
-./akari - - even < example.ppm > even_output.ppm
-./akari example.ppm odd_output.ppm
-
-
-Akari accepts 3 input formats:
-* PGM (netpbm grayscale image). Akari only accept PGM files with this
- header: P5
This is useful for decoding some curiously interlaced images, such as -the included example.ppm
- -Anything that is not parseable as PGM or PPM will be downsampled as -ASCII art. Since the source code is formatted as ASCII art, it’s only -natural to try:
- -./akari akari.c akari2.c
-
-
-akari2.c is also a valid C program, and accepts up to 1 argument. -By default, this second program reads text from stdin and writes -expanded output to stdout. If the extra argument is specified, the -output text will also pass through a rot13 filter.
- -gcc akari2.c -o akari2
-./akari2 < input.txt > expanded_output.txt
-./akari2 rot13 < input.txt > expanded_and_rot13_output.txt
-
-
-You can combine the two programs together to have just a regular rot13 -filter:
- -./akari2 rot13 < input.txt | ./akari > rot13.txt
-
-
-Of course, we wouldn’t stop with just 2 programs, you can downsample -the source again and get yet another C program:
- -./akari < akari.c | ./akari > akari3.c
-
-
-We must go deeper:
- -./akari < akari.c | ./akari | ./akari > akari4.c
-
-
-akari3.c and akari4.c are still (mostly valid) C programs. -“gcc -Wall” will output a few warnings, but still produce output -executables. The output executables each print a message to stdout.
- -It takes quite a bit of skill and obfuscation to interleave a -C program 4 levels deep, it’s much easier to interleave something like -a brainf#$% program in a C program, for example. For comparison, a -brainf#$% program is embedded inside akari.c
- -![]() |
-© Copyright 1984-2012,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Philip Blakely
-Cambridge, UK
-pmblakely@gmail.com
make blakely
-
-
-# Zoom out and make your terminal window 53 or more lines deep
-./blakely < blakely.c | head -300
-
-
-./blakely < 3.dat | head -100
-./blakely - < 3.dat | head -40
-./blakely < evolve_to_3.dat | head -55
-./blakely < t0_3.dat
-
-
-This program plays Life, computes Pi to 16 digits -if given its own source as input, and allows to check if your garden -is a Garden of Eden, all in one source.
- -If you have enough time to spare, put the plan of your garden in a text file, -and run:
- -./blakely - < garden.txt
-
-
-This program uses a well-known algorithm in order to display pi to -fifteen decimal places. The source-layout itself demonstrates the importance of -using the correct amount of whitespace in code and the clear superiority of spaces over tabs.
- -In order to see the main feature of the code, type:
- -./blakely < blakely.c
-
-
-and wait for about four seconds before using Ctrl-C (or whatever) to end the program. The -results are best viewed in a terminal window at least 60 characters -high and wide. Alternatively, redirect the output to a separate file -(killing when necessary).
- -The program emulates John Conway’s ceullular automaton known as “The -Game of Life”, using standard input as a starting grid. The layout of -the source-code is such that it evolves to a digital representation of -the first 15 decimal places of pi after 4 time steps. This was setup -using the other feature of the program which can be demonstrated as follows:
- -./blakely - < 3.dat
-
-
-The program will first display the grid given in 3.dat, and then three -more grids (taking a few minutes to display the last). Waiting for any more grids will -take a substantial amount of time. The final grid has been put into -evolve_to_3.dat, and if you type
- -./blakely < evolve_to_3.dat
-
-
-then the 3 will reappear after three time steps.
- -As should now be clear, this use of program will attempt to evolve a given setup backwards in -time according to the Life rules. The resulting grid is clearly not -necessarily unique. The program will evolve backwards given any single -command line option.
- -When evolving forwards, the code can only be stopped by killing the -program. In the reverse direction, the code can either be killed, or -will stop if it is unable to find a grid that will evolve to the -current layout correctly. This can be seen with the sample grid -t0_3.dat, which evolves backwards by only two time-steps.
- -The input files must encode a square grid, where a space is a dead -cell, and any other character (except a newline) is a living cell. Each line must be the same -length, and end with a single newline character \n (ASCII 10), including the last line. When -designing grids, it may help to type full-stops in place of spaces, -and do a global replace afterwards. Any deviation from this format will -cause errors in the output.
- -This is only an approximation to the original Life, as it takes place -on a finite grid, with borders that are automatically killed off -before each time step. However, when evolving backwards, the resulting -grids will not cause any cells on the boundaries to come alive. -As the display is performed before killing off the borders, some -boundary cells may sometimes appear to be alive, but not be treated as -such for the following time-step, although any living cells on the -right border will never be displayed.
- -The maximum grid size is currently 99 by 99 (exceeding this will cause a -seg-fault), but changing the two 9802s to MAX_SIZE*MAX_SIZE+1 will -solve this, although some reformatting of the -code may have to be done to allow larger numbers.
- -When compiled with the -Wall -pedantic -ansi options of gcc, some -warnings suggesting extra parentheses occur (not necessary for anyone -fully conversant with operator precedence). There is one unused -variable, v, but unnamed function parameters are not permitted in ANSI -C, so naming it is necessary, and gcc no longer warns about its -existence, although earlier versions did.
- -Since the program calculates ASCII character values for display, an -ASCII based system is required to run it. Also, as mentioned above, -any system that uses anything other than a plain ‘\n’ to end a line will cause -problems when reading in files.
- -Given the finely-tuned layout required to evolve into pi, this is one of the -main obfuscations used in the code. However, running the code through the -preprocessor, expanding the defines, and applying GNU’s indent, although -making the location of functions and statements clear, by no means makes the -code entirely clear. Note that expanding out the #defines does not take the -program over the character limit. The main reason for these is to do with the -layout, since there are few places that keywords or tokens of over 2 -characters can be fitted, and requiring the first few lines to be #includes -would cause similar problems.
- -Other obfuscations used are:
- -The forwards evolution of the grid is straightforward.
- -The reverse evolution is done using a brute-force method. As far as I -know, a brute-force method is the only viable automatic approach for -general grids, although more intelligent algorithms would be possible -given more space.
- -The program starts with an empty “trial” grid and, starting from the -top-left, tries all possibilities for the neighbours of the current -cell that will cause the cell to evolve to the required state. It then -proceeds to the right and down. Thus, it only ever needs to look at -the cells below and to the right when testing. However, the already -defined cells above and/or to the left of the cell may mean that there -are no possibilities that will give the correct state, in which case -the code backtracks and tries other possibilities on previous -cells. The program knows it has a valid grid if it gets to the last -cell. If it cannot find a valid grid, the program exits.
- -Since this uses brute-force, it can be very slow. (In fact, the -various obfuscations have, at least for the gcc compiler, -caused a substantial slowdown.)
- -The “calculation” of pi was chosen purely because algorithms to find -pi are numerous, but the Game of Life is rarely (if ever?) used for -this purpose. Also, separate digits made determining the layout somewhat easier.
- -Deriving the layout was the most complicated part of the program. As is clear from -the final layout featuring pi, the grid was divided into sixteen squares, -and layouts that would evolve to each of the nine digits required were -found. (This used the three-by-five digit-layout embedded in, at first, a -nine-by-nine grid, then in larger grids, until fifteen-by-fifteen was -reached.) The fifteen-by-fifteen grids give enough blank cells around -them that the digits will not collide when evolving.
- -However, this did not allow for sufficient characters to fit the code -into. Therefore it was necessary to add some regions that would quickly die off -without expanding to collide with the digits' evolution. -Groups of cells such as singletons, pairs, and larger groups like
- -* * * * * * * * * *
- *****************
-* * * * * * * * * *
-
-
-were useful in this regard.
- -Other problems were given by keywords which need to be all in one -string, keywords requiring space after them, and -multi-character tokens. Some of these problems were dealt with by -using the #defines and #includes given in the build-script, as there -was no way to have sufficient separate lines in the code to do this -without causing many difficulties. Some rejigging of the grid’s layout -as the code was fitted into its format was also done, resorting to -trial-and-improvement in some cases. Occasional use of constructs such -as f -= -3 was made as f += 3 could not be fitted into the required format. -The fact that the borders would be killed off immediately was also helpful.
- -It should be noted that evolving a full 60-by-60 grid backwards using -this code would probably take us at least up to the heat-death of the -universe.
- -The command ./blakely - < blakely.c is therefore not recommended.
- -![]() |
-© Copyright 1984-2012,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Szabolcs Borsanyi
-Theoretische Physik
-Gaussstraße 20
-42097 Wuppertal
-Germany
-borsanyi@uni-wuppertal.de
make borsanyi
-
-
-./borsanyi < some_data_file
-
-
-./borsanyi < data.1
-./borsanyi < data.2
-./borsanyi < data.3
-
-
-This is a nice quick histogram plotter. A useful utility when you need to -look at the distribution of some data.
- -Here are some challenges:
- -You can modify the number of histogram bins and the scaling of the histogram -by editing the source. Try to find them!
- -If you look at the source you will notice that the usual array of -histogram bins is missing. The source contains no arrays and it does not -use malloc or alloca. How does it build the histogram?
- -While the input does not need to be sorted, the histogram output is sorted. -How does it put the data into buckets? Why does it fork 22 times?
- -This small piece of program is meant to be a useful tool, when -there are some data around and you need a quick glance at the -histogram. I am all too often logged in to a remote machine with -slow X connection, and a terminal-based program would be of -great help.
- -![]() |
-© Copyright 1984-2012,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
David Lowe
-434 Tenney Drive
-Rogue River, OR
-97537
-j.david.lowe@gmail.com
-http://www.pootpoot.net/
make dlowe
-
-
-./dlowe -<n_iterations> corpus1/ [...] corpus0/ < start.net > end.net
-
-NOTE: The directory entries MUST end in a /
-
-./dlowe file [file ...] < trained.net
-
-
-
-
-tar -jxf dlowe-aux-data.tar.bz2
-
-./dlowe dlowe.c < ioccc-winlose-trained.net
-./dlowe dlowe < ioccc-winlose-trained.net
-
-./dlowe xor-0/00 < xor-trained.net
-./dlowe xor-0/11 < xor-trained.net
-./dlowe xor-1/01 < xor-trained.net
-./dlowe xor-1/10 < xor-trained.net
-
-./dlowe hint.html < english-trained.net
-
-./dlowe dlowe-aux-data.tar.bz2 < png-trained.net
-
-
-This entry is a ghoulish example of a brain (dead?) neural network classifier. -It comes with a set of corpora for you to try.
- -You can create your own trained networks. For example, we trained a network -on the C code of entries that were supplied to the 20Th IOCCC.
- -The ioccc-winlose-trained.net was trained using the earlystop.pl tool:
- -rm -f ioccc-winlose-trained.net
-./earlystop.pl ioccc-winlose-trained.net ioccc_won_training/ ioccc_lost_training/ ioccc_won_test/ ioccc_lost_test/
-
-
-where:
- -ioccc_won_training/
- 1/2 of C code of the 20th IOCCC winners (except for dlowe.c from 2011)
-plus 1/2 of the C code winners from prior IOCCC contests
-
-ioccc_won_test/
- 1/2 of C code of the 20th IOCCC winners (except for dlowe.c from 2011)
-plus 1/2 of the C code winners from prior IOCCC contests
-
-ioccc_lost_training/
-1/2 of C code from entries that that did not win
-
-ioccc_lost_test/
-1/2 of C code from entries that that did not win
-
-NOTE: The above directies were not shipped and the C code from
- entries that that did not win was flushed to /dev/null.
-
-
-The earlystop.pl tool wrote:
- -training 1 to 1001...
-training 1001 to 2001...
-prior error = 56.746974766043; current error = 58.095691135305
-
-
-The resulting ioccc-winlose-trained.net file was included in the -dlowe-aux-data.tar.bz2 file in the above mentioned URL.
- -The dlowe.c was explicitly excluded from this trailing set. So this test is interesting:
- -./dlowe dlowe.c < ioccc-winlose-trained.net
-
-
-The match of dlowe.c to the lose/win trailed network was:
- -dlowe.c 0.125108
-
-
-NOTE: The non-artificially intelligent decisions of the IOCCC judges include random - quirks and their non-linear judgment calls not found in the ioccc trained network. - Just because C code is or isn’t scored highly by this network does not - mean it will win or lose a future IOCCC. On the other hand … it just might!
- -While we cannot supply you with the losing IOCCC source code, the author did supply a number -data sets on which to test:
- -We created the english-trained.net as follows:
- -./dlowe -8000 english-1/ english-0/ < /dev/null > english-trained.net
-
-english-0/
- Non-English (French) text
-english-1/
- English (non-French) text
-
-
-We created the png-trained.net as follows:
- -./dlowe -8000 png-1/ png-0/ < /dev/null > png-trained.net
-
-png-0/
- Non-png (gif) images
-png-1/
- png (non-gif) images
-
-
-We created the xor-trained.net as follows:
- -./dlowe -8000 xor-1/ xor-0/ < /dev/null > xor-trained.net
-
-xor-0/
- Data that XORs to 0
-xor-1/
- Data that XORs to 1
-
-
-This is an artificially intelligent judging tool to help the IOCCC judges. -Here’s to shorter, more frequent contests!
- -This is a multilayer perceptron (a feedforward artificial neural network) -which can be trained, using on-line backpropagation, to classify input files.
- -It has a fixed topology of 216 input neurons, 6 hidden neurons and 1 output -neuron.
- -The neurons' activation function is the logistic function 1 / (1 + e ^ -x).
- -./dlowe file [file ...] < trained.net
-
-
-To classify files, one specifies a trained network (on stdin) and one or more -files to classify. The program will output one line per successfully-classified -file to stderr, with the filename and the classification: a number between 0 -and 1.
- -The interpretation of the classification number depends on how the network was -trained, but it’s geared toward interpretation as a probability or a -confidence.
- -./dlowe -<n_iterations> corpus1/ [...] corpus0/ < start.net > end.net
-
-NOTE: The directory args must end in a / for them to work.
-
-
-To train a network, one specifies a starting network (on stdin), two or more -corpora (directories containing training data), and the number of training -iterations to run. The program will write some progress data to stderr and, -when it’s done, will serialize the updated network to stdout.
- -If no input network is given, a random new network will be generated as a -starting point (i.e. provide an empty stdin).
- -The first corpus will be assigned a target value of 1. The last will be -assigned a target value of 0. Intervening directories (if any) will be assigned -intermediate target values.
- -The learning rate is hard-coded as 0.3. No momentum factor is used.
- -The png-1 corpus was obtained by manually scraping the first results from an -https://images.google.com search for “obfuscate filetype:png”.
- -The png-0 corpus was obtained by manually scraping the first results from an -https://images.google.com search for “obfuscate filetype:gif”.
- -Results:
- -The english-1 corpus was obtained by manually scraping the first results from -a https://www.google.com/webhp?lr=lang_en search for “paris filetype:txt”.
- -The english-0 corpus was obtained by manually scraping the first results from -a https://www.google.com/webhp?lr=lang_fr search for “paris filetype:txt”.
- -Results:
- -The xor-1 corpus consists of two files containing ‘01’ and ‘10’ respectively.
- -The xor-0 corpus consists of two files containing ‘00’ and ‘11’ respectively.
- -Results:
- -The program can’t tell you anything meaningful about files with less than two -bytes in them (I’m looking at you, smr.c!)
- -You must include the trailing directory separator on training directories -(this allows the program to be portable without wasting precious bytes on -figuring out how to concatenate directory and file names…)
- -Serialized network files are only portable between systems with the same -floating-point representation and endianness.
- -Making sure not to overfit the network to the training data is a bit of a -black art. I have enclosed ‘earlystop.pl’, a wrapper script that implements -a simple ‘early stopping’ algorithm; other techniques are possible.
- -Bad input (e.g. nonexistent files, non-numeric number of iterations, etc.) -tends to result in empty output.
- -Given exactly one corpus, the program will crash or produce garbage.
- -Leaks memory and file descriptors while processing files.
- -Will crash and die horribly if it runs out of memory.
- -The Microsoft C compiler doesn’t provide a dirent API, so to get this working -on a Windows system you’ll need cygwin+gcc (tested) or a dirent compatibility -library (untested, but they do exist).
- -Backpropagation doesn’t always converge: if you play with this long enough, -you’ll eventually have a training session that completely fails to converge.
- -Zombies! (Since neural networks are modeled after BRAINS, ya know? And -corpus sounds a lot like corpse. And I have 4- and 7-year-old kids ;)
- -Neural networks are interesting, and while the math isn’t terribly difficult, -their behavior is difficult to fully understand.
- -Had some extra space in one of the major data structures, and it seemed a -shame to waste it.
- -Similarly, I think three file pointers ought to be enough for anyone.
- -Lots of magic numbers expressed in various ways.
- -Random abuse of random C trivia.
- -Some textual changes were made to maximize the classification of this program -by a network trained to recognize ioccc winners ;)
- -… but mostly zombies!
- -![]() |
-© Copyright 1984-2012,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Peter Eastman
-peter.eastman@gmail.com
make eastman
-
-
-./eastman
-
-
-Quit the program. Resize your terminal window. Run it again.
-
-
-This round program will generate a classic spherical result!
- -You will need a terminal capable of displaying coloured ANSI -characters (for example an xterm or a Terminal.app window).
- -You might also want to turn off any scrollback history. The program will -size itself to the initial geometry of your terminal.
- -If you are ambitious, make the font really small and the window really -large for hi-rez graphics!
- -This program uses ANSI graphics to recreate the classic Boing Ball demo from -the Commodore Amiga. See http://www.youtube.com/watch?v=-ga41edXw3A if you -aren’t familiar with it. Back in its day, this demo inspired lust and awe in -geeks around the world.
- -The graphics are raytraced, with procedural textures on the ball and the back -wall. I did cheat a little to simplify the calculations: it uses a parallel -projection, but textures the back wall to look as if there were a floor being -viewed in perspective. The shadow is also just part of the texture, not an -actual raytraced shadow.
- -This program automatically adapts to the size of the terminal it is running in, -so try enlarging the window to get higher resolution. Don’t resize while the -program is running, though. It only checks the size once, when it starts up.
- -To compile:
- -cc -lm ball.c
- -Portability:
- -It should be completely portable. I’ve tested with gcc on Mac OS X 10.7 and -Fedora 10. I would expect it to work in any Unix-like environment.
- -Obfuscation:
- -I have merged expressions wherever possible, making extensive use of ternary -operators, commas, return values of assignment operators, etc. The entire -raytracing computation, include ray intersection tests and procedural texture -evaluations, is a single expression involving 41 operators.
- -Variables are named alphabetically in the order they are declared.
- -The third argument to ioctl() should really be a “struct winsize”, and I should -then look up the ws_row and ws_col fields, but that makes it way too obvious -what I’m doing there. Since a winsize just contains four unsigned shorts, I -replaced it with an array. And since all the values will be much less than -32767, I further simplified the type to just short[].
- -A wonderful thing about ANSI graphics is that it produces nearly unintelligible -code. Consider the printf spec to print a single space in a desired color: -“\x1B[%dm ”. I could have done something to further obfuscate it, but it’s -already indistinguishable from line noise, so why bother?
- -There are lots of other minor obfuscations to make the code less obvious. For -example, I could have written the outer loop as while(1), but why write a 1 -when I can calculate it from the return value of usleep() instead? And I could -have written usleep(80000), but usleep(79383) just looks so much better. And -so on.
- -![]() |
-© Copyright 1984-2012,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Kimmo Fredriksson
-kimmo.k.k.fredriksson@gmail.com
make fredriksson
-
-
-./fredriksson [-icvtnk#] regexp < file
-
-
-./fredriksson -k1 -i POOT < /etc/group
-ulimit -s unlimited
-./fredriksson -k2 -t -n bofuskate < /usr/share/dict/words
-
-
-The author of this entry was making sure that it does not win the -“Best Short Program” award. On the outside, the program behaves -as an approximate grep. On the inside, it is a Burrows-Wheeler -transform decompressor that produces the source code of the actual -obfuscated approximate grep program and calls it. As an exercise, -try writing the compressor.
- -Implements a variant of grep.
- -To search regexp from file, do:
- -./fredriksson [-icvtnk#] regexp < file
-
-
-Pipes may not work, see the section Limitations.
-The options -i -c -v and -n are the classic ones:
-i Ignore case.
-c Count only, prints the number of matches, but not the matching lines.
-v Invert match.
-n Prefixes each printed line by its line number (only if
- -c was not given).
This version of grep recognizes two more options, not present in normal -grep implementations:
- --kN Permit N insertions, deletions or mismatches of characters in the
- matches (aka edit-distance). E.g. “obfuscated” matches “obfuscation”
- with one deletion and two mismatches. Likewise, “obfuscate” and
- “oversimplify” match with 7 edit operations. The default is -k0
- (i.e. exact match).
-t Add local transpositions to the set of allowed edit-operations.
- That is, “ab” matches “ba” with one transposition (swap), and
- “obfuscated” matches “bofsuact” with three swaps and two insertions,
- i.e. use -tk5 to find this.
Of course, one could construct a standard regexp that matches the same -patterns, but the problem is that such a regexp grows exponentially in -size when the number of allowed edit operations is increased.
- -This version does not recognize all regular expressions, but the -following are allowed:
- -Wild card: . (dot) matches any character.
Bracket expression: list of charactres enclosed by [ and ],
-matches any single character in the list.
Range expression: two characters separated by hyphen and enclosed in
-brackets, matches any character that is lexicographically between the
-two characters (inclusive). E.g. [a-d] is the same as [abcd].
The special characters must be escaped, if they are to be taken
-literally (i.e. use e.g. \. to match period). You might want to protect
-these with ', i.e. use 'foo\[bar' instead of foo\[bar. If you want to
-use the literal - in bracket expression, protect that too (\-),
-otherwise this is not needed. Note that the syntax differs from standard
-(?) grep a bit, i.e. in plain grep you can use ] and - in bracket
-expressions by putting ] as the first character, and putting - last.
You can use this in place of cat. Just say
- - ./fredriksson -k3 cat < file
-Like with cat, you can append line numbers too:
- - ./fredriksson -nk3 cat < file
-It is assumed that the user knows how to feed correct input to the -program. If undefined options are given, the result is also undefined. -This is a feature.
It may consume huge amounts of memory, and a stack overflow may occur.
-This results in Segmentation fault (or the equivalent of your favorite
-system, such as Bus error). This is a feature, that can be used to detect
-overly long lines in the input file, such as checking the lenght of one
-liners in IOCCC entries, just adjust your stack size to a suitable
-threshold, and search for “ioccc”, with option -vk5.
Using warning options (such as -Wall) when building gives a lot of warning,
-such as suggest parentheses around '&&' within '||', value computed is
-not used, implicit declaration of function 'putchar', implicit
-declaration of function 'getchar', control reaches end of non-void
-function and format not a string literal and no format arguments.
-Please ignore them all, since they just try to tell you that the source
-is obfuscated.
Only standard input is handled. And only if stdin comes from a file,
-i.e. pipes may or may not work. If you want to count only (-c option),
-then this shouldn’t be an issue.
The total lenght of the (preprocessed) pattern is at most
-sizeof(long)*CHAR_BIT. That does not count things like bracket expressions
-or escape chars, that is, the pattern 'a[bcd]e\.f' is 5 chars long, not
-10 chars. That does not mean that the matched substring in the standard
-input has this limit, as using the edit operations can make the string
-longer. However, no assumptions are made for sizeof(long). In fact,
-you can easily use long long instead,
Depending on the file, may require a lot of stack space. If the -program segfaults (because of this), say
- - ulimit -s unlimited
-
-
-cross your fingers, hope it is enough, and try again.
Assumes C99 standard, because of the one very long line. Most C compilers -handle this just fine even in C89 mode, though.
The code should be reasonably portable, it assumes standard ASCII codes -for each char, and that a C compiler is on $PATH; the latter is hard coded -to be ‘gcc’, but any compiler would work, provided that it supports -C99, or long lines as an extension. This code has been tested on:
- -(Btw, tcc has its roots in IOCCC…)
The initialized char array includes the source code of the real program, -as well as its name and commands to build and run it, all Burrows-Wheeler --transformed, then run-length-encoded with unary coding. The main program -extracts and builds that, and then calls it. More precicely, the command -to build is
- - gcc -O3 ag.c -o ag
-
-
-To change that you need to edit the char array p[] and (possibly) two
-specially encoded constants, -~('('*'(') and 'C'*' '-'-'.
-The extracted source (ag.c) is obfuscated as well.
(The original version also deleted the generated source and the -corresponding binary after running it, but this feature was removed -from the submitted entry.)
The code demonstrates several useful programming paradigms, such as
- -main() contains several logical sub routines,
-selected by the first argument)Algorithmically, it incorporates the following
- -As a C program, it demonstrates that
- -int, char, void …))It also shows the power of boolean logic and bitwise arithmetic.
This is the first (?) entry in the history of IOCCC, that cannot be -totally un-obfuscated by the author. This is due to the clever choice of -the actual algorithm, that is obfucated by nature, and it is an open -research problem whether a simpler algorithm exists, with the same time -complexity.
The main obfuscation comes from using only arithmetic and boolean
-(short-circuit) logic combined with recursion to remove all loops and
-if-then-else constructs (also, no ternary ?: constructs are present).
-Two’s complement representation of integers is also abused. E.g. instead
-of writing x++ or x-1, it is much better to write x=-~x and ~-x.
No numerical values, other than in the initialized char array, try
- - ./fredriksson -ck0 [0-9] < fredriksson.c
-
-
-This should print 1, as there is a numer ‘3’ in the char array (only). -You can also try
- - ./fredriksson -ck0 [0-9] < ag.c
-
-
-after running fredriksson at least once (since this generates that
-ag.c file), and this should print 0.
The source code is best viewed with cat (or using the program itself), -instead of some editor. (This is a somewhat system dependent thing.)
- -One reason for this is that the code builds (some of the) constant
-values from string literal "\b", except that the backspace \b is not
-escaped like that, the source uses the raw ascii value (010 octal) instead.
-Thus when viewing with cat or something, that backspace erases the leading
-quotation mark. Makes it appear uncompilable, and it is: if you copy-paste
-the cat output from terminal to some editor, save it, the result would not
-compile.
Some other constants are built from ASCII values of chars.
- -Besides of making the code hard to read, all this makes it also quite large.
Running it through GNU indent or bcpp (C beautifiers) does not beautify
-it a bit. In fact, indent makes it only worse (at least with the default
-options). Running it through the preprocessor does basically nothing,
-since no #defines are used.
Some abuse of the rules. The number of non-whitespace and ;, {
-and } chars is below the limit, but most of the whitespace chars are
-in an initialized character array. That is, the number of chars in the
-program exceeds the 2048 limit. However, whitespace is whitespace and
-the rules did not specify that these must be in between the statements.
-A character is a whitespace if isspace() returns non-zero value. Even
-if deleting even one of those chars breaks the program! (This does not
-apply to the generated source ag.c.)
![]() |
-© Copyright 1984-2012,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Uri Goren
-goren.uri@gmail.com
make goren
-
-
-echo "some text" | ./goren
-
-
-echo "Hello, world!" | ./goren
-
-
-In the words of René François Ghislain Magritte Magritte:
- -
One may ask the surrealist question:
- -echo 'If | is just a representation of a pipe, then how can data stuff it?' | ./goren
-
-
-However if one takes a firm stand and declares:
- -echo '| is just a representation of a pipe because I say so! So stuff it!' | ./goren
-
-
-something happens! Why?
- -This program was written in homage to Rene Magritte’s picture “La -trahison des images” (The Treachery of Images).
- -In order to show my unconditional admiration of this work, I avoided -using conditions.
- -In this work, Magritte points out that a picture of a pipe is not -a pipe. But what IS a pipe? This program tries to provide an answer.
- -Magritte’s [test for pipes](http://en.wikipedia.org/wiki/The_Treachery_of_Images} is:
- -The famous pipe. How people reproached me for it! And yet, could
-you stuff my pipe? No, it's just a representation, is it not?
-
-
-Accordingly, this program only approves pipes which can be used for -stuffing data.
- -One thing I tried to achieve is condition free programming. Many -have noted that conditions make the code harder to read and understand. -A good example would be:
- -Brent Burley’s 2004 IOCCC winner
- -That entry omits conditional statements such as “if” and “while”. -His achievement in improving clarity by omitting conditions is -impressive, but I think it can be taken further, in two ways.
- -First, conditional operators, such as ?:, && and ||, can be thrown -away. Second, using setjmp and longjmp, which are unfortunately -not in common use, might make it difficult for a novice programmer -to understnad the code without referring to the man page.
- -By removing these, the code is 100% condition free, and every -function runs its instructions in perfect order. Naturally, this -makes the program flow trivial to understand. This can be verified -by disassembling the compiled code and looking for conditional jumps -(when compiled with gcc on x86, there are none).
- -The program should compile with any C compiler, but was tested -mostly with gcc on Linux.
- -It doesn’t support 64 bits (due to integer-pointer casts, and a >>31). -It does work on 64-bit Linux, becasue all functions are below 4GB.
- -![]() |
-© Copyright 1984-2012,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Shinichiro Hamaji
-shinichiro.hamaji@gmail.com
bsoup
- -make hamaji
-
-
-./hamaji < a_nonogram_file
-
-
-./hamaji < dragon.nono
-./hamaji < random.nono
-./hamaji < soccer.nono
-./hamaji < codegolf.nono
-./hamaji < face.nono
-./hamaji < penguin.nono
-./hamaji < samurai.nono
-
-
-This program solves “Nonogram”, which also known as “Paint by Numbers”:
- -http://en.wikipedia.org/wiki/Nonogram
- -This entry roar as the Year of the Dragon: A year considered -some to be good luck. Well it was certainly true that the -IOCCC was lucky to get such a fine submission!
- -The source code is a solution to a Paint by Numbers puzzle when you -paint by C. Try your hand at solving a few of the other .nono -files and then compare your solution with this program!
- -NOTE: NONOGRAM ® is a registered Trademark and is used with permission. - See http://nonogram.com/ for more information.
- -The format of the input files are as same as this site:
- -http://codegolf.com/paint-by-numbers
- -For example, for a simple problem which shows a glider of conway’s -lifegame.
- - 1
- .
- 112
-
-1 X
-1 X
-3 XXX
-
-
-the input should be
- -1
-1
-3
--
-1
-1.1
-2
-
-
-The width and the height of an input puzzle should be less than or -equal to 60.
- -When this solver finds the problem has no solution, it prints “invalid”. -This means the problem is indeed broken. For example, this happens for -an input like
- -2
--
-2
-
-
-When this solver cannot find a solution, it prints “failed”. This -failure can happen when the problem has more than one solution or the -solver cannot solve the input problem. Here is an example input of the -former:
- -1
-1
--
-1
-1
-
-
-There are two solutions:
- - 11
-
-1 X
-1 X
-
-
-and
- - 11
-
-1 X
-1 X
-
-
-Solving Nonogram is known NP-complete, so we cannot make a solver -which solves all puzzles. However, we can write a solver which solves -most problems solvable by humans. There are a bunch of ways to write -such programs. The two most obvious approaches are:
- -The former, brute-force approach is easy to implement. However, it -works only for smaller problems (width and height should be at most 30 -or so). Similarly, using generic probabilistic metaheuristics such as -simulated annealing doesn’t work for big problems.
- -http://ccl.northwestern.edu/netlogo/models/community/Nonogram
- -By its definition, the latter works for all human-solvable -problems. The issue of the latter approach is this kind of programs -tends to be lengthy. This approach still requires some recursions. The -most difficult problems which are considered human-solvable may -require some “guesses”. For this kind of problems, we need to assume a -cell is a space or a box, go ahead some steps with simple methods, -mark the tried cell as a box (or a space if we assumed the tried cell -is a box) if a contradiction is found.
- -My program uses an approach like “Set based solver” introduced in -http://www.haskell.org/haskellwiki/Nonogram . -This should be equivalent to the combinations of simple methods (no -advanced reasoning with guess). My solver also runs non-recursive -guess for each undetermined cells. So, my program should be able to -solve most human-solvable problems (assuming humans cannot execute -deeper recursions).
- -First of all, as you see, my program looks like a nonogram puzzle -which results a dragon. This puzzle is “dragon.nono” in this -directory. Note that whitespaces in character literals, a string -literal, and around the last comment are considered as a boxed cell.
- -My program is based on bit operations for speed. Many values are -stored using negative logic (0 means on and 1 means off) to utilize -the initial value of global variables. Thus, it might be difficult to -figure out how it works.
- -My program is decently shortened, because the size of source code is -limited by IOCCC’s rule (2048 non-whitespace characters) and a lot of -characters are just wasted for numbers around the picture.
- -The three requirements (dragon, speed, and size) naturally ended up -with the well obfuscated code.
- -This program uses two C99 features. One line comments and “long long”. -GCC’s “-ansi -pedantic” check should pass:
- -$ gcc -ansi -pedantic -std=c99 hamaji.c
-
-
-I checked my program with gcc-4.6.2 on linux, llvm-gcc-4.2 on mac, and -clang-3.0 on mac.
- -Note that the behavior of scanf differs on linux and mac, but this -program supports both semantics.
- -This program should not depend on sizeof(int), sizeof(void*), ASCII, -memory layout, undefined evaluation order (e.g., a[i++]=i), etc. -This program won’t work if the size of long long literal is less than 8. -By grepping the source code of gcc
- -grep LONG_LONG_TYPE_SIZE gcc/config/*/*
-
-
-I found long long may be 32bit integers only on AVR.
- -This code is considered as a new year’s postcard in Japan. We chose -the dragon because 2012 is the year of dragon.
- -http://en.wikipedia.org/wiki/Japanese_New_Year#Postcards
- -The second author wrote the picture, and the first author did -everything else.
- -The dragon.nono, samurai.nono, and penguin.nono was written by the -second author. The soccer.nono was from a wikipedia entry. This file -is important because it requires some guesses. The random.nono file -was randomly generated. The codegolf.nono and face.nono have borrowed -from this site:
- -http://codegolf.com/paint-by-numbers
- -You can reproduce dragon.nono from hamaji.c using c2nono.pl:
- -perl c2nono.pl hamaji.c | ./hamaji
-
-
-![]() |
-© Copyright 1984-2012,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Hou Qiming
-hqm03ster@gmail.com
make hou
-
-
-./hou 'a calculator expression -- see the C Code for details'
-
-
-./hou 11/26+222/31
-
-./hou 'log((21701-19937)-(23209-21701))/log(2)'
-
-./hou 'sin(1.5708)+0.04321+log(sqrt(exp(1*1*1)))+(1+2*3)-0.4-0.6+(4+6)*(2-1+2*3)-tan(0.785398)+2*10/3*6*sqrt(16/2/2)*10+10000-1000'
-
-
-This self-documenting scientific calculator compiles clean with no -warnings under the most strict pedantic mode of gcc and clang.
- -The first example, along with the correct result appears in the -source code. What does it mean?
- -The calculator obeys the precendence rules and allows parenthesis,
- - ./hou '1+2*3'
- ./hou '(1+2)*3'
-
-
-What exactly does the text formatting do?
- -What does this evaluate to in C?
- - +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
-
-
-Comments would almost be redundant. :-}
- -Not just fancy formatted comment removed by the C Pre-processor
- -The code does not contain some simple string-encoded lookup table for calculator operations.
- -The example input and output in the C code is significant. Can you find out why?
- -The button layout in the C code is significant … not just a nice looking layout.
- -The parser is functionally equivalent to a normal arithmetic parser for all valid inputs. -For another fun challenge: try to determine how it parses the command line argument.
- -This program is designed to be self-documenting. It doesn’t just provide an -example command line. It also provides the expected output and illustrates all -supported functionality using embedded ASCII art.
- -The parser parses function names, substraction, and division as single-letter -unary operators. A bitmask encoded hash table is used to check no-ops/digits -and another hash function maps the ASCII to a function ordinal, which is then -executed by the button panel.
- -Both hash functions are found using a separate search program. Another program -is used to find a way to format one hash function as example input such that -it produces something resembling the bitmask hash table as part of its output.
- -![]() |
-© Copyright 1984-2012,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Taketo Konno
-Tokyo, Japan
-inaniwa3@gmail.com
make konno
-
-
-./konno just_a_single_argument_of_lower_case_letters
-
-
-./konno qwerty
-./konno ioccc
-./konno "the quick brown fox jumps over the lazy dog"
-
-
-This tiny program outputs what looks like a tiny keyboard.
-OK, so the letters are missing. But that is no problem because
-this program identifes the lower case letters that were pressed!
It is one of those minimal keyboards without all of those -confusing symbols keys. No shift for SHOULDING CAPS -but at least it does not have that useless caps lock key!
- -We recommend that you completely deconstruct / figure out -how this program works and does what it does. Can you -extend this program to deal with a full QWERTY keyboard? -Can you then minimize the size of that code?
- -This program ignores non-lower case letters.
- -![]() |
-© Copyright 1984-2012,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Gregor Richards
-Richards@codu.org
make richards
-
-
-./richards
-
-
-echo '10 9 8 7 6 5 4 3 2 1*p*p*p*p*p*p*p*p*p' | ./richards
-
-
-Oh no, yet another dc-style calculator? (see 2000/dlowe using an embedded Perl -interpreter and deemed Worst Abuse of the Rules). -Well, this one does it (expression calculation, that is, not the rule abuse) in a different way. -The author claims that his calculator does just-in-time compilation. -What would you do to prove or disprove his claim without attempting to unravel the source?
- -This is an implementation of the classic UNIX dc command, the reverse-polish -calculator. Actually it’s a pretty bad implementation, since it only implements -32-bit integers (well, sizeof(int)-sized integers). It only implements the -commands +, -, *, /, p (only for numbers), register stacks, macros and -comparisons. Wow, you’d think I could’ve done better in 2K of code.
- -OH! I forgot to mention! It’s a JIT.
- -Wait, don’t stop reading! I know what you’re thinking, platform-specific code -is discouraged in IOCCC. But do you see any platform-specific code? There’s no -assembler here! This JIT works on a dozen platforms, and the only -platform-specific assumptions it makes are that the stack grows down and -integers are at least 32-bit.
- -You will probably get warnings while compiling the code. In particular:
- -Platforms on which all known/tested optimization levels work with no additional -flags:
- -Platforms which work but not at all optimization levels or needing special -flags:
- -![]() |
-© Copyright 1984-2012,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Oscar Toledo G.
-Av. Sta. Cruz del Monte 9-304
-Cd. Satelite. Edo. de Mexico.
-CP. 53110. Mexico.
-biyubi@gmail.com
-http://nanochess.110mb.com/
make toledo
-
-
-./toledo
-
-# NOTE: This requires X11 to run or modifications to use layer.c on
-# Windows
-
-
-./toledo
-
-
-This two player game uses X11. The control keys can be configured by -modifying the A,B,C and D macros at compilation.
- -After a quick splash screen the objective should be clear. There -are Red, Green and Cyan tanks. A larger window can be made by altering -the source early on, right before the code gets hard to follow.
- -Like Oscar’s previous winning X11 program for the 19th IOCCC, if -you remove both the X11 include files and replace them with
- -#include "layer.c"
-
-
-you ought to be able to compile and run this program on Windows.
- - /=========\
- \==\ /==/ ||
- || || /====\ |\/=\ || //==\ ==\ |=\
- || || || || || || // || =| | |
- || || //===| || || ||=// \\=\\ ==/ |=/
- || || || || || || || \\ || User's
- \===/ \\==// || || || \\ \==// Manual
-
-
-This is a color X11 3D tank-game for two players, just compile -and run it without arguments.
- -You will see briefly a tank spinning before each level.
- -Left half of the window shows the red player view and right -half shows the green player view, the background will change to -blue when the view goes inactive.
- -The objective is to chase and destroy the other player’s tank, -there is also an aqua tank for testing your aim and getting -extra points.
- -- -Caveat: You can shoot only 3 bullets at a time. -Trick: You can fire faster if they explode on anything. -Believe it or not, it has strategy!
When only one tank remains on the field, the level will advance. -Don’t forget to destroy the aqua tank.
- -The playground is surrounded by mountains and each level is -filled with random obstacles (pyramids and cubes).
- -The bars show players energy and score, each bar shows energy -and indicates current player view (wider on the left), right -part grows with every point.
- -Keys for player 1 (lowercase):
- -Keys for player 2:
- -- -Note: Numeric keys don’t work.
If you don’t like the keys assignment, you can change it on the -the makefile.
- -This game is highly violent, when the tank explodes you can -see the little stick man blowing in parts.
- -Not really, just kidding :D
- -Uses the +++, +- and *+ undocumented C operators :P
- - ....,,,,---++++++--,,..
- .,,,....... .$@@@@@@@@@@@@$$@@@@@@@@@@@@@@#+
- @@@@@###@@@@$$$@@@@$$$@@@-......-@+......,,,,,,##
- =++==++++++++=@@$==#$$$$$---,,,,@@@,,,,,,-------@@,..........,,.
- ,===#$$$$$$###$####=======@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+=##$@@@@@@@@.
- +@,,++++++++=+=========++++===++++++++++-+++@@-,,,,,,,,---+++=++++--,,... @.
- .@. .......,,,,-----++=@=++==@$=+--,,... @.
- $# S P O I L E R .,,-#@--,,,@$..... @.
- .@ ..,--+==++-,,,,.,,,,=@+++++====+++++---,,,....@.
- @+ ..,,-+++++++-,,.. @. ....,,,,,---+@@
- ,@ ..,--+++=+++,,.. $# .==+
- @#--++==++-,,.. ,@ S P O I L E R .==+
- ,#@@$+,,. @. ==+
- .,,+++++,,. S P O I L E R $= +=+
- ..,-==++-,. ,@ ---
- .,-+=+++,.. @. .++-
- .,,++=++-,. @+ ==+
- .,-++==+-,. +@ ==+
- ..,+++=+-,.. .@. +=+
- .,-+++++,@@==
-When I started working on this program, I figured that it would -be easy to fit on the character limit, but I missed three -things, the enormous X11 names, the unportable keycodes and my -2 KB of artwork.
- -Very hard coding did the first thing, in fact I worked out -twenty-nine different versions, at one step I had four -parallel versions with different characteristics removed -(mountains, horizon line, score/status bars and explosions), -I’ve managed to fit it all together!.
- -The second thing was solved using the makefile, it is under -160 bytes and you get adjustable keyboard. The greatest -mistery on the earth is why X11 handles unportable keycodes to -the user.
- -And finally, the third “Thing” was growing and growing, and -growing, eating bytes for lunch… after endless rounds of -crunching I obtained three-hundred seventy-eight bytes of -artwork and guess what?, it doesn’t fitted.
- -So I had to integrate a decompressor, based on the space, -tabulators and other non-counted characters.
- -The final program is composed of eight microfunctions, one is -the core and does most of the hard work, other functions help -doing the X11 things, explosion effects, 3-D calculations and -viewing.
- -The source code was formatted as an cube using a specially -written program, the reality is that the program is smaller and -obfuscated of what is needed so the reformatting doesn’t -exceeded the character limits, the crunched vectors were -generated by another special program and the tank that -surrounds this text was generated by yet another program.
- -Have fun!
- -![]() |
-© Copyright 1984-2012,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Daniel Vik
-802 Durshire Way
-Sunnyvale, Ca 94087
-daniel@vik.cc
-http://www.danielvik.com
make vik
-
-
-./vik file.mod > audio_file.raw
-
-
-./vik randowan.mod | mplayer -demuxer rawaudio -
-./vik mad_world.mod | mplayer -demuxer rawaudio -
-
-
-Alternatively, you can use
- -./vik file.mod > file.raw; ./raw2wav file.raw > file.wav
-
-
-It is possible to download a number of Mod files from The Mod Archive.
- -The randowan.mod and mad_world.mod files were created by -Henrik Bertilsson and -are included with his permission.
- -This entry converts .MOD audio files to a playable stream -in a most pleasing manner if you don’t like tremolo or vibrato.
- -Also it abuses the C compiler and/or assembler with a partially -initialized 32 MByte array. Can you tell what is that partial -initilzation for?
- -Does it take your system a long time to compile? You may want to do try:
- - cc -S vik.c
-
-
-and to examine the resulting assembly file vik.s. On some platforms -the assembly file is about 128 MBytes in size!
- -In 1987, Karsten Obarski changed the way music was handled in games and -demos with the introducton of the MOD file format on Commodore Amiga.
- -A MOD file contains a set of samples, a number of patterns indicating -how and when the samples are to be played, a list of what patterns to -play in what order, and a number of effects.
- -This program converts MOD files created with the standard trackers for -Amiga, e.g. Pro Tracker, Noise Tracker and Sound Tracker to raw 16 bit -44.1kHz stereo audio. The program supports MOD music with 4, 6, and 8 -channels MOD files with up to 31 samples.
- -The MOD format includes many effects for each audio channel and this -program supports most of them, including:
- -Due to size constraints tremolo and vibrato is not supported. Also, to -avoid infinite long songs, the position jump feature is ignored.
- -With his permission, the package incldues two songs composed by Henrik -Bertilsson, also known as Deelite:
- -Compiling for *nix systems (including cygwin) is straight forward:
- -$ gcc -o vik vik.c
-
-
-$ ./vik mad_world.mod > audio_file.raw
-
-
-$ ./vik randowan.mod | mplayer -demuxer rawaudio -
-
-
-(Don’t forget the last ‘-’ as it makes mplayer read from stdin.)
- -The IOCCC rules did not put a limit on the entropy of the source code, -and it appears that the general entropy rules doesn’t apply. An estimate -is that the code density entropy of this entry is ~1.2 which means that -there are around 2500 characters of code carrying information, yet there -are only 2037 IOCCC characters of actual code. Most of the additional -characters are encoded with non-counting characters in the frequency -table. But there are also ~50 or so white space characters spread out -through the source code that carry information.
- -The use of macros certainly adds to the obfuscation but the reason for -using them is mainly to fit as many features as possible within the size -limits. So please excuse the use of them.
- -Once the preprocessor is run, the code gets more interesting. The MOD -player is basically a register based state machine and all the magic is -hidden in a fog of short statements. Many of the register updates are -conditional and the program uses the ? operator (sigh) mainly to save -space, but also to leverage the comma operator and precedence more -efficiently.
- -The progam is portable to most platforms. The only system dependency is -that the program relies on writing binary data to stdout.
- -Microsoft compilers adds a carriges return to newlines, and to compile -the program with this platform, the following line can be added after -the main declaration in order for the program to run correctly:
- -_setmode(_fileno(stdout), 0x8000);
-
-
-The program only runs when a valid MOD file is passed as argument. If -no argument is passed, the program crashes.
- -![]() |
-© Copyright 1984-2012,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Matt Zucker
-mzucker1@swarthmore.edu
-http://www.swarthmore.edu/NatSci/mzucker1/
make zucker
-
-
-./zucker > image.ppm
-
-
-./zucker "Hello!!!" > hello.ppm
-./zucker faster\! -preview > image2.ppm
-
-# Display the PPM image with your favorite image viewer
-
-
-The rendered image is centered and is output as a 600 by 220 pixel PPM. -The vector font is proportional.
- -This entry uses no local variables. None! At! All!
- -This program makes pretty pictures. To see the default output, try -running
- - ./zucker > image.ppm
-
-
-On the author’s 2.5 GHz MacBook Pro, this command takes approximately -1 minute and 18 seconds to run – your runtime may vary. You will -need an image viewer capable of displaying Netpbm images in order to -display the output. On the Mac, Xee -works well; otherwise ImageMagick -and/or GraphicsMagick are both -capable of displaying Netpbm files, and are available on multiple -platforms. (Using Xee is particularly nice because it periodically -reloads the image as it is rendered.)
- -Aside from the default image, you may create your own by running the -program as follows:
- - ./zucker "your text" > image.ppm
-
-
-To mitigate long runtimes, the program can be invoked in a “preview”
-mode by appending -preview to the command line arguments, like so:
./zucker faster\! -preview > image.ppm
-
-
-If your platform distinguishes between binary and text streams, you
-may need to insert some code to reopen standard output in binary mode
-at the start of main. An ASCII platform is assumed.
This program is quite suitable for the inexperienced programmer, due -to a number of considerations:
- -It is fairly short: just 4 preprocessor directives followed by 29 -lines of source.
It compiles cleanly as ANSI C under gcc 4.2.1 with very strict -compilation flags.
It uses a very small subset of the keywords available in C, namely
-char, float, int, typedef, struct, for, and return.
-More difficult concepts such as void, if, switch, and
-while are eschewed for simplicity’s sake.
It also uses a very small number of library functions: just putchar,
-cos, sin, atan2, sqrt, and pow.
New programmers often prefer to use global variables when -possible. Hence, all variables in this program (aside from -function parameters) have global scope.
An important aspect of the computation is graphically illustrated -by the source code itself: the geometric construction of a -reflection ray at an object’s surface, given the incoming -direction and surface normal.
The program is not quite a traditional ray tracer, but a “sphere -tracer” which uses distance fields to encode proximity to objects in -the scene. Using sphere tracing to compute visibility instead of -analytic ray tracing provides two advantages: first, it greatly eases -the computation of ray-torus intersection (which would otherwise -require solving a quartic polynomial), and second, it makes it -possible to compute ambient occlusion (which is used to generate soft -shadows). Unlike many traditional ray tracers and sphere tracers, this -one uses iteration instead of recursion to compute the effect of -reflections. This, unfortunately, resulted in the programmer going -insane; however, program size was reduced and readability -hindered. Neither the plaintext for the program’s default output nor -for the Netpbm header appears in the program source, which hinders -readability as well. Also, unlike some previous IOCCC entries which -render ASCII text, this one uses a vector (as opposed to raster) -font. Although the program does not generate uppercase letters, it -handles them in a reasonable manner when they appear in the input.
- -Even when the program is pretty-printed and preprocessor macros are
-expanded, it should be fairly resistant to analysis due to reckless
-reuse of global variables, to the inherently opaque nature of the
-math, and to its overall density. Global variables are used to store
-the results of intermediate computation. As a result, seemingly simple
-functions have important side effects. Although some of the global
-variables are simply constants, their use is overloaded. For instance,
-the variable X is used both as the number 40 and as the ASCII
-character '('. Maintainability is hindered due to hardcoding
-several aspects of the program in multiple locations. As an example,
-it is impossible to modify either the image width or height without
-changing the source in at least three different places, including
-inside the large string literal.
Some of the functions are simple vector algebra operations such as -vector construction, dot product, and normalization. However, it was -found to be much more compact to define a single operation for -multiply-and-add rather than to have separate functions for addition, -subtraction, and scaling. Again, compactness led to obfuscation.
- -This program heavily abuses for loops. The comma operator is used to
-get as much milage as possible out of statements inside of loop
-declarations. Between for loops, the comma operator, and the ternary
-operator, it was possible to avoid if and while altogether.
Bitwise and arithmetic operators are used instead of logical operators
-whenever gcc doesn’t warn about it. Conversely, integer
-multiplication, division, and modulus are sometimes used in place of
-traditional bitwise operators just to keep the reader on his or her
-toes. Automatic casting between characters, integers, and floats is
-performed just about everywhere. Fascinatingly, this doesn’t seem to
-affect performance too badly. Sometimes when an explicit cast
-(i.e. from float to int) is needed, the program instead simply assigns
-to a free variable of the desired type instead. Both the array[index]
-and index[array] notations are used interchangably throughout the
-program.
Two other programs were written to support development of this -program. The first used a randomized search algorithm to deduce the -most compact encoding of the vector font instructions into ASCII; the -second used a modified form of the Knuth-Plass algorithm to layout the -final text on top of a hand-generated ASCII “stencil”. The programs -were not submitted as entries for this year’s IOCCC, not because they -lack obfuscation, but because neither is written in C (they are in C++ -and Python, respectively).
- -![]() |
-© Copyright 1984-2012,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Philip Blakely
-Cambridge, UK
-pmblakely@gmail.com
make blakely
-
-
-./blakely "RPN formula" resolution > output.gif
-
-
-./blakely "xx*yy*+" 64 > paraboloid.gif
-
-./blakely 9 32 > empty.gif
-
-time ./blakely 0 250 > flat.gif
-
-
-Several IOCCC themes (RPN calculator, animated GIF generator, ray tracing) in one package! Very impressive!
- -The checkerboard pattern in the output can be broken. Could you figure out how?
- -Larger GIF files confuse some image viewers.
- -This program renders a generic RPN expression in ray-traced animated GIF form. -The expression in spatial variables x and y is specified on the command-line with the required resolution, -and an animated GIF showing a fly-around of the resulting surface is output to stdout.
- -The program should be run as:
- -./blakely xy* 32 > pic.gif
-
-
-where the first parameter is a RPN expression, and the second is the width of the required GIF, up to a maximum of 250.
- -The expressions are written in Reverse Polish Notation with the following characters recognised:
- -NB all arithmetic is done in double precision, so 23/ is two-thirds, rather than 0
- -The surface plotted corresponds to -1 <= x,y <= 1 and for best results, the generated z value should lie between -1 and 1.
- -If there is a division by zero, square-root of a negative number, or similar operation, then the results are undefined.
- -For test-runs, use a resolution of 32. For simple expressions, the GIF generation should take only -a few seconds with a modern processor and full optimization. Run-time scales as O(N3) with resolution N, -and more complex expressions take longer to compute. For example, increasing the resolution of ripple.gif -to 250 took ~35 minutes to render on an i7 processor.
- -./blakely xy* 32 > saddle.gif
-
-./blakely xx*yy*1++d5*ct/ 64 > ripple.gif
-
-
-A generic root-finding algorithm to find the point of intersection between a ray -and the surface is done using a simple forward search from the eye. -In order to make the rendering realistic, both the value of the expression, and its derivative with respect to x and y must be tracked. -This is done using an obvious stack-based approach.
- -Much of the obfuscation is achieved through the use of single-letter variables and #defines. -The characters output for the GIF format are generated in myriad and wonderful ways, making use -of XOR, return values from putchar, and odd expressions. -The layout is in the form of X Y Z.
- -ASCII is assumed since many bytes for the GIF output are generated from characters given in the source code. -On compilation a few warnings about parentheses come up when using gcc 4.6.3, and one about no return value from main() (who uses exit codes anyway?), -but clang 3.1 emits no warnings.
- -(Note that the author may or may not be able to answer all of the above questions.)
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Alex Deckmyn
-alex.deckmyn@gmail.com
make deckmyn
-
-
-# A shell interpreter with proper backtick interpolation is required
-./deckmyn "`cat deckmyn.c`" "`cat musicfile.txt`" > sheetmusic.pbm
-
-
-./deckmyn "`cat deckmyn.c`" "`cat example_greensleeves`" > greensleeves.pbm
-
-
-The C of this entry is definitely sharp. The program cleverly uses its own -source at runtime to define the notes, time signature and accidental bitmaps.
- -In addition to sheet music, this program is also able, given the right input, -to generate an image of a 10-pin DIP chip (a sound processor?).
- -Ironically, the way this entry is called from the command line is an abuse of C Shell. -Please use Bourne-family shells to run this entry.
- -You need the source code and example input (either one of the example files, or manual input as below) ready. And a program capable of showing .pbm bitmap format.
- -./deckmyn "`cat deckmyn.c`" "`cat example_greensleeves`" > greensleeves.pbm
-display greensleeves.pbm
-
-./deckmyn "`cat deckmyn.c`" "KF m44c4 c4 g4 g4 : a4 a4 g2 :; " > short_bass.pbm
-display short_bass.pbm
-
-
-Every major C competition should have an entry capable of producing C major. -This is a music notation program. It produces bitmaps (.pbm) of music based on ASCII input. A full manual is added as a separate file. Some musical examples are also included.
- -The program is capable of printing notes, rests, (double) bar lines and accidentals on a single melodic line (multiple staves). No chords, polyphony etc.
- -The program expects two command line arguments. The first is a (very long) string that contains the complete music font. Note that it should not be given as a file name! The default music font is encoded in the (whitespace of the) source code deckmyn.c itself. Therefore, the first argument should be “cat deckmyn.c”.
The second command line argument is the music itself. This is, again, a string, not a file name. All music signs are entered as tokens of exactly 3 characters. The code is very sensitive to bad spacing! So for instance, if you use a file to write the music (e.g. example_greensleeves), you should keep in mind that newline is also a character!
- -To minimise the memory footprint, this program has no variable declarations at all, except for the arguments to main(). The only available memory space is from the command line arguments and count (argv and argc). Parts of argv are cast as integer when values under 0 or beyond 127 are expected.
- -The “music font” is defined by the source code itself. The first few lines are not part of the font definition, as this memory space will modified by the program. (So as required by the rules, it is only a (memory) copy of the source code that is modified.)
- -As there is no memory available, output is directly to stdout, byte by byte, from the top left to the bottom right pixel.
- -The memory locations of argv are used for various purposes. Therefore, the program name (default “deckmyn”) must be at least 4 characters long, including possibly the path. This, along with the ending ‘\0’, gives minimum 5 bytes of useful memory space. Otherwise, the program may attempt to write outside the string.
- -The code is quite sensitive. Errors in the input can lead to strange results. The code does not read beyond the end of the music input, but that is about the only error checking available. Any input that is not according to the rules in the MANUAL, may cause errors.
- -The program has no special hardware limitations or requirements, other than 8bit char (signed or unsigned) and two’s complement negatives.
- -The limitations of using char as counters for e.g. the number of music staves are minor. 127 staves to a page is rather a lot.
- -The code has no declared variables other than the command line variables. Not even pointers (we all know how messy code can get with too many pointers!). As more than one variable needs values beyond 127, parts of the command line memory are cast as integer using a macro.
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
make dlowe
-
-
-./dlowe
-
-
-./dlowe
-# Watch for a while if you like, then press a key within the window
-# Use up and down keys to escape death
-
-
-The judges lose playing this game. This entry wins!
- -OS X users running Mountain Lion and later will need to download and install:
- -http://xquartz.macosforge.org/landing/
-
-
-Q: How did we get past the variadic macro problem on a Mac?
- -A: Don’t use -pedantic-errors in the Makefile.
- -This is a challenging, fast-paced arcade game, based on the famous Game of -Life.
- -In the game, you are Mr.C, a lightweight spaceship making a futile dash for -escape from the rigid rules and predictability of life in the B3/S23 universe.
- -Use the up and down arrow keys to steer: collisions are fatal for Mr.C! Learn -to spot incoming gliders, skim the surfaces of beehives and blocks, and give -blinkers plenty of space. Things get crazier as Mr.C picks up speed… can he -escape?
- -No. There is no winning. Sadly for Mr.C, this universe goes on forever. Just -see how far you can make it!
- -Press ‘q’ any time to quit.
- -The code is formatted into a 14-cell shape which will evolve into a glider in -19 generations.
- -Lots of globals, including a global struct whose members have the same names -as global variables.
- -Global variables getting reused in different contexts.
- -Huge and convoluted expressions, abusing ternary operators and operator -precedence.
- -Lots of magic numbers, abuse of the relationships between magic numbers, and -abuse of the arithmetic properties of magic numbers.
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Yusuke Endoh
-mame@ruby-lang.org
-https://github.com/mame/
make endoh1
-
-
-./endoh1 < configuration.txt
-
-
-./endoh1 < endoh1.c
-
-./endoh1 < pour-out.txt
-
-./endoh1 < fountain.txt
-
-
-Let’s play Jeopardy!
- -Bzzzt!
- -Such heavily squeezed fluid simulation (this is parsed uniquely -as fluids are not squeezable) has a few quirks that the judges were -happy to experiment with.
- -One configuration file was inspired by an XKCD what if? entry.
- -DO NOT FORGET “-DG=1 -DP=4 -DV=8” and make your terminal window larger -than 80 x 25.
- -gcc endoh1.c -DG=1 -DP=4 -DV=8 -D_BSD_SOURCE -o endoh1 -lm
-./endoh1 < endoh1.c
-./endoh1 < logo.txt
-./endoh1 < column.txt
-./endoh1 < pour-out.txt
-./endoh1 < tanada.txt
-
-
-,___. ,. ,. ,. ,___. ,. ,. ,.
-|/--' || `' || |/--' `' || |\_.
-|\__. || ,. ,. ,. ,__/| |\__. ,. ,____. ,. ,. || ,_. |/-' ,_. ,__.
-|/--' || || || || |/-\| `--\| || |/\/\| || || || ,/-\. || ,/-\. |/-\.
-|| || `\_/| || |\_/| ,__/| || |||||| `\_/| || `\_/\.`\_. `\_/' || `'
-`' `' `--' `' `---' `---' `' `'`'`' `--' `' `-'`' `-' `-' `'
-
-
- ,.,. ,.,.
-,/\/\. ,. ,. ,. ,/\/\. ,. ,. ,__.
-|||#/' || `' ,_.|| |||#/' `',_.,__. || ||\\. ,.
-|||#\. || ,. ,. ,.,/#||| |\//\. ,.|#||##| ,. ,. || ,.,. |\/-' ,.,. ,.|\.
-|\/--' ||,/\.|| |||#/\/| `\#||| |||#||/\|,/\.|| ||,/'`\.|#| ,/'`\.|\/-\.
-`\| ||`\#||| |||#||\| ,//\/| ||`\|||||`\#||| ||`\.,/\/\|,.`\.,/'`\| `'
- `' `' `-'`' `'`-'`-' `-'`-' `' `'`'`' `-'`' `' `'`--'`'`' `'`' `'
-
-
-,_.,_. ,. ,. ,. ,_.,_. ,. ,. ,.
-|#||#| || `' || |#||#| `' || ||,_.
-||\/#| ||,. ,. ,.,_.,/| |\||#| ,.,_.,__.,. ,. || ,.,. |||#| ,.,. ,.,_.
-|||##| |||| || |||#||#| |#||#| |||#||##||| || ||,/||\.||`-',/||\.|||#\.
-||`--' ||`\_.|| |||\||#| |#||#| ||||'||\|`\_.|| ||`\||#|`\.,.`\||/'||`--'
-`' `' |#||| `'|#||#| |#||#| `'`' `'`' |#||| `' |||/' |||| |||| `'
- `-'`' `-'`-' `-'`-' `-'`' `'`' `'`' `'`'
-
-
-This program is a fluid simulator using “Smoothed-particle hydrodynamics (SPH)” -method.
- -http://en.wikipedia.org/wiki/Smoothed-particle_hydrodynamics
- -The SPH particles represent the fluid flow. Particles have information about -the position, density, and velocity. In every simulation step, they are -changed by pressure force, viscosity force, and external force (i.e., gravity).
- -This program reads a text from standard input, and uses it as an initial
-configuration of the particles. The character # represents “wall particle” (a
-particle with fixed position), and any other non-space characters represent
-free particles.
The compilation options -DG=1 -DP=4 -DV=8 represent, respectively, the factor
-of gravity, pressure, and viscosity. By changing their values, you can see
-different fluid behavior.
“Marching square”-like algorithm is used to render the particles.
- -http://en.wikipedia.org/wiki/Marching_squares
- -The program requires a C99 compiler; it uses complex types and one-line
-comments. It also uses usleep, which may require -D_BSD_SOURCE or somewhat
-to build with no warning. Under these conditions, it should be portable.
-At least, recent compilers with -std=c99 -Wall -W -Wextra -pedantic says
-nothing.
gcc -DG=1 -DP=4 -DV=8 -D_BSD_SOURCE -std=c99 -Wall -W -Wextra -pedantic endoh1.c
-clang -DG=1 -DP=4 -DV=8 -D_BSD_SOURCE -std=c99 -Wall -W -Wextra -pedantic endoh1.c
-
-
-I expect it to work in any Unix-like environment. VTxxx/ANSI sequences are -used to clear screen and move cursor to home.
- -I’ve tested with gcc-4.6.3 and clang-3.0 on Linux (Ubuntu 12.04)
-and gcc-4.5.3 and clang-3.1 on Cygwin. On Cygwin, gcc and clang complain about
-a usage of I (complex’s imaginary unit), but I bet this is cygwin’s issue;
-it is surely a C99 feature.
First of all, the source code itself serves as an initial configuration.
-Preprocessing directives (such as #include)’s # serve as walls.
This program uses double complex to represent any 2D vector. But, note that
-x-axis and y-axis is swapped (real axis = y-axis, imaginary axis = x-axis).
-The purpose of swapping is not only obfuscation, but also short coding: for
-example, to add gravity to total force, force += G suffices, rather than
-force += G*I.
-(Incidentally, you can exert horizontal gravity by using, such as, -DG=I)
Every five entries of double complex a[] contain information of one particle:
-position, wall-flag, density, force, and velocity, in turn.
You can use G, P, and V as a guide to find the calculation code of
-gravity, pressure, and viscosity forces.
Though some assignments may look meaningless, it is actually meaningful; it -extracts “integer part of real part” from a complex value by assigning (and -casting) it to an integer-type variable.
- -“logo.txt” is a source of the logo in this remark file.
- -“column.txt” is a water column collapse, which is a popular demo of SPH.
- -“pour-out.txt” pours you a cup of tea.
- -“tanada.txt” simulates “Terrace farming”. (“Tanada” means a “terraced rice -fields” in Japanese.)
- -“clock.txt” is a “water” clock created by HAMANO Tsukasa.
- -Other *.txt files are due to the judges.
- -“endoh1_color.c” is a variant that shows the density by using terminal 256 -colors.
- -I would like to thank my wife @hirekoke for her teaching me the SPH method.
- -The judges ordered suggested creating a color version
-after the judgment.
The judges and HAMANO Tsukasa (The silver medalist at this IOCCC) kindly -provided many configuration files.
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Yusuke Endoh
-mame@ruby-lang.org
-https://github.com/mame/
make endoh2
-
-
-./endoh2 > pi.c
-gcc -o pi pi.c
-./pi > 314.c
-...
-
-./endoh2 e > e.c
-gcc -o e e.c
-./e > 271.c
-...
-
-
-make pi
-make e
-make everything
-
-
-A pi/e printing quasi-quine in ASCII art with a compressed font in it; -what else to wish for in this program? Virtual machine emulation?
- -Yeah, “Again”. Sorry. But I don’t feel guilty or uncomfortable.
- -This entry is based on ‘over-used themes’ such as self reproducing -program and pi or e computation. I know you’re tired of them.
- -But have you ever seen all-in-one?
- -This program generates a new program in the shape of the Greek letter
-pi. Then, the generated program:
One more thing… When you give a command line option “e” to the -first program, the generated one will compute Napier’s constant -rather than pi.
- -This program itself is in the shape of a spigot. This is derived
-from analogy with “spigot algorithm” which infinitely computes the
-value of a mathematical constant such as pi or e.
http://en.wikipedia.org/wiki/Spigot_algorithm
- -The two sets of programs, 314*.c and 271*.c, are almost the same -except its shape and constant computation part. I tailored the -common part to parse in both shapes (“3.14…” and “2.71…”), by -tweaking the computation order and adding meaningless code fragment.
- -On the other hand, to make it fit inside one screen (80 x 25), my
-program is shortened properly, more than it looks. (As you may
-know, Quine needs to make its program size doubled.)
-For example, this program involves 3x5 bitmap font data of ten
-characters (‘0’ – ‘9’), as just 20 bytes: “G1%xJ{;Q7wunmuGuu%uu”.
-We can decode character n as 275*s[n+10] - 8*s[n] - 8. I solved the
-system of Bezout’s identities to find the magic string, with the
-aid of a brute force. See find-font-table.rb in detail.
http://en.wikipedia.org/wiki/B%C3%A9zout's_identity
- -I used many other tricks for short coding.
- -I’m sorry that many ASCII-art-style winning entries of IOCCCs -ignore preprocessor directives. In my program, #include is a part -of ASCII-art with comment padded.
- -These design requirements made my program well-obfuscated -willy-nilly.
- -I expect it to work in any major environment and C compiler. -To build with no warning, it requires two C99 features: string -literal more than 509 characters and omissible return in main -function. In fact, recent compilers with “-std=c99 -Wall -W --Wextra -pedantic” would say nothing.
- -gcc -std=c99 -Wall -W -Wextra -pedantic spigot.c
-clang -std=c99 -Wall -W -Wextra -pedantic spigot.c
-
-
-I’ve tested with gcc-4.6.3 and clang-3.0 on Linux (Ubuntu 12.04) -and gcc-4.5.3 and clang-3.1 on Cygwin.
- -gcc endoh2.c -o endoh2
-
-./endoh2 > pi.c
-cat pi.c
-
-gcc pi.c -o pi ; ./pi > 314.c ; cat 314.c
-gcc 314.c -o 314 ; ./314 > 3141.c ; cat 3141.c
-gcc 3141.c -o 3141 ; ./3141 > 31415.c ; cat 31415.c
-gcc 31415.c -o 31415 ; ./31415 > 314159.c ; cat 314159.c
-gcc 314159.c -o 314159 ; ./314159 > 3141592.c ; cat 3141592.c
-etc...
-
-./endoh2 e > e.c
-cat e.c
-
-gcc e.c -o e ; ./e > 271.c ; cat 271.c
-gcc 271.c -o 271 ; ./271 > 2718.c ; cat 2718.c
-gcc 2718.c -o 2718 ; ./2718 > 27182.c ; cat 27182.c
-gcc 27182.c -o 27182 ; ./27182 > 271828.c ; cat 271828.c
-gcc 271828.c -o 271828 ; ./271828 > 2718281.c ; cat 2718281.c
-etc...
-
-
-You can do make everything for the process (with no cat).
Note: The executable may return a failure (non-zero) exit status -unless -std=c99 option is given.
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Aaron Grothe
-2205 South 51st Street
-Omaha, NE 68106
-US
-ajgrothe@yahoo.com
David Madore
-http://www.madore.org/~david/
make grothe
-
-
-# To create a shared secret shared among M people with N+1 needed to reconstruct
-./grothe -secret 1-/dev/urandom 2-/dev/urandom ... N-/dev/urandom \
-1+shared1 2+shared2 ... M+sharedM
-
-# To reconstruct the original (an arbitrary combination of N+1 or
-# more shared files with their proper numbers)
-./grothe I-sharedI J-sharedJ K-sharedK ... +reconstructed
-
-
-./grothe -grothe.c 1+grothe.c.1 2+grothe.c.2
-
-./grothe -cookie_recipe.txt 1-/dev/urandom 2-/dev/urandom \
-1+cookie_piece1.dat 2+cookie_piece2.dat 3+cookie_piece3.dat 4+cookie_piece4.dat
-
-./grothe 1-cookie_piece1.dat 2-cookie_piece2.dat 4-cookie_piece4.dat
-+cookie_recipe_restore.txt
-
-
-Also known as Best abuse of the judging process.
- -The IOCCC 2012 submission page didn’t enforce the 2048 meaningful -character limit. This entry, as submitted, weighed in at 2222 chars -but was, luckily for it, extremely easy to bring down below the -limit. There were a number of strings that when concatenated allowed -the program to slide under the limit.
- -It was clear to the judges that the extra size was an entry -beautification step. Had it not, this entry would have been -rejected in round 0.
- -The judges also took some liberty obfuscating this entry a litte more.
- -How does this entry work? The only place multiplication is used is -to perform the atoi conversion.
- -Description
- -This program implements a version of Shamir’s Secret Sharing. Shamir’s Secret -Sharing allows you to encrypt a file into N parts where it will take M parts to -recreate the original file. E.g. you can split the secret recipe for Crystal Pepsi -into 3 parts and require two of them be available to extract the original recipe.
- -Actually surprisingly useful for an IOCCC entry :-)
- -Usage
- -To share a secret
- -E.g.
- -file to be shared - cookie_recipe.txt -number of pieces - 2 + file to be shared -total number of pieces created by program 4 -pieces needed to reassemble recipe 3 or greater
- -example usage
- -# to share secret into 4 pieces of which at least 3 will be needed to get back the recipe
- -./grothe \
- -cookie_recipe.txt
- 1-/dev/urandom 2-/dev/urandom
- 1+cookie_piece1.dat 2+cookie_piece2.dat 3+cookie_piece3.dat 4+cookie_piece4.dat
-
-
-# put recipe back together using 1, 2 and 4th piece
- -./grothe \
- 1-cookie_piece1.dat 2-cookie_piece2.dat 4-cookie_piece4.dat
- +cookie_recipe_restore.txt
-
-
-Limitations
- -Obfuscations
- -References
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Tsukasa Hamano
-hamano@cuspy.org
make hamano
-
-
-./hamano < textfile > output.pdf
-
-
-./hamano < hint.text > hint.pdf
-
-# You can read output.pdf with PDF reader
-acroread hint.pdf
-# or
-evince hint.pdf
-
-# deobfuscate
-gcc -xc hint.pdf -o hint
-./hint
-
-# Of course, You can obfuscate c code
-echo 'void main(){puts("Hello World!");}' | ./hamano > hello.pdf
-gcc -xc hello.pdf -o hello2
-./hello2 | gcc -xc - -o ./hello3
-./hello3
-
-
-This entry treads into a new territory for IOCCC - generating PDF files.
- -The originally submitted entry could have been thought of as a “Best abuse of -Ghostscript” winner. :-)
- -The source code and rendered pages are obfuscated for humans (where -is the font?), and the submitted entry created PDF files that left Ghostscript -confused.
- -The results can be viewed with Acrobat Reader, -evince and Apple’s Preview.
- -The updated version can also be viewed using Ghostscript.
- -There is something strange about the little flags in the output. -A search of English literature will provide a hint. The conclusion -you might draw is too elementary. :-)
- -So what do those flags really mean?
- -The [Dancing men algorithm][1] might be useful.
- -Don’t forget to take a look at the generated PDF, perhaps you might even want -to compile the output with a C compiler. When you run it, what does it -output?
- -This program obfuscate text file into PDF file with Dancing men -algorithm.
- -http://en.wikipedia.org/wiki/The_Adventure_of_the_Dancing_Men
- -Probably, the output PDF file is compliant with PDF 1.3. And also -available to compile as C code.
- -I’ve been tested with GCC 4.7 and Clang 3.0 on Linux, and following -PDF Reader:
- -This program is obfuscated by using classical methods. -But can you find out the embedded font from fragmented glyph?
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Qiming Hou
-hqm03ster@gmail.com
-http://www.houqiming.net
make hou
-
-
-./hou syntax-file file-to-process
-
-
-The results are best viewed in a 80x25 console with ANSI colors.
- -less hou.c
-
-./hou ansi.txt hou.c | less -r
-
-./hou chk.txt hou.c | wc
-
-./hou markdown.txt remarks.markdown > remarks.htm
-your-browser remarks.htm
-
-
-copy header.htm hou.htm /y
-hou html.txt hou.c >> hou.htm
-start hou.htm
-
-
-What a versatile entry! It can be used to check the size of IOCCC entries and to publish them as HTML.
- -For extra credit: what is the meaning of the number 2321237?
- -The reviewer may have already noticed that the 2nd page of this program is a dense blob, which is discouraged by the contest rules. We wish to point out that a majority of state-of-art programming editors support syntax highlighting, which should be enabled when reading this entry. Anticipating that the reviewer’s preferred color setting may produce a suboptimal visual effect, a few syntax files are provided to highlight the source code under an author-provided setting, using the submitted program itself. Syntax highlighting would also visually improve the 3rd page.
- -The code may throw a few warnings due to formating constraints. The author did try to remove warnings under gcc and Visual Studio, though.
- -The author does not own the original anime series where the embedded ASCII arts come from. For comparison, original non-ASCII art depictions of the relevant characters and objects can be found by googling the embedded text messages.
- -The syntax file consists of a number of rewriting rules. Each rule consists of a regular expression, a space, a format string, and a newline. All text matching the regular expression would be replaced by the format string. In case of a conflict, rules appearing earlier would take precedence. One can refer to the original text in the format string using “%s”. Other “%” characters in the format string must be escaped with another “%”. The space character can be used in the regular expression by escaping it with [] or “”.
- -The following regular expression operators are supported:
- -() [] * + ? | ""
-
-
-For example, one can use the following expression to match a certain declaration statement in hou.c:
- -"char"[ *]*[a-zA-Z_][0-9a-zA-Z_]*[ ]*((=[0-9a-zA-Z_ ]+)|(\[[0-9a-zA-Z_ ]*\]))?[ ]*(,[ *]*[a-zA-Z_][0-9a-zA-Z_]*[ ]*((=[0-9a-zA-Z_ ]+)|(\[[0-9a-zA-Z_ ]*\]))?[ ]*)*;
-
-
-The regex engine is also algorithmically efficient. To illustrate the point, ansi.txt contains a pathological expression [2] that guarantees a hang for the competing Perl engine while matching itself. Try to compare these two engines:
- -./hou ansi.txt ansi.txt
-perl patho.pl < ansi.txt
-
-
-Finally, there are a few limitations…
- -The first layer of obfuscation comes from the challenge of embedding a large ASCII art in a dense blob. The entire art is composed using only keywords, strings and character constants. That results in a number of otherwise useless defines and quite a number of unconventionally written constants. While the preprocessor may remove the former, the later would remain regardless of beautification and preprocessing.
- -The second layer of obfuscation comes from the need to squeeze a reasonably powerful regex engine into the remaining area that isn’t occupied by excessive keywords and useless constants. To achieve this, the regex compiler is written using the same threaded virtual machine [1] that parses the regex. Due to compiler limitations, the generated VM code also ends up obscured by a large amount of spaghetti branches and virtual thread creations. Finally, the VM in [1] is extended to track multiple expression matches for the actual formating.
- -As an extra tweak, the text message actually does something useful. Remove the “Make a contract with me” catch line and the program would cease to function.
- -[1] Russ Cox, Regular Expression Matching: the Virtual Machine Approach
- -[2] Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby, …)
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Seonghoon Kang
-kang.seonghoon@mearie.org
make kang
-
-
-echo "full spelling of an English cardinal numeral less than a quadrillion" | ./kang
-
-
-echo Nineteen hundred and eighty-four | ./kang
-echo uno | ./kang
-echo trois | ./kang
-echo fier | ./kang
-echo "shest'" | ./kang
-
-
-The judges were able to appreciate the Indo-European language family -relation by making this entry successfully recognize some French, -German, Italian, Russian, and Spanish numerals.
- -Also worth mentioning is this entry’s ability to understand the -colloquial year numbers of the last millennium.
- -We’ve added a linefeed to the print format for convenience.
- -This short program reads a spelt number (e.g. forty-two) and writes a
-corresponding decimal number (e.g. 42). Too long for one-liners, alas,
-but it still qualifies as a short program as it has less than 0x100 bytes.
It accepts a variety of spelt numbers:
- -zero.forty-two and forty two are same.
-So does period or comma.TWO, Two, two are same.one and a are interchangeable: one hundred and a hundred are same.and is optional: one hundred twenty-three and one hundred and twenty-three
-are same.billion is 109 and trillion is
-1012.It does not accept some spelt numbers, which I found mostly irrelevant:
- -hundred, thousand etc. do not work.one million million does not work. Get used to one trillion!This program is quite portable, only requiring the following:
- -int main(int, int) should be accepted by the linker. (Original
-version only)char should be at least 8 bits long (as dictated by the standard), int
-should be at least 32 bits long, long long should be at least 64 bits long.char should wrap around, if your char is unsigned.The design of the program explicitly allows for EOF which does not equal to -1
-(it has to be negative per the standard) and both signed and unsigned char,
-for example. Furthermore it is endian-independent.
Many obfuscations used are typical for standard IOCCC entries:
- -main function are reused as normal variables.?: ternary operator and ||
-short-circuiting operator.for loops and nothing else.~-a instead of a-1,
-~a?...:... instead of a!=-1?...:..., etc.,) for multiple statements. The number of them is
-minimized, however, as it is too easy to (ab)use them.n["string"] instead of "string"[n]. Both are fine for this program but
-I went to the former just for fun.Other obfuscations are more subtle:
- -"1+DIY/.K430x9G(kC[" is 18 bytes long, but actually 19 bytes
-including the final null character are used.two
-hundred and three, it actually writes 0x203 as hexadecimal.n) have dual uses.main-er within it!But the most important obfuscation is the clever construction of lookup table. -The program uses 11 different characters required for recognizing 22 lexemes:
- -zero one tw- th(i)r- fo(u)r- fi- six-
-seven- eigh- nin- ten eleven twelve
-hundred(s) thousand(s) million(s) billion(s) trillion(s)
-a and -teen -ty
-
-
-So that they are internally represented as like:
- -r n tw- tr- fr- f- s-
-sn- g- nn- tn ln twl
-nr(s) tsan(s) lln(s) blln(s) trlln(s)
-a an -tn -ty
-
-
-The stemmer recognizes the longest matching prefix, so every lexeme can be
-recognized by at most three characters (e.g. trl instead of trlln). This is
-also handy for ignoring plurals. But that would make that the table does not fit
-in the printable byte—112 is already almost 27!
The trick is to use octal; three characters (a, b and g) are interpreted
-as sequences of two characters (ny, nn and nw respectively). Asides from
-a smaller lookup table, it has many good consequences:
a and and share the common prefix, ny, and can be discarded
-altogether. Note that ny itself does not appear from other entries.thousand is interpreted as tsan, which is equivalent to tfyn in the
-octal scheme. As it is the only entry with tf prefix, it can be shorten by
-one character.Having said this important trick, other details should be relatively easier to -follow. The order of lookup table, for example, is very important, -and the biggest constant 6177 is not arbitrarily chosen.
- -The cleaner (size-optimized) version of this program was originally published -in my website in July 2011. Sun Park and others have reviewed it and let me -aware of possible improvements. I’d also like to thank Seo Sanghyeon for -proof-reading remarks.
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Taketo Konno
-Tokyo, Japan
-inaniwa3@gmail.com
make konno
-
-
-./konno N
-# where N is 0 to 255
-
-
-./konno 30
-
-
-This entry is a good one-liner to analyze completely.
- -For extra credit, what are the minimal changes to convert it to -64-bit integers so that it could print 32 lines?
- -This program outputs elementary cellular automaton patterns.
- -Try:
- -./konno 30
-./konno 90
-./konno 102
-./konno 109
-./konno 165
-
-
-There are 256 (from 0 to 255) possible rules.
- -This program uses bit operations. I think
- -7&O<<!o>>!o+29
-
-
-is an intersting operation. This isn’t equal to
- -7&O>>29
-
-
-operation. What is the operation doing?
- -This program assumes that the size of int is 4.
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Don Yang
-omoikane@uguu.org
-http://uguu.org/
make nyaruko
-
-
-./nyaruko [seed.txt] < original.bin > output.c
-bash output.c > key.c
-perl output.c > data.c
-
-cat key.c data.c > output.c
-
-gcc output.c -o output
-./output > regenerated.bin
-
-
-echo "A quick brown fox jumps over the lazy dog" | ./nyaruko > output.c
-perl output.c > data.c
-gcc -o data data.c
-./data
-gcc -o output output.c
-./output
-
-
-The judges have nothing to add that has not already been written -about in the spoiler.html.gz file! :-)
- -Nyaruko is a binary to text filter. Given some input on stdin, -Nyaruko will produce C code that reproduces this input on stdout:
- -./nyaruko < original.bin > output.c
-gcc output.c -o output
-./output > regenerated.bin
-
-
-Output is encrypted, but both key and data are included in the output. -To separate the key from the data, run these commands:
- -bash output.c > key.c
-perl output.c > data.c
-
-
-The key-less data.c still compiles, but produces a different message -on stdout instead of the original input. This message is a hint to -why the code is formatted the way it is.
- -To combine the key and data, concatenate them together in either -order:
- -cat key.c data.c > output.c
-cat data.c key.c > output.c
-
-
-By default, Nyaruko generates a unique random key for every message, -using /dev/urandom as the seed. If given an extra command line -argument, Nyaruko will seed using that file instead of /dev/urandom:
- -./nyaruko seed.txt < input.bin > output.c
-
-
-This makes the output key deterministic, allowing the same key to be -shared across different files. On operating systems that do not have -/dev/urandom, users should always specify this extra seed argument to -avoid deterministic keys.
- -Implementation details that makes Nyaruko more obfuscated than usual -programs:
- -Output code has these features:
- -Code layout is meant to resemble Nyaruko, also known as Nyarlathotep, -the Crawling Chaos. The most obvious thing to do with chaos is to -make a random number generator, and the most obvious thing to do with -a random number generator is to make one-time-pads for encryption.
- -Nyaruko has these environment dependencies:
- -Output code has the same dependencies, with the additional -requirement that the compiler must support arbitrarily long string -literals. Maximum input size that can be encoded while still -producing standard-compliant output is ~276 bytes for C89, and ~3168 -bytes for C99.
- -Nyaruko has been to verified to work with these compiler/OS -combinations:
- -Note that on MingW, stdin and stdout are not opened in binary mode by -default, this means Nyaruko may not faithfully encode files on MingW.
- -spoiler.html.gz - Contains full recording of how the code went from -blank state to an obfuscated program, gzipped to fit under 1MB.
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
John Tromp
-john.tromp@gmail.com
-http://tromp.github.io/
On a 32-bit machine:
- -make tromp
-
-
-On a 64-bit machine:
- -make tromp64
-# And mentally substitute ./tromp64 for ./tromp everywhere below
-
-
-cat ascii-prog.blc data | ./tromp -b
-cat binary-prog.Blc data | ./tromp
-
-
-(cat hilbert.Blc; echo -n 1234) | ./tromp
-(cat oddindices.Blc; echo; cat primes.blc | ./tromp -b) | ./tromp
-cat primes.blc | ./tromp -b | ./primes.pl
-
-
-The judges dare to say that the data files this entry is processing -are more obfuscated than the entry itself.
- -This program celebrates the close connection between obfuscation and conciseness, -by implementing the most concise language known, Binary Lambda Calculus (BLC).
- -BLC was developed to make Algorithmic Information Theory, the theory of smallest programs, -more concrete. It starts with the simplest model of computation, the lambda calculus, -and adds the minimum amount of machinery to enable binary input and output.
- -More specifically, it defines a universal machine, which, from an input stream of bits, -parses the binary encoding of a lambda calculus term, applies that to the remainder -of input (translated to a lazy list of booleans, -which have a standard representation in lambda calculus), -and translates the evaluated result back into a stream of bits to be output.
- -Lambda is encoded as 00, application as 01, and the variable bound by the n'th -enclosing lambda (denoted n in so-called De Bruijn notation) as 1^{n}0. -That’s all there is to BLC!
- -For example the encoding of lambda term S = \x \y \z (x z) (y z), -with De Bruijn notation \ \ \ (3 1) (2 1), -is 00 00 00 01 01 1110 10 01 110 10
- -In the closely related BLC8 language, IO is byte oriented, -translating between a stream of bytes and a list of length-8 lists of booleans.
- -The submission implements the universal machine in the most concise manner conceivable. -It lacks #defines and #includes, and compiles to a (stripped) executable of under 6K in size.
- -Without arguments, it runs in byte mode, using standard in- and output. -With one (arbitrary) argument, it runs in bit mode, using only the least significant -bit of input, and using characters ‘0’ and ‘1’ for output.
- -The program uses the following exit codes: -0: OK; result is a finite list -5: Out of term space -6: Out of memory -1,2,3,4,8,9: result not in list form
- -The size of the term space is fixed at compile time with -DA
- -The shortest (closed) lambda calculus term is \x x (\ 1 in De Bruijn notation) -which is the identity function. When its encoding 0010 is fed -into the universal machine, it will simply copy the input to the output. -(well, not that simply, since each byte is smashed to bits and rebuilt from scratch) -Voila: a half byte cat:
- - echo " Hello, world" | ./tromp
-Hello, world
-
-
-Since the least significant 4 bits of the first byte are just arbitrary padding -that is ignored by the program, -any character from ASCII 32 (space) through 47 (/) will do, e.g.:
- - echo "*Hello, world" | ./tromp
-Hello, world
-
-
-If the input doesn’t start with a valid program, that is, -if the interpreter reaches end-of-file during program parsing, -it will crash in some way:
- - echo -n "U" | ./tromp
-Segmentation fault
-
-
-Furthermore, the interpreter requires the initial encoded lambda term to be closed, -that is, variable n can only appear within at least n enclosing lambdas. -For instance the term \ 5 is not closed, -causing the interpreter to crash when looking into a null-pointer environment:
- - echo ">Hello, world" | ./tromp
-Segmentation fault
-
-
-Since these properties can be checked when creating BLC programs, -the interpreter doesn’t bother checking for it.
- -The BLC universal machine may be small at 650 bytes of C -(952 bytes including layout), but written -as a self interpreter in BLC it is downright minuscule at 232 bits (29 bytes):
- - 01010001
- 10100000
- 00010101
- 10000000
- 00011110
- 00010111
- 11100111
- 10000101
- 11001111
- 000000111
- 10000101101
- 1011100111110
- 000111110000101
- 11101001 11010010
- 11001110 00011011
- 00001011 11100001
- 11110000 11100110
- 11110111 11001111
- 01110110 00011001
-00011010 00011010
-
-
-The byte oriented BLC8 version weighs in at 43 bytes (shown in hexadecimal).
- - 19468
- 05580
- 05f00
- bfe5f
- 85f3f
- 03c2d
- b9fc3f8
- 5e9d65e5f
- 0decb f0fc3
- 9befe 185f7
- 0b7fb 00cf6
-7bb03 91a1a
-
- (cat uni8.Blc; echo " Ni hao") | ./tromp
-Ni hao
-
-
-Even shorter than the self-interpreter is this prime number sieve in 167 bits (under 21 bytes):
- -000100011001100101000110100
- 000000101100000100100010101
- 11110111 101001000
- 11010000 111001101
- 000000000010110111001110011
- 11111011110000000011111001
- 10111000
- 00010110
-0000110110
-
-
-The n'th bit in the output indicates whether n is prime:
- - cat primes.blc | ./tromp -b | head -c 70
-0011010100010100010100010000010100000100010100010000010000010100000100
-
-
-For those who prefer to digest their primes in decimal, there is oddindices.Blc, -which will print the indices of all odd characters (with lsb = 1) -separated by a given character:
- - (cat oddindices.Blc; echo -n " "; cat primes.blc | ./tromp -b) | ./tromp | head -c 70
-2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
-
-
-Program hilbert.Blc, at 143 bytes, is a very twisty “one-liner” (shown in hexadecimal):
- -1818181 8111154 6806041 55ff041
-9d f9 de 16 ff fe 5f 3f
-ef f615ff9 46 84 058117e 05
-cb fe bc bf
-ee86cb9 4681600 5c0bfac bfbf71a
- 85 e0 5c f4
-14d5fe0 8180b048d0800e078 016445f
-fe 5f
-f7 ffffe5fff2fc 02f7ad97f5bf ff
-ff bf ff ca af ff
-7817ffa df76695 4680601 57f7e16
- 05 c1
-3fe80b2 2c18581 bfe5c10 42ff805
-de ec 06 c2 c0 c0
-60 8191a00167fb cbcfdf65f7c0 a20
-
-
-It expects n arbitrary characters of input, and draws a space filling Hilbert curve of order n:
- - (cat hilbert.Blc; echo -n "1") | ./tromp
- _
-| |
-
- (cat hilbert.Blc; echo -n "12") | ./tromp
- _ _
-| |_| |
-|_ _|
- _| |_
-
- (cat hilbert.Blc; echo -n "123") | ./tromp
- _ _ _ _
-| |_| | | |_| |
-|_ _| |_ _|
- _| |_____| |_
-| ___ ___ |
-|_| _| |_ |_|
- _ |_ _| _
-| |___| |___| |
-
- (cat hilbert.Blc; echo -n "1234") | ./tromp
- _ _ _ _ _ _ _ _
-| |_| | | |_| | | |_| | | |_| |
-|_ _| |_ _| |_ _| |_ _|
- _| |_____| |_ _| |_____| |_
-| ___ ___ | | ___ ___ |
-|_| _| |_ |_| |_| _| |_ |_|
- _ |_ _| _ _ |_ _| _
-| |___| |___| |_| |___| |___| |
-|_ ___ ___ ___ ___ _|
- _| |_ |_| _| |_ |_| _| |_
-| _ | _ |_ _| _ | _ |
-|_| |_| | |___| |___| | |_| |_|
- _ _ | ___ ___ | _ _
-| |_| | |_| _| |_ |_| | |_| |
-|_ _| _ |_ _| _ |_ _|
- _| |___| |___| |___| |___| |_
-
-
-The smallest known BF interpreter is written in… you guessed it, BLC, -coming in at 112 bytes (including 3 bits of padding):
- - od -t x4 bf.Blc
-0000000 01a15144 02d55584 223070b7 00f032ff
-0000020 7f85f9bf 956fe15e c0ee7d7f 006854e5
-0000040 fbfd5558 fd5745e0 b6f0fbeb 07d62ff0
-0000060 d7736fe1 c0bc14f1 1f2eff0b 17666fa1
-0000100 2fef5be8 ff13ffcf 2034cae1 0bd0c80a
-0000120 e51fee99 6a5a7fff ff0fff1f d0049d87
-0000140 db0500ab 3bb74023 b0c0cc28 10740e6c
-0000160
-
-
-It expects its input to consist of a Brainfuck program -(looking only at bits 0,1,4 to distinguish among ,-.+<>][ ) -followed by a ], followed by the input for the Brainfuck program.
- - more hw.bf
-++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.]
- cat bf.Blc hw.bf | ./tromp
-Hello World!
-
-
-Curiously, the interpreter bf.Blc is the exact same size as hw.bf.
- -Writing BLC programs can be made slightly less painful with this parser that -translates single-letter-variable lambda calculus into BLC:
- - echo "\f\x f (f (f x))" > three
- cat parse.Blc three | ./tromp
-000001110011100111010
-
-
-THe program inflate.Blc and its inverse deflate.Blc allow us to translate between -BLC and BLC8. -If you assemble a byte oriented program, you’ll need to compact it into BLC8:
- -So we could assemble an input reversing program as
- - echo "\a a ((\b b b) (\b \c \d \e d (b b) (\f f c e))) (\b \c c)" > reverse
- cat parse.Blc reverse | ./tromp > reverse.blc
-
-
-and change it to BLC8 with
- - cat deflate.Blc reverse.blc | ./tromp > rev.Blc
- wc rev.Blc
-0 1 9 rev.Blc
-
-
-and then try it out with:
- - cat rev.Blc - | ./tromp
-Hello, world!
-^D
-!dlrow ,olleH
-
-
-BLC8 program symbolic.Blc shows individual reduction steps on symbolic lambda terms. -Here it is used to show the calculation of 23 in Church numerals:
- - echo "(\f\x f (f (f x))) (\f\x f (f x))" > threetwo
- cat parse.Blc threetwo | ./tromp > threetwo.blc
- cat symbolic.Blc threetwo.blc | ./tromp
-(\a \b a (a (a b))) (\a \b a (a b))
-\a (\b \c b (b c)) ((\b \c b (b c)) ((\b \c b (b c)) a))
-\a \b (\c \d c (c d)) ((\c \d c (c d)) a) ((\c \d c (c d)) ((\c \d c (c d)) a) b)
-\a \b (\c (\d \e d (d e)) a ((\d \e d (d e)) a c)) ((\c \d c (c d)) ((\c \d c (c d)) a) b)
-\a \b (\c \d c (c d)) a ((\c \d c (c d)) a ((\c \d c (c d)) ((\c \d c (c d)) a) b))
-\a \b (\c a (a c)) ((\c \d c (c d)) a ((\c \d c (c d)) ((\c \d c (c d)) a) b))
-\a \b a (a ((\c \d c (c d)) a ((\c \d c (c d)) ((\c \d c (c d)) a) b)))
-\a \b a (a ((\c a (a c)) ((\c \d c (c d)) ((\c \d c (c d)) a) b)))
-\a \b a (a (a (a ((\c \d c (c d)) ((\c \d c (c d)) a) b))))
-\a \b a (a (a (a ((\c (\d \e d (d e)) a ((\d \e d (d e)) a c)) b))))
-\a \b a (a (a (a ((\c \d c (c d)) a ((\c \d c (c d)) a b)))))
-\a \b a (a (a (a ((\c a (a c)) ((\c \d c (c d)) a b)))))
-\a \b a (a (a (a (a (a ((\c \d c (c d)) a b))))))
-\a \b a (a (a (a (a (a ((\c a (a c)) b))))))
-\a \b a (a (a (a (a (a (a (a b)))))))
-
-
-As expected, the resulting normal form is Church numeral 8.
- -Taking only the first line of output gives us a sort of BLC disassembler, -an exact inverse of the above assembler. The prime number sieve disassembles as follows:
- - cat symbolic.Blc primes.blc | ./tromp | head -1
-\a (\b b (b ((\c c c) (\c \d \e e (\f \g g) ((\f c c f ((\g g g) (\g f (g g)))) (\f \g \h \i i g (h (d f))))) (\c \d \e b (e c))))) (\b \c c (\d \e d) b)
-
-
-Hardly any less obfuscated…
- -The last line of - cat symbolic.Blc primes.blc | ./tromp | head -16 -starts out as - \a \b b (\c \d c) (\c c (\d \e d) (\d d (\e \f f) (\e e (\f \g g) ((\f (\g \h \i
- -The \a is for ignoring the rest of the input (to which the universal machine -applies the decoded lambda term). The \b b (..) (…) is the list constructor, -usually called cons, applied to a head (a list element) and a tail (another list). -In this case the element is (\c \d c), which represents the boolean true, and -which we use to represent a 0 bit. This is the bit that says 0 is not prime. -The next list element (following another cons) is (\d \e d). Another 0 bit, -this time saying that 1 is not prime. The third list element is (\e \f f), -a 1 bit, confirming our suspicion that 2 is prime. As is the next number, -according to (\f \g g). We can see that the tail after the first 4 elements -is still subject to further reduction. The bit for number 4 will show up -for the first time in line 30, as (\g \h g), or 0, as the result of zeroing -out all multiples of the first prime, 2. -Since my computer reaches swap hell before line 40, we can’t see the next bit arriving, -at least not in this symbolic reduction.
- -Performance is quite decent, and amazingly good for such a tiny implementation, -being roughly 50% slower than a Haskell implementation of the universal machine -using so-called Higher Order Abstract Syntax which relies on the highly optimized -Haskell runtime system for evaluation. Of course individual blc programs running -under the interpreter perform much worse than that same program written in Haskell.
- -Our interpreter copes well with extra levels of interpretation:
- - time cat primes.blc | ./tromp -b | head -c 210 > /dev/null
-real 0m0.043s
- time cat uni.blc primes.blc | ./tromp -b | head -c 210 > /dev/null
-real 0m0.191s
- time cat uni.blc uni.blc primes.blc | ./tromp -b | head -c 210 > /dev/null
-real 0m1.919s
- time cat uni.blc uni.blc uni.blc primes.blc | ./tromp -b | head -c 210 > /dev/null
-real 0m23.514s
- time cat uni.blc uni.blc uni.blc uni.blc primes.blc | ./tromp -b | head -c 210 > /dev/null
-real 4m52.700s
-
-
-Obfuscation is due entirely to conciseness. Some questions to ponder:
- -Which of the term space codes 0,1,2,3 serves multiple purposes?
- -Why is the environment pointer pointing into the term space?
- -What does the test u+m&1? do?
- -How does the program reach exit code 0?
- -And how do any of those blc programs work?
- -The program freely (without casting) converts between int and int*, causing -many warnings; - note: expected ‘int *’ but argument is of type ‘int’ - warning: assignment from incompatible pointer type - warning: assignment makes integer from pointer without a cast - warning: assignment makes pointer from integer without a cast - warning: incompatible implicit declaration of built-in function ‘calloc’ - warning: incompatible implicit declaration of built-in function ‘exit’ - warning: passing argument 1 of ‘d’ makes pointer from integer without a cast - warning: passing argument 1 of ‘p’ makes pointer from integer without a cast - warning: pointer/integer type mismatch in conditional expression
- -Avoiding these would make the program substantially longer, -and detract from its single minded focus on conciseness.
- -It implicitly declares functions read, write, exit and calloc, the latter two incompatibly. -32 bit and 64 bit executables are separate Makefile targets, involving a change -from int to long and from a hardcoded sizeof of 4 to 8.
- -The program has been tested to work correctly on Linux/Solaris/MacOSX both in 32 and 64 bits.
- -See the file how13.
- -Christopher Hendrie, Bertram Felgenhauer, Alex Stangl, Seong-hoon Kang, -and Yusuke Endoh have contributed ideas and suggestions for improvement.
- -Binary Lambda Calculus -https://tromp.github.io/cl/Binary_lambda_calculus.html
- -G J Chaitin, Algorithmic information theory, Volume I, -Cambridge Tracts in Theoretical Computer Science, Cambridge University Press, October 1987. -http://www.cs.auckland.ac.nz/~chaitin/cup.html
- -Jean-Louis Krivine. 2007. -A call-by-name lambda-calculus machine -Higher Order Symbol. Comput. 20, 3 (September 2007), 199-207. -http://www.pps.univ-paris-diderot.fr/~krivine/articles/lazymach.pdf
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Daniel Vik
-daniel@vik.cc
-http://danielvik.com/
make vik
-
-
-This entry requires Zlib.
- -./vik e base.png filename > encodedimg.png
-# or
-./vik e base.png SomeRandomText > encodedimg.png
-
-
-./vik d encodedimg.png
-
-
-./vik e base.png source.png > encodedimg.png
-
-
-./vik d encodedimg.png > restored.png
-
-
-./vik e ioccc.png chocolate.png > chocolate-in-ioccc.png
-./vik e chocolate.png ioccc.png > ioccc-in-chocolate.png
-./vik d chocolate-in-ioccc.png > restored-chocolate.png
-./vik d ioccc-in-chocolate.png > restored-ioccc.png
-
-
-References to chocolate had no effect on judging this entry. We -guarantee it.
- -Can you discern hidden pieces of chocolate in chocolate-in-ioccc.png ?
- -This program is a steganography application for embedding an image or text -into another image as well as extracting the embedded image or text back. -The program stores the embedded image or text in the low bits of the RGB -values.
- -The program supports any 8 bit true color PNG images (RGB, RGBA, grayscale, -and grayscale+alpha). The output image is always 8 bit RGB. When embedding -one image into another, the width and height needs to be the same.
- -The program only updates the IDAT and IHDR chunks of the source image. Any -additional chunks are copied into the resulting image.
- -For some reason the chocolate image seems to have some special properties. -Apart from being quite big and a little bit noisy, it appears that when -embedded into another image and extracted, the bitmap data is also a valid -brain$#@$ program. It is of course possible to get the bitmap data from the -extracted image, and run it through any of the previous winning brain$#@$ -interpreters, but I thought it would be easier to include an interpreter in -the program to avoid the hassle:
- -./vik e ioccc.png chocolate.png > encodedimg.png
-./vik b encodedimg.png
-
-
-It is of course also possible to embed a brain$#@$ program as a text file -(as explained above) and decode it, e.g.:
- -./vik e ioccc.png .+[.+] > encodedimg.png
-./vik b encodedimg.png
-
-
-I really wanted to keep the program simple, so instead of adding multiple -macros or helper methods that can be confusing, I placed all functionality -in the main function. Main is called recursively and quite extensively, but -it gives the benefit that all invocations of the function has the same -parameters, argv and argc. This really helps readability, as a programmer -doesn’t need to remember several variable or function names. I also tried -to reduce the number of keywords, and the program only has four for-loops -followed by a single return statement. There is a little bit of use of the -question mark operator, but this is really there to keep the program as -simple as possible.
- -The program is portable to most platforms that have zlib available. The -only system dependency is that the program relies on writing binary data to -stdout.
- -By default, Microsoft compilers adds carriage returns to new lines, and to -compile the program on this platform, the following line can be added after -the variable declarations in the main declaration in order to run -correctly:
- -_setmode(_fileno(stdout), 0x8000);
-
-
-The program doesn’t have many error checks so passing in invalid arguments -or images of mismatching sizes, or unsupported pixel formats will cause the -program to crash.
- -Since a lot of care was taken to keep the code simple, it turned out to be -quite easy to extend functionality. I did include a small brain$#@$ after I -realized that the chocolate image had some interesting properties.
- -But there is more functionality I added that didn’t fit within the size -limits and could not remain included. For example, I added a method to -format source code based on a PNG image. So the format of the program is -actually done by the program itself.
- -And to be honest, the chocolate image did not have a brain$#@$ program -embedded to begin with. I added functionality to the program to embed a -brain$#@$ into a PNG image and used it to create the image provided with -the entry.
- -I also added a method to analyze PNG images, to print the size and format, -as well as the scan line filters.
- -All these features were quite easy to add, much thanks to the (actually -pretty good) design of the code.
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Adar Zeitak
-aa4z2@walla.co.il
make zeitak
-
-
-./zeitak < file.c
-
-
-where file.c is the file to be checked for nesting errors. For example, you may -try incorrect.c and the program itself.
- -./zeitak < zeitak.c
-./zeitak < incorrect.c
-
-
-This is an extremely subtle and twisted piece of Gold award winning code!
- -The judges had spent a considerable amount of time analyzing this entry. -At one point we spent -18 minutes -just to understand 18 key characters of this code.
- -The file zeitak_deobfucate.c provides a version that has been slightly -deobfuscated. You may find reading that file helpful in your attempt -to understand this extremely subtle entry.
- -As you have probably understood by looking at the source*, this program has -something to do with parenthesis (and equality of opening and closing -parenthesis, if you look close enough). It goes over the file given to it and -checks that every opening (, [, or { has a matching closing one and -vice versa. It also checks that every “ or ‘ is closed.
- -If an error is detected, an error message will be printed. If the problem -is a superfluous closing bracket, it will even print a few characters -around it’s position.
- -Ignores parenthesis inside strings or character constants, so no errors -will be detected in the following line:
- - printf(")");
-Doesn’t get confused by the 1984/anonymous entry!
Escapes (e.g. \") are ignored, so the following line will produce
-an error:
printf("\"");
-IOCCC winners already contain entries without digits, control-flow -keywords and certain operators in their source. This entry has an -even more limited source, that is:
- -So, what’s left? Parenthesis, and lots of them, as looking at the source will -reveal immediately. The main obfuscation is building the whole algorithm using -only function calls, typecasts, array lookups and pointer operators.
- -Additional obfuscations include:
- -The program requires char to be one byte and pointers to be
-at least two bytes long.
The program was tested on the following platforms:
Ubuntu 9.04 32-bit with GCC - Windows 7 32-bit with GCC -** Windows 7 32-bit with OpenWatcom
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Michael Birken
-o__1@hotmail.com
-http://www.meatfighter.com/
make birken
-
-
-./birken < 17_columns_wide_paint_by_numbers_file
-
-
-./birken < examples/ioccc.txt
-
-perl -e 'map{map{print int(rand()*8);}(0..16);print chr(10);}(0..30);' | tr '[0-4]' ' '| ./birken
-
-
-This program also wins the “Most amusing abuse of the iocccsize tool” award; although not the -absolute best: it is possible to achieve 0 by writing
- -/* *\
-/....
-
-
-The game of Tetris had been used in many endeavors, from studying algorithmic complexity to treating PTSD. -Using it for painting by numbers looks like a novel idea.
- -This document is best viewed as an HTML file in a browser that supports animated gifs. Extract examples.tbz2 for the sample input files.
tar -xjvf examples.tbz2
-
-
-By rotating, positioning and dropping a predetermined sequence of pieces, this program exploits the mechanics of Tetris to generate arbitrary images.
- -The algorithm converts pixels from a source image into squares in the Tetris playfield, one row at a time from the bottom up. To generate an individual square, the algorithm assembles a structure consisting of a rectangular region fully supported by a single square protruding from the bottom. When the rectangular region is completed, its rows are cleared, leaving behind the protruding square. Three examples of the process appear below.
- -


During construction of a row, all of the squares produced by this method must be supported. In the images above, the generated squares are supported by the floor of the playfield. However, if an arbitrary row contains holes, it may not provide the support necessary for the construction of the row above it. The algorithm solves this problem by constructing a flat platform on top of the row with holes. In the animation below, a platform is built above a row comprising of a single red square. The platform is a temporary structure and inserting the final piece removes it.
- -
Below, a row containing 5 red squares is deposited above a row containing 3 red squares. This is accomplished by building a flat platform on top of the lower row. The platform provides the support necessary to generate the 5 red squares. Finally, the platform is removed by inserting its final piece and the new row drops into place. Note, if the algorithm needed to generate the rows in the opposite order (a row of 3 red squares above a row of 5 red squares), a platform would not be necessary.
- -
For reference, the names of the 7 Tetriminos (the game pieces) appear in the table below.
- -
This algorithm was tailored specifically to render sprites from early video games. Those games packed graphics into 8×8 tiles where 2 bits were dedicated to each pixel. Consequentially, sprites usually contained only 3 colors plus transparent regions and they were typically sized either 16×16 or 16×32 pixels.
- -The animation below depicts all the patterns used to emit single squares. J, T and L Tetriminos are used interchangeably within each pattern to produce the protruding square at the bottom. The algorithm assigns those Tetriminos to the 3 colors present in the sprite. The remaining Tetriminos are assigned arbitrary colors. And, all the colors remain constant during gameplay.
- -
It is not possible to emit a square of all 3 colors in the first 2 and the last 2 columns due to the shapes of the 3 Tetriminos. As a result, the minimal width of a playfield to accommodate a 16 pixel wide sprite is 2 + 16 + 2 = 20 squares. However, it turns out that 20 is too small.
- -As illustrated below, the region above the protruding square cannot exclusively consist of a single row because the only pieces that could fit, the I Tetriminos, are unsupported.
- -
With 2 rows, the only means of spanning the full playfield width in a way that remains supported is to use S and Z Tetriminos. But, that will always leave holes in the upper row.
- -
The minimal number of rows required above the protruding square is 3 and as shown repeatedly above, such patterns do exist. 20 squares is the minimal width required to fit a 16 pixel wide sprite. But, 20 × 3 + 1 = 61, which is not divisible by 4 and hence not constructible out of Tetriminos. However, a width of 21 yields 21 × 3 + 1 = 64, which can be built with 16 Tetriminos. That width actually enables the algorithm to render sprites up to 17 pixels wide.
- -The original Tetris playfield is 10×20 squares, a 1:2 ratio. The program maintains that ratio by using a playfield of 21×42 squares.
- -Since J, T and L Tetriminos are used interchangeably to produce the emitted square and 3 squares of those Tetriminos contribute to the row above it, there are 21 − 3 + 1 = 19 single square emitting patterns. However, due to mirror symmetry, there are really only 10 patterns. Clearing 3 rows works for the majority of them. But, an exhaustive computer search revealed that 2 of the patterns require more. The next possible option is 7 rows since 21 × 7 + 1 = 148, requiring 37 Tetriminos. As the images below show, those patterns do exist.
- -

Before a row is constructed, the algorithm inspects the row below it. If the row below fails to provide support for all of the squares to be deposited above it, then a temporary platform is required. When that platform is removed, the new row will drop, leaving some of the squares apparently floating above empty space due to the way that gravity works in the original Tetris.
- -The illustration below depicts the 10 platform patterns (really only 5 considering mirror symmetry). The construction of a platform begins by dropping a T Tetrimino on top one of the squares of the last generated row. The remaining Tetriminos support each other down to that first T. Meaning, as long as the previously generated row contains at least 1 square, like the red square below, then it is possible to construct a flat platform above it for the generation of the next row.
- -
In the middle of platform construction, the bottom row gets completed and cleared, leaving 3 rows above it. The final J or L Tetrimino that will remove those rows is not inserted until the square emitters are done generating the next row of the sprite on top of the platform. That final piece precludes square emission in the first and last 2 columns. But, as discussed above, the square emitters are limited to the 17 inner columns due to the geometry of the J, T and L Tetriminos used in the process.
- -Also, of the 19 possible ways to start constructing a platform on top of a T Tetrimino, only the 10 patterns shown above exist.
- -The input sprite is represented textually. Digit characters 0 to 7 correspond to pixels with colors from the palette below.

As discussed above, sprites are limited to a maximum of 3 colors from this palette.
- -All other characters are interpreted as transparent pixels.
- -The maximum permissible size of the input text is 32 rows by 17 columns. Row length can vary as long as no single row exceeds 17 characters.
- -Every row must contain at least one palette digit character.
- -The examples directory contains several sprites in this textual format that can be fed into standard input. Several examples take advantage of the Tetris playfield background color. Instead of using character 0, internal regions marked as transparent are effectively rendered as black.
The program conceptually uses Tetris as an output device similar to a line printer. It restricts itself to those operations that can be performed on the Tetris playfield: spawning, rotating, positioning and dropping Tetriminos. This process is visually represented using ANSI escape sequences.
- -The rate at which the program plays Tetris is completely determined by the rate in which the terminal application receives and displays the ANSI escape sequences.
- -To slowdown the output programmatically, introduce a delay immediately after the call to fflush.
This program demonstrates how to exploit a bug in IOCCC size tool version 2013-07-30-v17. The first line of the program is reproduced below.
- -char*_ = "'""/*";
-
-
-If that line is added to the top of any program, the tool will report a size of 8.
- -./iocccsize -i < prog.c
-8
-
-
-When that line is deleted from this program, the tool properly reports the secondary size limit of the program as 2048.
- -./iocccsize -i < prog.c
-2048
-
-
-Although this bug provides an easy means of circumventing contest rule 2, as demonstrated from the size value, this entry is not necessarily striving for a ‘worst abuse of the rules’ award.
- -This program is almost, but not quite, entirely unlike a demonstration of good programming practices. Contrary to other programs, an inspection of this one will certainly reveal that it possesses tea, not to mention an affinity for the constant 42.
- -Variables are named and ordered to spell out, “Tetris”, “ELORG”, “DVK” and the aforementioned “Tea”. ELORG is the abbreviation for Elektronorgtechnica, the former Soviet state owned computer organization that handled the worldwide Tetris intellectual property rights. DVK is the line of Soviet PDP-11-compatible personal computers capable of running Alexey Pajitnov’s original 1984 Tetris prototype.
- -Carefully selected variable names also yielded wonderful expressions like l=0, O=0, O=1 and while(O). “Tetris” also makes a second appearance of sorts:
[T][e][t]--; while(R+i) { s
-
-
-The source is formatted to resemble the Tetris playfield midgame. It is also an homage to all the past IOCCC entries formatted as a compact block of text; the T, orientated appropriately to reflect its name and the first letter in the title of the game, is just a moment away from producing such a text block.
- -Three tables are encoded as separate strings within the program:
- -The first string stores the coordinates of the squares of the 19 distinct rotations of Tetriminos (see below). Since a Tetrimino is a chain of 4 squares, all Tetriminos fit within a 4×4 matrix. To determine the coordinates of the squares, the Tetrimino is pushed to the upper-left of the matrix. Each coordinate value requires 2 bits of storage. Consequentially, the four x-coordinates and the four y-coordinates were packed into separate octets. To convert the octets into valid ASCII characters, the squares were sorted such that the least significant bits stored the largest coordinate values. The results were offset by 35, the # character, which is 1 beyond the ASCII value of ", making it easier to pack into a string. None of the resultant values are beyond ASCII 127. The coordinates for all 19 rotations fit in a string of length 38.

The second string stores the single square emitter patterns and the platform patterns. Each pattern is a sequence of pairs, { Tetrimino index, drop x-coordinate }. As mentioned, there are 19 distinct rotations, requiring 5 bits of storage for the Tetrimino index. Another 5 bits is required for the drop x-coordinate since there are 21 columns in the playfield. Necessarily, the pair is stored as 2 separate characters. By offsetting them by 40, the ( character, the resultant string almost resembles a long and complex mathematical expression. The program takes advantage of mirror symmetry by only storing 10 single square emitter patterns and 5 platform patterns. The pattern lengths are not encoded within the string. Rather, they are embedded within the string decoding logic.
The third string conceptually stores the default colors of the 19 rotations. A 3-bit value is assigned to each, covering the 7 possible colors. In addition, when a mirrored pattern is executed, J exchanges with L and S exchanges with Z, necessitating a second list of 3-bit color values. Pairs of color values (6 bits) fit comfortably into a character that is offset by #. The result is a string of length 19.
The program is full of subtle obfuscations:
- -The unary decrement operator is used in conjunction with global variable automatic zero initialization to set variables to -1.
The boolean expression of the form, x + 1, is used multiple times to determine if a value is not -1. Similarly, expressions of the form x - y are used to determine if x != y.
Several arrays store unrelated data in segments throughout the array to reduce named variables.
The x["..."] trick appears once.
Variable i is less than necessary.
A cursorily glance at the expressions 4&&L and m&&e==m suggests that they always evaluate to true.
The varying single square emitter pattern lengths are resolved during string decoding using the clever expression, (i & 3) - 3, which identifies pattern 3 and 7 as longer.
The file size of prog.c is a prime number. Deleting the first line also produces a prime-sized program. These properties do not qualify the program as a prime number generator.
Due to the contest code size constraint, some optimizations reluctantly had to be omitted. For example, multi-square emitters are possible:
- -



In fact, using dynamic programming and creative heuristics, real-time search is possible, enabling patterns like this:
- -
And, even this:
- -
In addition, it is possible to extend the algorithm to 6 colors instead of just 3. This is achieved using I, S and Z to produce the protruding square. A series of rectangular regions are constructed above those Tetriminos to erode them down to a single emitted square.
- -The details of these enhancements are left as an exercise to the reader.
- -The following example files were created by the program author. They can be freely used and distributed.
- -format.txt - The layout of the programhelloworld.txt - Hello World, Tetris-stylehilbert.txt - A graphic based on the Hilbert curveioccc.txt - IOCCClandon.txt - Portrait of a man with glassesleo.txt - Portrait of a man without glassesrhino.txt - A purple rhinocerossimon.txt - Portrait of a man without hairThe following files are based on graphics from non-free, copyrighted video games. The use of a limited number of textual representations of the graphics for the demonstration of this program qualifies as fair use as such files do not significantly impede the right of the copyright holder to sell the copyrighted material and it is not being used to generate profit in this context. The origin of each file is detailed below (character, game, company, year).
- -belmont.txt - Simon Belmont, Castlevania, Konami, 1986bloober.txt - Bloober, Super Mario Brothers, Nintendo, 1985bomberman.txt - Bomberman, Bomberman, Hudson, 1983boo.txt - Boo, Super Mario Brothers 3, Nintendo, 1988bub.txt - Bub, Bubble Bobble, Taito, 1986cheepcheep.txt - Cheep Cheep, Super Mario Brothers, Nintendo, 1985gurin.txt - Gurin, Binary Land, Hudson, 1983koopaparatroopa.txt - Koopa Paratroopa, Super Mario Brothers, Nintendo, 1985lakitu.txt - Lakitu, Super Mario Brothers, Nintendo, 1985mario.txt - Fire Mario, Super Mario Brothers, Nintendo, 1985mspacman.txt - Ms. Pac-Man and Ghost, Ms. Pac-Man, Midway, 1982paranaplant.txt - Piranha Plant, Super Mario Brothers, Nintendo, 1985samus.txt - Samus Aran, Metroid, Nintendo/Intelligent Systems, 1986toad.txt - Toad, Super Mario Brothers 2, Nintendo, 1987The origin of the remaining files are described below:
- -happyface.txt - Based on a smiley; rights unknownsnoo.txt - 8-bit version of Snoo, Reddit’s alien mascot![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Adrian Cable
-adrian.cable@gmail.com
make cable1
-
-
-./cable1 name group1 group2
-
-
-./cable1 obama republican democrat
-./cable1 nixon republican democrat
-./cable1 bush republican democrat
-./cable1 kennedy republican democrat
-./cable1 lincoln republican democrat
-
-
-Partisan may be defined as a strong supporter of a cause, party or person. -We need not limit ourselves to the two major political parties in the US today.
- -Let us consider:
- -./cable1 Cooper Mac PC
-
-
-Simon works for Apple, so would would expect Mac. :-) -Landon is a long time Mac user:
- -./cable1 Noll Mac PC
-
-
-That works too!. Now Leo brings PCs to the IOCCC judging for cross-platform -testing:
- -./cable1 Broukhis Mac PC
-
-
-We can test other people. The late Steve Jobs:
- -./cable1 Jobs Mac PC
-
-
-That works! How about Bill?
- -./cable1 Gates Mac PC
-
-
-A PC guy as expected. What about that other Steve?
- -./cable1 Ballmer Mac PC
-
-
-Humm .. maybe there is a hidden reason he is leaving the late Micro$oft? :-) -Why late? See this tweet.
- -So how does a one line C source know so much? Hint: it doesn’t.
- -Politics is full of memorable one-liners. Without wishing to misunderestimate the taste of the judges, nor prejudge the past, the author hopes you enjoy this contribution to the genre.
- -This one-line C program accepts as a first command-line argument the last name of any of the last 31 US Presidents (from Franklin Pierce onwards), in lower case, and prints out their political affiliation.
- -Use “republican” as the 2nd command-line argument, and “democrat” as the 3rd (or equivalent strings of your choice).
- -clang warns about a missing type specifier for main, and that implicit function declarations are invalid in C99 (but still accepts them).
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Adrian Cable
-adrian.cable@gmail.com
make cable2
-
-
-./cable2 file.bmp [color]
-
-
-Extract example-images.tbz2:
- -make data
-
-
-Here is an OCR example that shows all 94 supported ASCII characters:
- -./cable2 ascii.bmp
-
-
-Here is an example of colored ASCII:
- -./cable2 multi_color.bmp color
-
-
-Here is an example using different character sizes and different -positions in the same file:
- -./cable2 mixed_sizes.bmp
-
-
-How about about hand-written C code:
- -./cable2 hello_world.bmp | gcc -xc -o hello -
-./hello
-
-
-Sometimes typeset text will work, if the typeset has characters that -are enough to the supported handwritten shapes. For example, -Menlo, 160 pt:
- -./cable2 typeset.bmp
-
-
-And as an added IOCCC bonus: :-)
- -./cable2 bonus.bmp
-
-
-We can confirm that this is the first time the IOCCC has been used -to peer-review a new research. We had quite a bit of fun with a sharpie and a -scanner.
- -This entry takes a BMP image file of hand-drawn (mouse-drawn?) text, specified as the first command-line parameter, and converts it to an ASCII text document. Magic!
- -BMP files created by most paint programs should work. The author recommends Paint.NET.
- -clang warns about unused expression results, missing type specifiers, and incompatible pointer conversions - all just a fun consequence of the obfuscations.
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Adrian Cable
-adrian.cable@gmail.com
make cable3
-
-
-./cable3 bios-image-file floppy-image-file [harddisk-image-file]
-
-
-./runme
-
-
-This entry weighs in at a magical 4043 bytes (8086 nibbles, 28,301 -bits). It manages to implement most of the hardware in a 1980’s era -IBM-PC using a few hundred fewer bits than the total number of -transistors used to implement the original 8086 CPU.
- -If you are using OS X, the included sc-ioccc.terminal configuration file will -correctly display console applications that use ANSI graphics.
- -Update: This entry now has its own web page http://www.megalith.co.uk/8086tiny
- -The author hereby presents, for the delectation (?) of the judges, a portable PC emulator/VM written specifically for the IOCCC which runs DOS, Windows 3.0, Excel, MS Flight Simulator, AutoCAD, Lotus 1-2-3 …
- -In just 4043 bytes of C source, you get a complete mid-late 1980s-era IBM-compatible PC, consisting of:
- -The emulator uses the SDL graphics library for portability, and compiles for Windows, Mac OS X, Linux and probably most other 32-bit/64-bit systems too.
- -If you like living on the edge you can try building the emulator on a big endian machine, and you will get an emulation of a big endian 8086, a rather bizarre and somewhat useless beast. For everyone else, please run the emulator on a little endian machine.
- -RULE 2 ABUSE DISCLAIMER
- -/RULE 2 ABUSE DISCLAIMER
- -This entry has been tested on Windows (compiled with MS Visual Studio 2010 and 2013), Mac OS X (clang and gcc), and Linux (clang and gcc). The Makefile supplied is good for Mac OS X, Linux and probably other UNIXes. I have received reports that the emulator works on Raspberry Pi/Android/ARM (you will need to compile with -fsigned-char) and iOS. You will need to adjust the Makefile if your system lacks sdl-config to correctly point to the SDL libraries and header files.
- -On UNIX-based systems we can get raw keystrokes using stty. However Windows has no stty. Therefore the Makefile includes a -D entry to define a “keyboard driver” KB which as it stands is suitable for UNIXes, but maybe not non-UNIX platforms. For example, for Windows/MS Visual Studio, instead of the Makefile definition of KB, use something slightly different - add the following entry to the Preprocessor Definitions list in the Project Properties page:
- -KB=(kb=H(8),kbhit())&&(r[1190]=getch(),H(7))
-
-
-The code as supplied uses implicit function declarations for POSIX file I/O and in doing so assumes that file offsets are the same bit width as your architecture. For some systems (e.g. 32-bit Mac OS X, which uses 64-bit file offsets) this is not the case, and to run successfully on these systems, you will need to explicitly declare these functions by adding the appropriate include to the top of the source:
- -#include <unistd.h>
-
-
-./cable3 bios-image-file floppy-image-file [harddisk-image-file]
-
-
-PLEASE NOTE that under UNIXes the keyboard must be in raw mode for the emulator to work properly. Therefore the emulator is best run from a shell script that looks something like:
- -stty cbreak raw -echo min 0
-./cable3 bios floppy.img harddisk.img
-stty cooked echo
-
-
-The simplest use of the emulator is with a single floppy boot disk image, like the fd.img provided, which is a FreeDOS boot disk.
- -Before running the emulator on a Unix-type system, stty needs to be used to put the keyboard into raw mode (and afterwards it needs to be put back to cooked). So, run the emulator using something like this script (provided as “runme”):
- -stty cbreak raw -echo min 0
-./cable3 bios fd.img
-stty cooked echo
-
-
-Easiest to start with is to try a ready-made 40MB hard disk image containing a whole bunch of software:
- - - -For the more adventurous, you can start off with (for example) a blank 40MB image file called hd.img made using e.g. mkfile. Then use:
- -stty cbreak raw -echo min 0
-./cable3 bios fd.img hd.img
-stty cooked echo
-
-
-Preparing the hard disk for use in the emulator is done just like a real PC. Boot the emulator, and use FDISK to partition the hard disk. When it’s done FDISK will reboot the emulator. Then you can use FORMAT C: and you are done. The resulting disk image is in the right format to be mounted on a real Windows PC using e.g. OSFMount, on a Mac using hdiutil, or on Linux using mount, providing an easy way to copy files and programs to and from the disk image. Or, you can install programs from regular floppy disk images (see “Floppy disk support” below).
- -The emulator simulates an XT-style keyboard controlled by an Intel 8042 chip on I/O port 0x60, generating IRQ1 and then interrupt 9 on each keypress. This is harder than it sounds because a real 8042 returns scan codes rather than the ASCII characters which the C standard I/O functions return. Rather than make the emulator less portable and use ioctl or platform-dependent equivalents to obtain real scan codes from the keyboard, the emulator BIOS does the reverse of a real PC BIOS and converts ASCII characters to scancodes, simulating press/release of the modifier keys (e.g. shift) as necessary to work like a “real” keyboard. The OS (DOS/Windows) then converts them back to ASCII characters and normally this process works seamlessly (although don’t be surprised if there are issues, for example, with non-QWERTY e.g. international keyboards).
- -Most of the time you can just type normally, but there are special sequences to get Alt+xxx and Fxxx.
- -To send an Alt+XXX key combination, press Ctrl+A then the key, so for example to type Alt+F, press Ctrl+A then F.
- -To send an Fxx key, press Ctrl+F then a number key. For example, to get the F4 key, press Ctrl+F then 4. To get F10, press Ctrl+F then 0.
- -To send a Page Down key, press Ctrl+F then O. To send a Page Up key, press Ctrl+F then E. Other key combinations are left for the discovery of the user.
- -The emulator supports both text output via the standard BIOS interrupt 0x10 interface, and also direct video memory access (one page, 4KB video RAM at segment B800) in 80x25 CGA 16-color text mode.
- -BIOS text output calls are converted to simple writes to stdout. Direct video memory accesses for the 80x25 CGA color text mode are converted to ANSI terminal escape sequences. If you are using a terminal which does not support ANSI (e.g. you are compiling the emulator with MS VC++ and running in a Windows console window) then PC applications that directly write to video memory in text mode may be unusable.
- -Most CGA I/O ports are not supported except for the CGA refresh register at 0x3DA, which some applications use for timing or synchronisation.
- -The regular PC character code page (437) includes various extended ASCII characters for things like line drawing. You might want to set the font in your terminal program to something that includes these (e.g. on Mac OS X there is a freeware font called Perfect DOS VGA 437 which does the trick).
- -Occasionally a DOS application on exit will leave the video hardware in an odd state which confuses the emulator, resulting in subsequent text output being invisible. If this happens, just use the DOS CLS command to clear the screen and all will be well again.
- -Hercules 720x348 monochrome graphics mode emulation is implemented using SDL. Most Hercules features are supported via the normal I/O interface on ports 0x3B8 and 0x3BA including video memory bank switching (segments B000/B800), which some games use for double-buffered graphics. CGA graphics modes are not supported.
- -When an application enters graphics mode, the emulator will open an SDL window (which will be closed when the application goes back to text mode). Including code to redirect keystrokes from the SDL window to the main terminal window would have busted the IOCCC size limits, so you need to keep the main emulator terminal window in focus at all times even when you are doing graphics (sounds a little odd but you will get used to it).
- -On UNIXes, SDL will automatically output graphics via X11 if the DISPLAY environment variable is set up.
- -Some applications (e.g. AutoCAD) support a PC configuration with a CGA card and a Hercules card, for simultaneous text and graphics output on different displays. The emulator simulates this configuration, too, using separate windows for the (terminal) text and (SDL) graphics displays.
- -Like a real PC, the emulator needs a BIOS to do anything useful. Here we use a custom BIOS, written from scratch specifically for the emulator. Source code for the BIOS (written in 8086 assembly language) which compiles with the freely-available NASM x86 assembler is available from the author on request.
- -The BIOS implements the standard interrupt interfaces for video, disk, timer, clock and so on, much as a “real” PC BIOS does, and also a small timer-controlled video driver to convert video memory formatting into ANSI escape sequences when the emulator is in text mode.
- -Memory map is largely as per a real PC, with interrupt vector table at 0:0, BIOS data area including keyboard buffer at 40:0, CGA text video memory at B800:0, Hercules dual-bank graphics memory at B000/B800:0, and BIOS at F000:100. Unlike a real PC, in the emulator the CPU registers are memory-mapped (at F000:0), which enables considerable optimisation of the emulator’s instruction execution unit by permitting the unification of memory and register operations, while remaining invisible to the running software.
- -CPU supports the full 8086/186 instruction set. Due to the complexities of the 8086’s arbitrary-length instruction decoding and flags, 8086 instructions are first converted to a simpler intermediate format before being executed. This conversion, along with instruction lengths and how each instruction modifies the flags, is assisted by some lookup tables which form part of the BIOS binary.
- -The CPU also implements some “special” two-byte opcodes to help the emulator talk with the outside world. These are:
- -0F 00 - output character in register AL to terminal
-0F 01 - write real-time clock data (as returned by localtime) to memory location ES:BX
-0F 02 - read AX bytes from disk at offset 512*(16*SI+BP) into memory location ES:BX. Disk is specified in DL (0 = hard disk, 1 = floppy disk)
-0F 03 - write AX bytes at memory location ES:BX to disk at offset 512*(16*SI+BP). Disk is specified in DL as per 0F 02
-
-
-Emulator exit is triggered if CS:IP == 0:0 (which would be nonsensical in real software since this is where the interrupt vector table lives). The supplied Dos6.22.img disk includes a small program QUITEMU.COM which contains a single JMP 0:0 instruction, to allow the user to easily quit the emulator without shutting down the terminal.
- -Emulates a 3.5" high-density floppy drive. Can read, write and format 1.44MB disks (18 sectors per track, 2 heads) and 720KB disks (9 sectors per track, 2 heads).
- -If you want to install your own software from floppy images (downloaded from e.g. Vetusware), the easiest way to “change disks” is to copy each disk image in turn over the floppy image file you specify on the command line. Don’t forget to put your original boot disk back at the end!
- -Supports up to 1023 cylinders, 63 sectors per track, 63 heads for disks up to 528MB.
- -Disk image format used is a subset of the standard “raw” format used by most disk image mount tools. In general, disk images prepared by the emulator will work with disk image tools and other emulators, but not the other way around.
- -The emulator uses a particularly dumb algorithm to derive a simulated cylinder/sector/head geometry from the disk image file’s size. This algorithm often results in not all the space in the image file being available for disk partitions. For example, creating a 40,000,000 byte image file results in DOS FDISK seeing only 31.9MB as the volume size.
- -Note that unlike a real PC, the emulator cannot boot from a hard disk (image). Therefore, you will always need to use a bootable floppy image, even if after boot everything runs from the HD.
- -No mouse is emulated.
- -Reading the RTC (both time and date) is emulated via the standard BIOS clock interface, pulling the time/date from the host computer. Setting the time or date is not supported.
- -A countdown timer on I/O port 0x40 is simulated in a broken way which is good enough for most software. On a real PC this has a default period of 55ms and is programmable. No programmability is supported in the emulator and the period may be about right or completely wrong depending on the actual speed of your computer.
- -On a real PC, IRQ0 and interrupt 8 are fired every 55ms. The emulator tries to do the same but again, the delay period is uncalibrated so you get what you get.
- -Beeps only, through the console.
- -The emulator will run practically any software a real PC (of the spec listed at the top of this file) can. The author has tested a number of OSes/GUIs (MS-DOS 6.22, FreeDOS 0.82pl3, Windows 3.0, DESQview 2.8), professional software (Lotus 1-2-3 2.4 and AsEasyAs 5.7 for DOS, Excel 2.1 for Windows, AutoCAD 2.5, WordStar 4), programming languages (QBASIC, GWBASIC, Turbo C++), games (Carrier Command, Police Quest, and a bunch of freeware Windows games), and diagnostic/benchmark software (Manifest, Microsoft MSD, InfoSpot, CheckIt) and all of them run well.
- -Screenshots of some of these applications running (on Mac OS X) are provided for the impatient.
- -A lot of compiler warnings are produced by clang. Missing type specifiers, control reaching the end of functions without returning values, incompatible pointer type assignments, and some precedence warnings, all necessary to keep the source size down. Other compilers are likely to produce similar warnings.
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
make dlowe
-
-
-./dlowe [numbers...]
-
-
-./dlowe 0 1 2 3 4 5 6 7
-./dlowe 16 32 64 128
-
-echo sparkline of file sizes: `wc -c * | awk '{print $1}' | xargs ./dlowe`
-
-./dlowe 0
-
-
-We liked how this entry used Unicode, specifically UTF-8, in a somewhat obfuscated way.
- -Also, why doesn’t it crash, and produces a correct output when called with one argument -or when all arguments are equal?
- -For extra fun, compile and run
- -#include <stdio.h>
-int main() {
- printf("%d %d %d\n", (int)(-1.0/0.0), (int)(0.0/0.0), (int)(1.0/0.0));
-}
-
-
-with gcc and clang.
- -With GCC (4.7.2), we get
- --2147483648 -2147483648 -2147483648
-
-
-and with clang (3.3), we get
- --2147483648 0 2147483647
-
-
-Which one is correct? :)
- -A tiny implementation of command-line ‘sparkline’ data visualization.
- -$ sparkl 0 1 2 3 4 5 6 7
-▁▂▃▄▅▆▇▉
-
-$ echo sparkline of file lengths: `wc -c * | awk '{print $1}' | xargs sparkl`
-sparkline of file sizes: ▁▁▁▃▃▂▁▂▁▁▉
-
-
-This is a handy little tool for visualizing numeric series from the -command-line, using ‘sparklines’. Pass it a numeric series as arguments, and -sparkl will display a sparkline graph, which you can use to very quickly get a -sense of the shape of your data.
- -The code is very terse. I was torn between submitting this version, and a -one-line version compressed using a couple more -D flags.
- -Hand-rolled utf-8 sequence, magic numbers (what’s that 7 for?), meaningless -variable names, reused variables, and so on.
- -Edward Tufte invented sparklines (among other things.) Brilliant.
- -Zach Holman’s ‘spark’ utility was absolutely -an inspiration.
- -As I was writing up this description, I discovered I’m not the first person to -write an obfuscated C sparkline utility! Vicent Martí created -this one years (!) ago. (My -implementation is completely independent.)
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Yusuke Endoh
-mame@ruby-lang.org
-https://github.com/mame/
make
-
-
-This builds endoh1, echo, hello, and tac.
- -./endoh1 [file.lazy]
-
-
-./endoh1 hello.lazy
-./hello
-echo Hello | ./echo
-./tac < endoh1.c
-
-
-Be patient with the last one.
- -We liked this entry because it can serve as a standalone program as well as an include file; and, as usual, -because its input data is at least as obfuscated as the program itself.
- -This entry can be considered an abuse of the GCC’s optimizer; it takes GCC about 4x longer to compile it -with -O3 than without, compared to clang’s 2x.
- -$ less prog.c
-$ gcc -o prog prog.c
-$ ./prog
-
-
-… Isn’t there any more to it?
- -Yes, of course.
- -This is a tool for C programmers to play the SKI combinator calculus, -especially, Lazy K.
- -This program will shine when it is used as a library.
-For example, hello.lazy is a “Hello world” program written in Lazy K.
$ lazy hello.lazy
-Hello, world!
-
-
-where lazy is a reference implementation of Lazy K.
-At the same time, hello.lazy is a valid C program that uses prog.c as a library.
$ gcc -o hello -xc hello.lazy
-$ ./hello
-Hello, world!
-
-
-In other words, this program is a kind of polyglot.
- -The usage is simple:
-you just have to wrap Lazy K program with #include "prog.c".
-Note that # is a comment in Lazy K.
… is inherent in SKI combinator calculus :-)
- -In addition, it uses various hacks to parse SKI code as C, -and to satisfy IOCCC’s size rule.
- -These led to the good obfuscation. -See Spoiler section in detail, if you need.
- -This program supports only “Combinator-calculus style notation” of Lazy K.
-“Unlambda style” and “Iota and Jot” style are not supported.
-Also, it requires a space between identifiers.
-In short, use (S K) instead of (SK), “`sk”, **i*i*i*ii*i*i*ii,
-or 11111100011100.
Huge memory may be required to compile the program -(about 300 MB on my machine).
- -In addition, there are some limitations (and workarounds) -mentioned in Spoiler section. -But I think it wouldn’t matter only when you run the attached programs.
- -I confirmed that the program successfully worked -with the following compilers.
- -Recent compilers with -Wall -W -Wextra -pedantic say nothing.
gcc -Wall -W -Wextra -pedantic prog.c
-clang -Wall -W -Wextra -pedantic prog.c
-tcc -Wall -W -Wextra -pedantic prog.c
-
-
-I think it will work on almost all platforms. I confirmed:
- -To check whether the program is specified on the command line
-or included from another source file,
-the program uses a predefined macro __INCLUDE_LEVEL__.
-It is a gcc extention, and also supported by clang.
-If your compiler does not support it,
-you cannot use the program as a library.
-But you can compile and run it as a standalone program, at least.
-In fact, tcc does not support the macro, but does work.
Gur jubyr cebtenz vf vagrecergrq ol znpeb rkcnafvba.
-Sbe rknzcyr, F (X V) vf genafyngrq gb n abezny P pbqr, (f)((x)(v)),
-be fvzcyl f(x(v)).
-Guvf rkcerffvba ergheaf na nofgenpg flagnk gerr,
-naq cebt.p rinyhngrf vg.
-Guvf cebtenz hfrf irel fvzcyr “grez erjevgvat” nccebnpu
-sbe rinyhngvat FXV pbzovangbe pnyphyhf.
-Gur erjevgvat ehyrf ner fubja va gur funcr bs gur pbqr.
Pbafvqre n frdhrapr bs shapgvba nccyvpngvbaf va P:
- -f(k)(k)(k)(k)...
-
-
-Jung glcr fubhyq f unir?
-Hasbeghangryl, P qbrf abg cebivqr n “erphefvir glcr”,
-fhpu nf glcrqrs s (*s)();.
-Fb, V hfrq n urniyl arfgrq shapgvba cbvagre glcr:
glcrqrs ibvq *(*(*(*...(*(s))()...)())())
-
-
-Guvf yvzvgf ubj znal nethzragf bar shapgvba pna or pbafrphgviryl nccyvrq gb.
-Ohg lbh pna vapernfr gur ahzore ol gjrnxvat gur qrsvavgvba bs znpeb c.
Arkg, jr arrq gb rapbqr “pybfherf”. -N pybfher vf n shapgvba gbtrgure jvgu na raivebazrag -juvpu vf n ersrerapr gb aba-ybpny inevnoyr.
- -Va guvf pnfr, jr arrq fbzrguvat gung:
- -Ubjrire, ab glcr va P vf pnyynoyr naq unf n ersrerapr ng gur fnzr gvzr. -(Vg vf srnfvoyr ol qlanzvp pbqr trarengvba, ohg vg vf sne sebz cbegnoyr.)
- -Fb, V nqqerffrq guvf vffhr ol trarengvat znal shapgvba qrsvavgvbaf -fgngvpnyyl ol (no)hfvat znpebf:
- -ibvq *k1; ibvq s1(ibvq *l) { erghea nccyl(k1, l); }
-ibvq *k2; ibvq s2(ibvq *l) { erghea nccyl(k2, l); }
-ibvq *k3; ibvq s3(ibvq *l) { erghea nccyl(k3, l); }
-...
-ibvq *(u[]) = { s1, s2, s3, ... }
-
-
-naq ol nyybgvat rnpu bs gurz jura n pybfher vf arrqrq.
- -Guvf yrnqf gb nabgure yvzvgngvba:
-gur ahzore bs cer-qrsvarq pybfherf yvzvgf
-ubj znal vaqragvsvref (F X V) bar cebtenz pna hfr.
-Ohg lbh pna vapernfr guvf ahzore
-ol gjrnxvat gur qrsvavgvba bs znpeb N O P naq Q.
-(Abgr gung pybfherf ner nyybggrq bayl jura cnefvat;
-nsgre gur rinyhngvba fgnegf, “bhg bs pybfher” pnaabg bpphe.)
Guvf znetva vf gbb aneebj gb pbagnva n qrgnvyrq rkcynangvba.
-Vafgrnq, V whfg nfx lbh bar dhrfgvba.
-Pna lbh gryy jung i f[]={0,0,f+6,f+2,f+4,f,f+3,f+5,f+1}; vf?
-V sbhaq guvf ol hfvat FZG fbyire.
![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Yusuke Endoh
-mame@ruby-lang.org
-https://github.com/mame/
make endoh2
-
-
- make all
-
-
-You’ll need to have Ruby installed to run all the automated check
- -make check
-
-
-cat jpeg.c
-
-
-Look at jpeg.jpg in an image viewer program.
- -This is a program which, when fed its own source, generates a program that almost is its whitespace inverse, -which, in its order, generates a JPEG file (speaking of file size abuse, that is about 16.4 times -larger than a PBM file with the same image, but the source was also abusing the size counting program…)
- -Don’t pay attention to the OCR behind the ruby curtain — it’s a straightforward bitmap comparison.
I picked JPEG instead of PNG, GIF, or BMP
-because it is the most difficult to generate.
-I believe that the JPEG encoder is the world’s smallest ever.
-Nevertheless, the program was too big to meet the IOCCC’s size rule.
-So I created a smaller bootstrap program that generates the main program.
-prog.c contains fragments of the main program as a comment
-which iocccsize -i does not count.
-I gratefully think the judges for spoiling the size rule this year.
I think the program will work on any major platforms and compilers.
- -This program uses (a part of) Proggy Tiny Fonts -which is distributed in MIT License:
- -Copyright (c) 2004, 2005 Tristan Grimmer
-
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of this software and associated documentation files (the "Software"),
-to deal in the Software without restriction, including without limitation
-the rights to use, copy, modify, merge, publish, distribute, sublicense,
-and/or sell copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
-
-
-![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Yusuke Endoh
-mame@ruby-lang.org
-https://github.com/mame/
make endoh3
-
-
-./endoh3
-
-
-Trying this out will depend on how your system can play sounds. The author’s -remarks include some options for different operating systems.
- -The simplest way is to create a .wav file and have your system play that.
- -echo 'CDEFGABc' | ./endoh3 | ruby wavify.rb > cde.wav
-
-
-There are also some other musical samples, twinkle.abc and menuet.abc.
- -This program can tweet out a tune and is small enough to tweet.
- -This is a sound synthesizer for a subset of ABC music notation.
- -Try:
- -gcc -o prog prog.c
-echo "CDEFGABc" | ./prog > /dev/dsp
-
-
-If /dev/dsp is not available on your system, use an OSS sound wrapper such
-as padsp or aoss:
echo "CDEFGABc" | ./prog | padsp tee /dev/dsp > /dev/null
-
-
-If you are using Mac OS X, try sox:
- -echo "CDEFGABc" | ./prog | sox -q -traw -r8000 -b8 -e unsigned-integer - -tcoreaudio
-
-
-If they do not work, use the attached script to convert the output -into a wave file format:
- -echo "CDEFGABc" | ./prog | ruby wavify.rb > cde.wav
-
-
-and play cde.wav.
You can enjoy some music scores that I attached:
- -cat twinkle.abc | ./prog > /dev/dsp
-cat menuet.abc | ./prog > /dev/dsp
-
-
-The following sequence of questions may be helpful to understand the program.
- -89/84.? I found it by using Stern-Brocot tree.The following features are supported:
- -C D E F G A B (in low octave)c d e f g a b (in high octave)zA (an eighth note)A2 (a quarter note)A3 (a dotted quarter note)A4 (a half note)The following features are not supported:
- -^C _C
-
-C1/2
-
-C0.5 instead.c' C,T:title L:1/4You can not write a note length immediately followed by a note E,
-such as C2E2.
-Can you know why?
-You can work it around by inserting a whitespace: C2 E2.
I tested it on:
- -I believe that all the scores that I attached are out-of-copyright.
- -I did write a score of the Happy Birthday song too. -(It does not matter because the song is out-of-copyright in my country.) -But I do not attach it to protect you from W****r.
- -For the same reason, do not play a score that contains only z1092.
-You know, it is “the famous song”.
Urer vf n zntvpny rkcerffvba juvpu V sbhaq ol oehgr-sbepr:
- -(p % 32 + 5) * 9 / 5 % 13 + a / 32 * 12 - 22
-
-
-Vagrerfgvatyl, vg pbairegf na NFPVV ahzore bs NOP abgrf -gb gur pbeerfcbaqvat gbar ahzore.
- -'P' (NFPVV 67) => 3
-'Q' (NFPVV 68) => 5
-'R' (NFPVV 69) => 7
-'S' (NFPVV 70) => 9
-'T' (NFPVV 71) => 10
-'N' (NFPVV 65) => 12
-'O' (NFPVV 66) => 14
-'p' (NFPVV 99) => 15
-'q' (NFPVV 100) => 17
-'r' (NFPVV 101) => 19
-'s' (NFPVV 102) => 20
-'t' (NFPVV 103) => 22
-'n' (NFPVV 97) => 24
-'o' (NFPVV 98) => 26
-
-
-Ol gur jnl, lbh pna jevgr n unys-gbar ol gur sbyybjvat punenpgref.
- -'X' => 4 (= P#)
-'Y' => 6 (= Q#)
-'H' => 8 (= S#)
-'I' => 11 (= T#)
-'C' => 13 (= N#)
-
-
-Abgr gung gur gbar ahzoref fvzcyl rahzrengr gur frzv-gbar fgrcf.
-Fb jr pna pnyphyngr gur serdhrapl rnfvyl: cbj(2, a / 12.0).
-Gura, ubj pna jr pnyphyngr cbj jvgubhg zngu.u?
-cbj(2, 1.0 / 12.0) vf nccebkvzngrq ol 89/84..
-(V sbhaq guvf nccebkvzngvba ol hfvat Fgrea-Oebpbg gerr.)
-Jr pna tnva gur serdhrapl ol zhygvcylvat gur inyhr a gvzrf.
Svanyyl, gur sbyybjvat pbqr trarengrf n fnj jnir:
- -sbe(p = 0; p < yra; p++) chgpune(n = a * Q);
-
-
-jurer Q vf n serdhrapl naq n vf n inevnoyr jubfr glcr vf pune.
-Ol nffvtavat sybng gb pune inevnoyr, gur vzcyvpvg glcr pbairegvba vf cresbezrq sebz sybng gb pune (zbqhyb 256).
-(Fgevpgyl fcrnxvat, guvf orunivbe vf haqrsvarq nppbeqvat gb 6.3.1.4 va P99;
-lbh pna ercynpr vg jvgu (ybat)(a*Q) vs lbh ner crqnagvp.)
Nyy gung jnf yrsg jnf gb pbzovar naq pbaqrafr gur pbzcbaragf. -Gur xrl vf fdhnfuvat gurz vagb whfg bar sbe-ybbc.
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Yusuke Endoh
-mame@ruby-lang.org
-https://github.com/mame/
make endoh4
-
-
-./endoh4
-
-
-NOTE: The author recommends the use of xterm.
- -./endoh4 < cube.txt
-
-
-For example, if you are a soccer fan, try:
- -make all
-./endoh4 < solids/archimedian-solid/a11-truncated-icosahedron.txt
-
-
-This program is formatted as the net for a tetrahedron. (hint, try feeding the -program it’s own source code). When it runs there is an animation for the -computation to work out the convex hull.
- -This is a convex polyhedron viewer, which:
- -This simple spec involves many details.
- -"',;;;,;'"(Note that this program does not use math.h.)
I think it conforms with both C89 and C99. -I confirmed that it worked on gcc, clang, and tcc. -It should not be warned with -pedantic and -Wextra.
- -You may want to use tput to hide a terminal cursor.
tput civis
-./endoh4 < cube.txt
-tput cnorm
-
-
-You can change the screen size. Let the aspect ratio be about 3:1.
- -gcc -DS=120,40 -o endoh4 endoh4.c
-
-
-The shape of this code is the geometric net of a regular tetrahedron. - So, try:
- -./endoh4 < endoh4.c
-
-
-The solids.tbz2 file includes various solid data: -Platonic solids, -Archimedean solids, -Prisms, -Antiprisms, -Bipyramids, -Trapezohedrons, and -Johnson solids.
- -I created the files by using the POV-Ray scripts -(1 and - 2) -in Wikipedia. -They are copyrighted in CC BY-SA 3.0 -by “User:Cyp” and “User:AndrewKepert”.
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Qiming Hou
-hqm03ster@gmail.com
-http://www.houqiming.net
make hou
-
-
-./hou [scene-file-name] [options]
-
-Follow the instructions in stdout, preferably with an auto-refreshing PPM image viewer ready.
-Refresh the image every time the output refreshes, all effects should be more or less recognizable when you see 16.
-
-
-./hou BIG
-./hou old_default.scene BIG
-./hou otherroom.scene
-./hou otherroom.scene NAIVE
-
-
-You could consider that this program violates the source code size -limit. This is because the first compliation of this program is -really just a decompressor to generate the real source code of the -program.
- -This program will loop infinitely while progressivly refining a -raytraced image.
- -This program is a programmable rendering engine with a built-in default scene. The standard command line is:
- -./hou [scene-file-name] [options]
-
-
-As hou runs, it writes a progressively refining image to a ppm file specified in the scene. The initialization may take a while, but once it’s done, a rough preview should be available in seconds. Leave hou running for the night, and you get a high quality result like the attached *.jpg files. Kill hou manually after you’re satisfied with the image quality.
- -To save time and energy for the judges, rendered images for all provided scenes are provided as attached files.
- -Fully programmable: Almost every stage of the renderer is programmable with a shader, i.e., a short script that does something rendering-related. In particular, each scene consists of one or more geometry shaders, a camera shader, and one or more material shaders. Shaders are written in an interpreted language that supports basic arithmetic, a few math functions, variables and procedural call in the CPS (Continuation Passing Style).
Fast preview: This renderer isn’t just a naive path tracer, it actually uses a modern global illumination algorithm which is robust against challenging scene configurations. You can mostly place light sources and specify surface properties as you please without worrying too much about the convergence speed – you always get a nice fast preview within one or two minutes. As proof, there is a comparison: “./hou otherroom.scene” gives a rough idea about the overall illumination at 16 samples per pixel (i.e., when the program prints 16), whereas the naive approach “./hou otherroom.scene NAIVE” only produces a mess of white dots.
Rich visual effects: The algorithm samples all light path types so most physically based effects can be produced. The default scene demonstrates quite a few of them: reflection, area light, soft shadows, color bleeding, caustics, and depth-of-field blur. Of course, one can also get programmable-shading effects like procedural texturing and approximated Fresnel terms.
Accelerated ray tracing: The ray tracing part uses an algorithm better than the brute-force intersection of everything. The renderer even builds an acceleration data structure! Despite the double precision and the single-threaded-ness, it still runs at about 0.5 million rays per second on the author’s machine.
Pause and resume: Can’t run ./hou overnight? No problem! You can kill and resume a rendering session whenever you want. The renderer automatically saves the progress every 16 samples and resumes where it’s left off when restarted. Also, each scene/parameter combination gets a different saved session so you don’t have to worry about conflicts.
hou.c uses compression to get around the size limit. The compression fully complies with the rules and the guidelines (at least the portion that shows up in grep “size limit”). Please see the “Self-imposed restrictions” section below for more details.
hou does not terminate (as suggested by the second line of rule 6).
The building process does not involve any OS tool beyond cc and make. No gzip compression! a.c.gz doesn’t fit in 2053 bytes, anyway.
Neither hou.c nor a.c (the real decompressed source) uses #define (or cc -D) at all.
The source code is not required at runtime.
a.c does not drop optional features to reduce size. There are pure optimization code that can be dropped without affecting the converged output (only affecting the ray tracing speed / convergence rate). All files are properly fopened with “rb” / “wb” for Windows compatibility. The PPM header has a comment line for non-standard-compliant viewers (specifically, my old HDRShop 1.0). And there is a nice text message saying “please wait…”.
Despite the messy look, a.c and hou.c compiles warning-free (hou.c even wastes 18 bytes on #include<stdio.h> just for putchar). a.c compiles mostly clean in the C99/ANSI modes of clang and gcc (with -Wall –pedantic). The only warning generated is a pedantic one: “string constant too long”.
Both the compression and the rendering use mathematically involved algorithms. Understanding the C doesn’t help much if one isn’t familiar with the math.
Modern renderers provide shader access to just about any internal state. This one follows suit and reuses the same shader-accessible array for all important internal states.
Infinity and not-a-number are used during normal course of execution.
Previous image-generating entries may take care to hide the “IOCCC” string in the code, but they leave the text clear in the result. This entry takes it further and obfuscates the output image as well. Can you find the text in the image? Hint: look up.
a.c leaves all shaders in plain text, but the plain text shader code can’t be taken for its face value – the arithmetic rules subtly diverge from our common sense.
a.c is less portable than hou.c itself. hou.c only depends on ASCII and should run just fine on 16-bit, small memory, or float-incapable machines. a.c, while still reasonably portable, is quite memory consuming, requires IEEE754-compliant double, and assumes int to be 32-bit.
Though technically endian-dependent, a.c remains portable providing that one doesn’t copy saved sessions across endians.
3225 3225 3225 9 9 3225 3225
- 1 1 1 1 1 1 1 1 1 1
- 4225 1226 1 1 1 1 1222 1226
- 1 1 1 1 1 1 1 1 1
- 4226 1 4226 8 4222 4226 1 1
-
-
-The program consists of a recursive-descend interpreter, a 3DDDA (3D Discrete Differential Analysis) ray tracer, a PSSMLT (Primary Sample Space Metropolis Light Transport) light path sampler, all squeezed into the size limit using a PPM compressor (Prediction by Partial Matching, and yes, the output format is chosen for the pun).
- -PSSMLT uses the Metropolis-Hasting algorithm to sample a 32D unit hypercube. Each point in the hypercube is interpreted as a sequence of random numbers, and is sent to a path tracer to generate a light path. The point’s Metropolis-Hasting energy is then defined as the corresponding path’s contribution value to the final image. Since each path is sampled with a probability proportional to its energy, the sample distribution directly corresponds to the final image, which can then be produced as a simple per-pixel histogram of all generated paths. The robustness comes from a state mutation strategy that actively tries to explore the neighborhood of high energy peaks (e.g. paths that happen to hit the light source in otherroom.scene). In addition, a rudimentary form of lens path stratification is added to balance the attention each pixel receives. The Metropolis-Hasting process completely avoids the tell-tale pixel sampling loop required in most other image generation methods.
- -The 3DDDA tracer is chosen for scalability: its performance doesn’t get much worse as scene complexity increases. Another benefit is that with the DDA code in place one can naturally use hierarchical grids as an acceleration structure. The downside, of course, is that the setup involves quite a few divisions, which naturally turns into division-by-zeros. Fortunately, the IEEE754 standard has a nice set of rules just for this purpose and the arithmetics are organized in a specific way to take advantage of this. The shader interpreter component is relatively straightforward, just an expression evaluator stripped to the bare minimum – it doesn’t even support numerical constants natively. A final little bit is a just-good-enough PRNG (Pseudo Random Number Generator) to replace the low precision Windows rand() and the non-C99 Unix drand48(). An overnight session would run through its short period many times, but that doesn’t necessarily map to the same set of paths in PSSMLT. After all, Metropolis et al. used an even worse PRNG in their 1953 paper.
- -The PPM compressor uses statically weighted fixed order contexts with an arithmetic encoder tweaked for iocccsize. The encoder emits octet-space pairs where each octet encodes ~6.5 bits of information and each space encodes 2 bits (thanks to the generous definition of “space” in iocccsize.c). The compressor actively shuffles the variable names around until the compressed string happens to contain enough “{}; ” to pass the final iocccsize test. There are a few other tweaks:
- -The PPM model uses mostly whitespace characters for weights.
The encoder never emits ‘“’ and ‘\’.
The decoder uses an O(n2) algorithm to avoid the gigabytes-sized hash table frequently found in other PPM implementations.
![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Christopher Mills
-mrxo@sonic.net
make mills
-
-
-./mills
-
-
-./mills &
-
-
-While that is running, point your favorite browser at: http://localhost:8224
- -Who will be the first to post an image rendered during a leap-second?
- -This program is a handy graphical clock. Simply run the program, click OK to -any annoying security dialogs that pop up (aren’t those annoying?), then fire -up your web browser and type in the following URL:
- -- -
You will soon be presented with a lovely dynamically rendered 3D scene that -also convienently tells you the current time!
- -The program will continue to give you the time of day as it changes by
-reloading the page as often as it can render. If you grow tired of watching
-your life slip by, hit Control-C in the original window. Note that if you
-want to restart the program again, you should wait a minute or two before
-doing so. For details as to why this is necessary, feel free to Google
-TIME_WAIT. And while you are there, click on an ad. They could use the
-money.
It would be possible to fix this by adding
- -n=1,setsockopt(s,SOL_SOCKET,SO_REUSEADDR,&n,sizeof n),
-
-
-at an appropriate spot in the code (an exercise left to the reader). However, -as this limitation is documented, it is not techinally a bug.
- -The program wears many hats (not literally). It is
- -It replies to web requests with a PNG image that uses the -Adam7 -encoding to return data progressively. Since the data is returned in Adam7 -format, the scene is displayed initally at a lower resolution and allowed to -be progressively refined as time goes on. The ray tracer is integrally tied -to the PNG encoder, casting rays in the Adam7 order. The web server uses -PNG primarily because of PNG’s ability to return data progressively, and not -as you might think because the PNG standard is so obfuscated as to require -both little- and big-endian encodings at different spec layers.
- -Since ray-tracing was an obvious choice to return to a web server, I needed -something to ray-trace. A static scene would be uninteresting. I took -inspiration (as I often do) from the IOCCC remarks file which says
- -- -At least one judge prefers to maintain the use of the leap-second - as part of the world’s time standard.
Then it was obvious; The code should display the time. It is believed (but -not confirmed) that the code will, in fact, display leap seconds correctly.
- -To display the time, of course we would need a font. This font is encoded -as a string, using only the C whitespace characters. Clearly, the judges -intended this use of whitespace for data compression, since their tool -doesn’t count whitepsace in strings differently than whitespace outside of -them.
- -The code can be user-modified simply by changing the build command line. -The following symbols are defined in the build file:
- --DLT=x1,y1,z1,x2,y2,z2,...
Defines the coordinates of the lights in the scene. It should be a -comma-separated list of coordinates (x, y, z), three per light.
-DNL=n
Defines the number of lights. Should be equal to the length of the list -above (three times the number of lights).
-DEY=x,y,z
Defines the position of the viewer (the eyepoint) for the scene. The eye -is looking at the origin (0, 0, 0).
The original program bound the server to INADDR_ANY to allow everyone to
-experience the server’s output. The Judges suggested that I instead restrict
-the bind to INADDR_LOOPBACK to reduce security alarms. As a compliant veteran
-of innumerable post-ship late feature additions, I have modified the Makefile
-to inject the new code without destroying the beautiful spherical symmetry of
-the source code. In addition, I have altered the word sin_port to the more
-family-friendly version win_port to protect against curious impressionable
-youth trying to learn about sockets on Internet.
![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Don Yang
-omoikane@uguu.org
-http://uguu.org/
make misaka
-
-
-This will build a bunch of versions of the code. See the author’s details for information on all of these builds.
- -To understand the various intermediate source files that are built, try:
- -make understanding
-
-
-./horizontal_cat [files...] > [output]
-./vertical_cat [files...] > [output]
-
-
-NOTE: Use - for standard input. For example:
- -./vertical_cat - -
-
-
-seq 1 12 | ./horizontal_cat - - -
-
-./long_cat
-./long_faat_cat
-./long_fat_cat
-./loong_cat
-./loooong_cat
-./loooooooong_cat
-
-seq -f '%.0f ' 45 | ./horizontal_cat - misaka.c
-
-
-There is more to cat than mere cats.
-Be they tall, fat, long or squat, this source code is sure to amuse.
While one of the judges was reviewing this entry on the stern of the -Island Sky -in the middle of the Atlantic Ocean waiting the -total solar eclipse of 2013 -the judge was stuck by a -flying fish. -While result the impact was that the -Port from Portugal was lost, the -Grog from Cape Verde -and the laptop containing this entry was saved.
- -While I’m sure most cats would have preferred otherwise, -the flying fish was returned to emswim with the fishesem. :-) -No cats were harmed in the process of judging this entry.
- -Misaka is a file concatenation utility, with at least two modes of -operation:
- -gcc misaka.c -o horizontal_cat
-./horizontal_cat [files...] > [output]
-
-./horizontal_cat misaka.c misaka.c > misaka2.c
-gcc misaka2.c -o vertical_cat
-./vertical_cat [files...] > [output]
-
-
-Where [files…] are a list of text file names. Use “-” to read from stdin.
- -One of my favorite unix utilities is cat. The best thing about it was -that it was named “cat”. That, and it’s useful for quickly showing contents -of a file. Though it was primary meant for concatenating files, that -function only seem to work if I wanted to concatenate files vertically.
- -I thought the lack of horizontal concatenation must have been an oversight, -so I implemented this utility:
- -gcc misaka.c -o horizontal_cat
-./horizontal_cat files...
-
-
-horizontal_cat concatenates files horizontally and write the output to -stdout. Each input file is padded with spaces on the right so that the -original text alignments are preserved.
- -If “-” is specified as a file name, horizontal_cat will read from stdin. -Unlike cat, horizontal_cat loads all input to memory first. Thus you -can specify “-” multiple times to get stdin multiplied horizontally. For -example, if you have seq(1) in your shell, you can add line numbers to both -sides of misaka.c like this:
- -seq -f ' %.0f ' 45 | ./horizontal_cat - misaka.c -
-
-
-Because horizontal_cat must know the maximum width of all files before -writing any output, all files must be processed at least twice. To support -stdin, file must be buffered to memory. This lead to the feature that -horizontal_cat can be used to duplicate stdin.
- -Seems like the stdin doubling feature might be useful even for concatenating -files vertically, so I included a vertical mode. But supporting vertical -mode with command line options would be no fun. Instead, vertical mode is -enabled by concatenating the source code horizontally:
- -./horizontal_cat misaka.c misaka.c > misaka2.c
-gcc misaka2.c -o vertical_cat
-./vertical_cat files...
-
-
-vertical_cat works more or less like cat, except you can use -vertical_cat to duplicate stdin:
- -./vertical_cat - -
-
-
-After horizontal_cat and vertical_cat, I thought, maybe all I really -wanted was just more cats. So I implemented one more mode, this one is -enabled by concatenating misaka.c vertically:
- -./vertical_cat misaka.c misaka.c > misaka3.c
-gcc misaka3.c -o long_cat
-./long_cat
-
-
-long_cat outputs ASCII art of a cat to stdout. You can make this cat -exponentially longer by concatenating more files vertically (up to 31 levels -high, depending on sizeof(int) for your compiler):
- -./vertical_cat misaka.c misaka.c misaka.c > misaka4.c
-gcc misaka4.c -o loong_cat
-
-./vertical_cat misaka.c misaka.c misaka.c misaka.c > misaka5.c
-gcc misaka5.c -o loooong_cat
-
-./vertical_cat misaka.c misaka.c misaka.c misaka.c misaka.c > misaka6.c
-gcc misaka6.c -o loooooooong_cat
-
-
-If your terminal has really thin fonts, you can also make this output fatter -by concatenating files horizontally:
- -./vertical_cat misaka.c misaka.c | ./horizontal_cat - - > misaka7.c
-gcc misaka7.c -o long_fat_cat
-
-./vertical_cat misaka.c misaka.c | ./horizontal_cat - - - > misaka8.c
-gcc misaka8.c -o long_faat_cat
-
-
-Output width is determined by the first level of stacked programs, so a -triangle like the following will not have horizontally expanded output:
- -./horizontal_cat misaka.c misaka.c | ./vertical_cat misaka.c - > misaka9.c
-gcc misaka9.c -o same_as_long_cat
-
-
-Finally, if you lost track of how many misaka.c you have stacked together, -you can feed the source to a brainfuck interpreter to get a overview of how -the programs are stacked. Example:
- -perl bf.pl misaka9.c
-
-
-This outputs:
- -MISAKA
-MISAKA MISAKA
-
-
-horizontal_cat and vertical_cat will exit with zero status on success.
- -If any input file fails to open, horizontal_cat and vertical_cat will -report the offending file name to stdout, and exit with nonzero status.
- -If horizontal_cat and vertical_cat ran out of memory, they will exit -with nonzero status without outputting anything.
- -horizontal_cat makes the following assumptions about input files:
- -Misaka has been verified to work on these following compiler+OS -combinations:
- -Misaka requires a C99 compiler due to the use of single line comments. -Misaka does not depend on any other C99 features.
- -Main obfuscation is in having a C program that compiles when tiled -horizontally and vertically, while using single line comments in less than -half of the lines. And maintaining a meaningful layout while doing that.
- -There are other challenges too, of course, like getting a Brainfuck program -to tile horizontally and vertically. Really, tiling code of any sort -horizontally is an interesting exercise, I encourage everyone to try this -once.
- -Other features to look for:
- -“gcc -Wall” should provide a hint to where the mode switch happens, it -does not output any irrelevant other warnings (verified on 4.6.3).
- -Extra files included in my submission are informational only, they are not -needed for the program to work.
- -The name, layout, and functionality of Misaka is inspired by a particular -stackable figure:
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Yves-Marie Morgan
-yves-marie.morgan@parrot.com
make morgan1
-
-
-echo "2013/10/03" | ./morgan1
-
-
-echo "1985/10/28" | ./morgan1
-
-echo "1996/12/31" | ./morgan1
-
-
-Try pressing the arrow keys when your focus is in the window.
- -To verify the output, try echoing the date of an evening with a clear sky. -Use binoculars and/or telescope as needed. In some cases you may need -to wait for a better time of the evening. In a few cases, such as -the South Pole in the summer, you may need to move to a different -observing site.
- -It displays the position of the 8 planets of the solar system around the sun. -The date given in the command line is in the format YYYY/MM/DD (year, month and -day). The direction keys can be used to move in time : -Left : go back 1 day. -Right : go forward 1 day. -Down : go back 20 days. -Up : go forward 20 days.
- -It handles correctly all leap years and the switch between julian calendar and -gregorian calendar (10 days missing between 1582/10/04 and 1582/10/15).
- -The scale is logarithmic to be able to display the 8 planets without having -Mercury, Venus, Earth and Mars squizzed around the sun.
- -The size is not proportinal either.
- -It also displays the position of 2 famous comets during their last approach : -- The first one arround the third IOCCC. -- The second one between the thirteenth and fourteenth IOCCC.
- -with gcc 4.7.2 on Linux Ubuntu 12.10 : -* prog.c:38:3: warning: suggest parentheses around ‘&&’ within ‘||’ [-Wparentheses] -* prog.c:40:34: warning: value computed is not used [-Wunused-value] -* prog.c:56:6: warning: suggest parentheses around ‘&&’ within ‘||’ [-Wparentheses] -* prog.c:58:50: warning: value computed is not used [-Wunused-value] -* prog.c:61:5: warning: suggest parentheses around ‘-’ inside ‘>>’ [-Wparentheses]
- -with clang 3.1 on Linux Ubuntu 12.10 : -* prog.c:38:49: warning: ‘&&’ within ‘||’ [-Wlogical-op-parentheses] -* prog.c:38:27: warning: ‘&&’ within ‘||’ [-Wlogical-op-parentheses] -* prog.c:55:13: warning: ‘&&’ within ‘||’ [-Wlogical-op-parentheses] -* prog.c:56:14: warning: ‘&&’ within ‘||’ [-Wlogical-op-parentheses]
- -Due to most parentheses and braces removed when unecessary.
- -To verify the display, you can look at one of this programs : -* xephem : http://www.clearskyinstitute.com/xephem/ -* homeplanet : http://www.fourmilab.ch/homeplanet/ -* http://www.theplanetstoday.com/
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Yves-Marie Morgan
-yves-marie.morgan@parrot.com
make morgan2
-
-
-./morgan2
-
-
-For the console version (ncurses)
- -or
- -./morgan2 X
-
-
-For the graphical version (X11)
- -The judges enjoyed playing the game almost to completion; if we remember correctly, -we managed to place 59 or 60 dominos. We wonder, what would be faster: to play the game to completion -or to write an unobfuscated version of it?
- -This program is a domino game. The goal is to place dominos on the 8x8 grid. -Each domino is made of 6 squares of the color red or green. To place a domino, -at least one of it side shall match the other side of another domino.
- -At the start of the game, the first domino is placed randomly on the grid. You -get another domino to place by selecting one empty position in the stack on the -right. You can have to 8 dominos pending at any time.
- -Use Up and Down key to move the cursor in the stack. Press Enter to either
The currently selected domino is indicated on the top right.
- -Once a domino has been selected, the cursor moves to the grid. Use Up, Down,
-Left and Right keys to move in the grid. Press Enter on an empty position
-to place the domino.
To go back to selection mode, press Enter on an occupied position.
The domino can be place in an empty position if all its neighbour have matching -sides and the domino has at least one neighbour.
- -First, depending on the number of dominos pending in the stack, a bonus is -accorded : -* 1 domino in the stack : 8 points. -* 2 dominos in the stack : 4 points. -* 3 or 4 dominos in the stack : 2 points. -* 5 or more dominos in the stack : 0 point.
- -Then the bonus is multiplied by the number of matching neighbor the placed domino -has (1, 2, 3 or 4). This is added to the score.
- -Finally, the total score is divided by the number of dominos placed (1 - 64).
- -The 3 numbers on display represent : the total score, the fill count and the -final score (total score divided by fill count).
- -The game is finished when no more domino can be placed and you either : -* filled the complete grid. -* have 8 pending dominos in the stack. -* no more domino can be revealed in the stack (more than 56 dominos placed on - the grid).
- -Note There is no real end of game detection implemented in the program,
-simply press q when you have finished…
with gcc 4.7.2 on Linux Ubuntu 12.10 : -* prog.c:46:65: warning: value computed is not used [-Wunused-value]
- -with clang 3.1 on Linux Ubuntu 12.10 : -* prog.c:23:24: warning: adding ‘int’ to a string does not append to the string [-Wstring-plus-int]
- -!!!!! HAVE FUN !!!!!
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Arch D. Robison
-arch.d.robison@gmail.com
make robison
-
-
-./robison
-
-
-echo '1*2*3*4*5*6*7*8*9%1000' | ./robison
-echo '100000000000000000000*(20*(1+(99477941840441*50)))/31664812345028528' | ./robison
-
-
-Of integers this prog does a lot, -plus minus, div times (and what not).
- -And modulus if remainders the needing, -on standard input percent be feeding.
- -More than one line can thru give input, -when interactive one values more than thruput.
- -With cut and paste and some time, -one can compute M(23209).
- -I love the C language; its tersness is tops.
-But the thing I abhor is numerical ops!
No shifting, division, remainder, or times.
-No increment, decrement, or subscripting blech,
-No addition, subtraction, or bitwise bool glop.
-As for pointer arithmetic – totally yech!
But I do have a pref'rence, for pointer deref'rence.
-I find NOTS are a bang, and relations a ball.
-I like calling routines, and recursions in essence.
-But the thing I like MOST is a string dot h CALL!
With mem copy I copy, and mem set I clear.
-Take string len of this, and string copy that.
-From my keyboard I pause, to hear subroutines dear:
-The bark of string chrr, and the purr of string CAT!
One tiny detail that could lead to defeat.
-From where an arg points: string calls only go forth,
-So how to go back, to be Turing complete?
-From standard dot H, to the rescue, q SORT!
My fixation might hint at a textual bent.
-Does my program compose a tatoo for your shin?
-Play crosswords or translate from Urdu to Tzouby?
-To give it a whirl, just punch 2 + 2 in.
You can add, do division, and multiply too.
-Take unary minus and also subtract.
-Summing hairs of a walrus? No longer a fuss.
-Parenthetical grouping – no pushing a stack!
Try dividing a googol by one forty three,
-Subtract an octillion - it’s simply divine.
-To compute a remainder, inscribe a percent.
-For the sign of the answer, see C ninety nine!
A hundred and twenty five digits or so,
-Are the lengthiest figures the program can gnash.
-Go over that limit, by even a digit:
-Risk incorrect answers, or witness a crash!
Say, say, does it have octal or binary zen?
-What about duodecimal, ternary, hex?
-Try the base as an option (of course in base ten)
-Any base two to twenty – for that is the specs.
Use lowercase in trans-decimal radix,
-Divide babbage (in base seventeen) by cafe –
-a nice fad, but avoid a division by nix:
-No errant result, but you could wait all day!
To grok the internals, ask Queen Cleopatra,
-or King Tutankhamun; for him it’s a romp.
-Addition by cats, and if given two figures,
-to tell which is bigger, sort down and string CMP!
Unlawful subtraction, a grade school infraction,
-starts at the left and works to the right.
-Yet more innovation: like Henry Ford’s cars,
-With a pound and define, mass production of vars!
The moral is clear, for programmers out there:
-With the C lib for strings, you can hack with a flair.
![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Michael Birken
-o__1@hotmail.com
-http://www.meatfighter.com/
Alexander Prishchepov
-https://github.com/sans17/
make
-
-
-./prog < some_secret_or_something
-
-./prog http://host[:port]
-
-
-./prog.c
-
-./prog http://127.0.0.1:1701
-
-
-Port 1701? Well this is not the l2f registered TCP/1701 protocol. -Sniff the traffic to/from that port. You will see HTTP client -and server traffic. The HTML content you may see is static and -immutable. Nothing funny with the HTTP status codes. Even the -timestamp cookie, once set, remains static throughout the -session. The data appears to not be transmitted within the -binary content communicated between client and server.
- -So how does this program do it? A trek though the cloak of -obfuscation awaits the reader of the source!
- -When launched in web server mode, this application appears to deliver nothing more than a static HTML page. But, in actuality, it provides covert file transfer over the Internet. This is demonstrated by starting the application as a client-side downloader. The hidden transmitted data cannot be reconstructed or even detected from the binary content of the traffic between the client and the server.
- -./prog < secret_file_to_be_downloaded
-
-
-Try using the program’s source code as the secret file:
- -./prog < prog.c
-
-
-./prog http://host[:port]
-
-
-The optional port defaults to 1701. If the web server instance is started on the same box, try:
- -./prog http://127.0.0.1:1701
-
-
-It will incrementally display the contents of the hidden file at a rate of approximately 1 baud.
- -The client-side downloader will automatically terminate if the web server is bounced.
- -Plug the URL into a browser to view a static HTML page containing ASCII artwork.
- -Studying the network traffic will reveal that the HTML content is static and immutable, the HTTP request and response fields do not contain anything remarkable, HTTP status and error codes are not exploited, no unusual or deprecated features of HTTP are used, and while the cookie is based on a timestamp, its value also remains unchanged throughout the session. As mentioned in the abstract, the data is not transmitted within the binary content communicated between the client and the server. A full explanation of the protocol appears below, but feel free to explore before reading further.
- -The inspiration for this program comes from Star Trek VI: The Undiscovered Country, specifically the final confrontation between the Enterprise and the enhanced prototype Klingon Bird of Prey. The definitive feature of the prototype was its ability to fire while cloaked. But, perhaps even more impressive was its able to keep an open communication channel with the Enterprise throughout the battle, enabling the antagonist Chang to taunt Captain Kirk with Shakespearian quotes while he slowly pelted his ship with torpedoes. Normally, cloaked vessels must maintain silent running to avoid detection.
- -The battle is commemorated in the form of ASCII artwork depicting the ships faced head-to-head in the page delivered by the web server. Plus, the program source code is formatted in the shape of a Klingon Bird of Prey. The code itself includes a number of Star Trek references: the registry number of the Enterprise (NCC-1701) is defined as a constant; variable names spell out Cpt. James T. Kirk and Odo (the Deep Space 9 character was played by René Auberjonois who also appeared as Colonel West in Star Trek VI); the STARDATE constant makes timing configurable; and, the constant k stands for Khan (in the final engagement in Star Trek II: The Wrath of Khan, the damaged Enterprise managed to disable the USS Reliant’s shield generator by accessing its prefix code: 16309).
- -As obligated by a program that employs 23rd century cloaking technology, when the source is fed as input to IOCCC size tool version 2014-09-23-v19, and the -i command line option is used, the value printed is 0.
- -The client-side downloader relies on the response time of the web server rather than the binary content of the response. The server transmits 1 nibble at a time by counting to the nibble value via a sequence of rapid responses terminated by a long response. For instance, the value 5 would be transmitted by making a series of requests that result in 5 near instantaneous responses followed by a half-second delayed response. The long delay is skipped in the case of 15, the maximal nibble value. With the aid of an ASCII table, it is actually possible to read the nibbles by repeatedly pressing the refresh button within a browser and observing the page refresh delay.
- -Nibble Count Coding (file transfer protocol NCC-1701) is faster than transmitting each individual bit as a short or long delay because it sends each byte with 2 long delays whereas communicating individual bits requires 8 long delays in the worst case scenario. In fact, Nibble Count Coding is faster than applying Huffman Coding since that is designed to produce compact codes under the assumption that the bit value does not affect transmission time.
- -The server relies on the cookie to identify each client uniquely, enabling it to transfer the sequence independently to each client.
- -As with all network communication, accurate transmission of data relies on the nature of hardware revealed through statistics and timeouts set accordingly. The long delay is arbitrarily set to 0.5 seconds. This is microsecond tunable via the STARDATE constant defined at the top of the source code. Increase the value in the event of transmission errors. Decrease the value to download faster and less reliably.
- -The NCC constant is the web server port number.
- -For space considerations, the following include statements were dropped resulting in compiler warnings:
- -#include <asm/byteorder.h>
-#include <ctype.h>
-#include <netinet/in.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/select.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/unistd.h>
-
-
-It may be necessary to restore some of these under certain environments.
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Ferenc Deak
-fritzone@gmail.com
make deak
-
-
-./prog
-
-
-Changing bounding box coordinates in the source to explore
-various regions of the fractal.
-
-
-We consider this entry a tribute to all “Abuse of the C preprocessor” -and Mandelbrot fractal drawing entries we’ve seen over the years.
- -We liked the use of unary notation facilitated by variadic macros.
- -The application was written on a standard Ubuntu 14.04 and tested with -gcc 4.9.1 and clang 3.5 on 64 bit system (though this should not matter). -The application makes no assumption regarding any system specific settings, -and it only needs a console to run. The provided Makefile is just to have -an easy compilation. I don’t see any problems porting it to different -compiler/system as long as it supports the C99 standard.
- -The purpose of the application is mainly to illustrate the weird possibilities -of the C preprocessor, than to be a full featured console mode Mandelbrot -drawer. There are tools much better suited for drawing fractals.
- -The usage of recognizable elements from the C programming language in the -application source code is intentionally kept to a bare minimum. If this phrase -would not be true, the application would be the following:
- - double _[]={-2
- ,1,-1.3 ,1.3, 0, 0,0,0
- ,0 ,0,50, 80, 0,0,0 ,255
- , 8,0}; int main (
- int j) {if (j== 1 ){ if(
- _[12] >_[10] )_[17]=1 ;} if
- (_[13] >_[11 ] ||_[17]==1) return
- ;_[6] = _ [13] / _[11]*(_[1]-_[ 0])
- +_[ 0]; _ [7]=_[12]/_[10]*(_[3]-_[2] )+_
- [2];_[8]=_[9]=_[14]=0;l2:_[4]=_[8] * _ [8]
- ;_[ 5]= _ [9]*_[9];_[9]=2*_[8]*_[9]+ _[7
- ];_[8 ] = _ [ 4 ]-_[5]+_[6];_[14 ]++
- ;if((_ [14]< _ [15])&&(_[4]+ _[ 5]
- <_[16 ])) goto l2; putchar(
- " #@*+ "[( int) _[14]%
- 5 ]);_ [13 ] ++ ; main (
- 0) ;_[12]++; _[13] =0
- ;if(_ [17] !=1) putchar
- (0xa); main(1);}
-
-
-The application expects no parameters, the only way you can change the behaviour
-is to modify the source code at the indicated location: the line
-/* <-- Configure here: X1, X2, Y1, Y2 */ is intentionally not obfuscated so
-that the adventurous programmer can manually modify the coordinates of the
-fractal to be drawn on the screen.
Yes, unfortunately there are compiler warnings of the kind “initialization makes -integer from pointer without a cast” the provided Makefile automatically -disables them.
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Yusuke Endoh
-mame@ruby-lang.org
-https://github.com/mame/
make
-
-
-./prog > foo.c
-
-
-./prog > main.c
-
-make main
-./main Hello
-
-
-Big terminals with tiny fonts have their uses in certain cases. -One of them is:
- -./prog < prog.c > treacle.c
-make treacle
-# or instead of make: cc -Wno-empty-body -funsigned-char treacle.c -o treacle
-./treacle
-
-
-When using a smart phone to read the output, you may need to -step back to see the bigger picture because that picture is worth -more than 1000 words.
- -You may want to use a large display with a very small-font terminal.
- -Decompress src.zip if you need explanation.
![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Yusuke Endoh
-mame@ruby-lang.org
-https://github.com/mame/
make
-
-
-./prog < input > output
-
-
-echo Hello | ./prog
-
-echo Hello | ./prog > hello.c
-make hello
-./hello
-
-
-If you look closely at the source, you will see code that appears -to puts C code that includes itself. How and why? Perhaps it is -in the DNA code of the code? Perhaps there are 23 reasons? :-)
- -This chromosome program synthesizes a double helix. -The helix can also be compiled as a C program.
- -Enjoy DNA programming!
- -This program was inspired by Acme::DoubleHelix: -http://search.cpan.org/~xern/Acme-DoubleHelix-0.01/
The synthesized helix just includes the original program at the head.
-Do you see how prog.c determines whether it was invoked as a standalone program or included as a header file?
-Note that it does not use any gcc extension such as __INCLUDE_LEVEL__.
The synthesized helix of course follows the base-pairing rules for DNA: -A is bonding only to T, and C is bonding only to G.
![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Sandro Maffiodo
-smaffer@gmail.com
-http://www.assezeta.com/sandromaffiodo
make
-
-
-cat mario.level | ./prog 320 200 800 300 128 144 mario.rgba mario8.wav 10343679
-
-
-cat giana.level | ./prog 320 200 1000 300 192 168 giana.rgba giana8.wav 5459393
-
-cat mario.level | ./prog 320 200 800 300 128 144 mario.rgba mario8.wav 10343679 && telnet towel.blinkenlights.nl
-
-
-A classic for a particular generation. Like all good programs, being data -driven means you can do fun things in small spaces.
- -Use tabsize=4 to see the magic
- -./expand -t 4 < prog.c
-
-
-The program returns 0 if the user win or not-zero if loose so you can test it and make something useful (or not), like that:
- -cat mario.level | ./prog 320 200 800 300 128 144 mario.rgba mario8.wav 10343679 && telnet towel.blinkenlights.nl
-
-
-This is an engine for Platform Games. It can be used to create games like the legendary Super Mario Bros. -With this simple and clear sourcecode you can create all the games you want, for free!
- -In my two tests i tried to create one level of Super Mario Bros and one of The Great Giana The Sisters. -Both games are classic platform games and both share the same fundamental rules:
- -The color of the sky is wrong on MacOS. You need to flip some bytes from the last parameter of the program:
- -MARIO LAST PARAMETER: 4292124159
-
-GIANA LAST PARAMETER: 3243070463
-
-
-The code requires libSDL1.X.
- -The build process will generate some warnings (60~ on clang) about:
- -The program read a single image that contains all the game sprites. The image must be a grid of 8xN sprites. The size of a single sprite must be square. The program calculates the size in this way:
- -sprite_size = image_width / 8
-
-
-Each sprite is identified by its position inside the grid, counting line by line, from left to right (for example sprite 0 is the top left sprite in the grid, sprite 8 is the first sprite of the second row of the grid).
- -Some positions of the grid have a predefined purpose:
- -| Position | -Description | -
|---|---|
| 0 | -Player stand right | -
| 1 | -Player walk right frame 0 | -
| 2 | -Player walk right frame 1 | -
| 3 | -Player jump right | -
| 4 | -Player stand left | -
| 5 | -Player walk left frame 0 | -
| 6 | -Player walk left frame 1 | -
| 7 | -Player jump left | -
| 8 (second row) | -Super player stand right | -
| 9 | -Super player walk right frame 0 | -
| 10 | -Super player walk right frame 1 | -
| 11 | -Super player jump right | -
| 12 | -Super player stand left | -
| 13 | -Super player walk left frame 0 | -
| 14 | -Super player walk left frame 1 | -
| 15 | -Super player jump left | -
| 24 | -Player dead | -
| 32 | -Player win | -
| 40 | -Super player win | -
All the others sprites can be used as you want, depending on the game you want to create.
- -The program reads the level description from stdin.
- -The level description is a sequence of rows where each row describe an object. You can input as many objects as you want but the maximum number of objects handled by the program is 333. You can modify this value by editing the source here:
- -C[333*7],d=333;
-
-
-Each row have six columns:
- -CLASSFLAGS must be a combination (bitwise or) of some of these constants:
- -| NAME | -CONSTANT | -CLASS | -
|---|---|---|
| ENEMY | -1 | -An enemy. CLASSPARAM0 can be 0 if the enemy don’t move, 1 if the initial move direction is right, -1 if direction is left. All enemies that walk will change its direction after 20 pixels. The sprite of an enemy must have 2 others adjacent sprites: SPRITE-1, used when the enemy die, and SPRITE+1, used when it walks | -
| BLOCK | -2 | -A wall. Player can walk over the object but can not pass through it | -
| GIFT BLOCK | -4 | -When the player hits the object from below, a new object is created. CLASSFLAGS of the new object is defined in CLASSPARAM0. The sprite used for the new object is defined in CLASSPARAM1. The sprite of the gift object must have an adjacent sprite: SPRITE+1, used when the block is hit | -
| POWERUP | -8 | - This is the classic Mario’s mushroom. When the player hit the powerup object, the player become Super player. If CLASSFLAGS has the bit ZOOM, the player height will be doubled. The Super player can hit the enemies without die, but when this happens, the Super player goes back to being normal |
-
| END | -16 | -When the player hits this object the level ends. Player win | -
| ZOOM | -32 | -This flag can be used with POWERUP to indicate a powerup that will doubles the size of the player (like Mario’s mushroom) | -
| DESTROY | -64 | -When the player hits the object the object disappear. This is the classic Mario’s coin, but the engine does not counts the points, so, from the user point of view, this object is useless | -
| DESTROYUP | -128 | -This object is like a BLOCK but when the player hits the object from below, the object disappear | -
If CLASSFLAGS is zero the object has only an aesthetic function.
- -The last row of the level descriptor must have all its columns set equal to -1.
- -Some classical features are missing: throw objects, shoot, multiple lives, points counter. You can add those features if you want!
- -The program allow to run one level only. It’s easy to add a menu and multiple levels but the size of the engine will grow too much.
- -When the Super player become bigger (ZOOM flag), the player can collide with blocks and get stuck inside them. This is a KNOWN BUG. When your player become bigger, stay away from blocks!
- -There is one audio track only (game effects are missing).
- -Some of the sprites used in the examples are identical to those of the original games, others were designed by me.
- -The music used in the examples have been resampled, starting from the original versions for the Commodore Amiga and Nintendo NES.
- -Super Mario Bros is a game created by Nintendo Entertainment, my use of the sprites does not intend to infringe the intellectual property of Nintendo but only demonstrate the operation of the program. From my point of view this is a tribute to the legendary game Super Mario Bros!
- -The Great Giana The Sisters is the game created by Time Warp Productions and also for this game worth my previous notes. Long live The Great Giana The Sisters !! :)
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Sandro Maffiodo
-smaffer@gmail.com
-http://www.assezeta.com/sandromaffiodo
make
-
-
-./prog arg
-
-
-cat image.rgb | ./prog ' .,:;!$#@'
-
-
-On the face of it :-) given what this program one might wonder what makes this winner special. -But when you realize the source is small enough to tweet on twitter you understand.
- -Who will be the first to tweet this source? How many re-tweets will such tweet get? -And how many people will really understand the tweet?
- -This program convert an image to an ASCII ART. The program reads a raw RGB image from stdin and print the ASCII ART to stdout.
- -The build process will raise some warnings about:
- -The program crash if run without parameters.
- -If you have a terminal geometry than if different from the common 80x25 you can modify the output width by changing the value of the first variable:
- -d=80
-
-
-Type this:
- -cat image.rgb | ./prog " .:;Y0"
-
-
-You can use your own image. Convert the image to a raw RGB image, using imagemagick it’s very simple:
- -convert -geometry 80x source.jpg image.rgb
-
-
-This program require one parameter, or crash. The parameter of the program is the convertion ramp. You can use different ramps or create your own (for ex. using some letters of your name). -These are some ramps you can try:
- -./prog " :1"
-./prog " .:;Y0"
-./prog " .:-=+*#%@"
-./prog " .,:!-iots&8%#@$"
-./prog "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,"^`'. "
-
-
-An alternative version of this program is only 121bytes long:
- -d=80,e,j;g(){j+=getchar();}main(){for(;;){j=0;g();if(j<0)break;g(g());putchar(" .:#@"[j/3*5>>8]);if(!(++e%d))puts("");}}
-
-
-This alternative version have a fixed ramp. It’s smaller but it’s not so fun to use…
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Yves-Marie Morgan
-yves-marie.morgan@parrot.com
make
-
-
-./prog [arg ..]
-
-
-make
-cp -f prog morgan
-./morgan clobber
-ls
-
-./morgan all install
-ls
-
-./prog love haste waste supernova
-ls
-
-make
-./prog magic
-ls
-
-
-Think of this as a Maker Faire’s make. :-)
- -It works reasomably well. While not super ultra-featured, it does fair well with the Makefile we supplied. -Not only that, it helped uncover a bug we had in our special Makefile rules.
- -This program is a tiny make clone.
It is able to parse a subset of the make syntax and will execute rules for
-goals given in arguments if they need to (based on timestamp of dependencies
-of rule targets).
name=value.It should be able to build programs of previous years with the provided Makefile
-found in previous contest archives. Simply use this program instead of make.
-It will recursively use itself for submake (the MAKE= assignment inside
-Makefile will be ignored to continue using itself).
Makefile.$< and $@ are supported for automatic variables in commands.-j option).:= += ?= syntax for variable assignment.with gcc 4.8.2 on Linux Ubuntu 14.04 64-bit : -* prog.c:22:15: warning: return makes integer from pointer without a cast [enabled by default] -* prog.c:23:72: warning: signed and unsigned type in conditional expression [-Wsign-compare] -* prog.c:12:11: warning: suggest parentheses around ‘&&’ within ‘||’ [-Wparentheses]
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Don Yang
-omoikane@uguu.org
-http://uguu.org/
make sinon
-
-
-cp sinon.c run.c
-
-
-Then keep running ./glock.sh or ./hecate.sh within a minute with -slight pauses between invocations.
- -cp sinon.c run.c; ./hecate.sh; ./glock.sh; sleep 3; ./glock.sh; sleep 1; ./hecate.sh
-
-
-Try to figure out how this entry determines the optimization level with -which it had been compiled. Is this an example of undefined behavior -or unspecified behavior?
- -Sinon is a game of timing, the goal is to eliminate all enemies in -under one minute.
- -To start, compile and run the program. To resume, compile and run the -output repeatedly until you have won/lost the game. For example:
- -cp sinon.c run.c
-gcc -O0 run.c -o run && ./run | tee run.c
-gcc -O2 run.c -o run && ./run | tee run.c
-...
-
-
-Sinon is played by compiling and running the output repeatedly. Two -factors determine what actions are taken:
- -If you fire too quickly, the weapon will jam. If you fire too slowly, -you will not be able to eliminate all the enemies in time. Thus the -primary objective of the game is to time your compilations just right.
- -Sinon has two weapons that are selected based on compiler optimization -level:
- -“gcc -O2” or “clang -O2” will fire Hecate II, a powerful rifle that -requires longer time to cool off.
“gcc -O0” or “clang -O0” will fire Glock 18C, a less powerful pistol -that requires less time to cool off.
Because the weapons cool off independently, the best strategy is to -alternate between the two weapons. It is fairly easy to win the game -with this strategy even with occasional jams.
- -If your compiler does not have the right optimizations, only Glock 18C -would be available. It is still possible to win, but your timing will -need to be more precise. This is effectively playing the game on -“hard” mode. It is worth trying this mode even if you have the right -compilers.
- -Sinon has been tested and verified to work on these platforms:
- -Sinon is intended to be played in a 80x25 terminal.
- -Sinon might be the first game that uses compiler optimization level as -a primary input.
- -Sinon has a demo mode that plays the game automatically. Make sure -that there are no files named “run” and “run.c” in current directory -(they will be overwritten) and run:
- -perl sinon.c | bash
-
-
-File size and CRC32 of sinon.c are embedded in line 7.
- -Process for making Sinon is included in spoiler.html.
- -Layout of this code is based on Asada Shino, also known as “Sinon”, -from Sword Art Online.
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Cel Skeggs
-ioccc@celskeggs.com
-http://www.celskeggs.com
make
-
-
-./prog
-
-
-./prog
-
-
-HINT: Try pressing the left and right arrow keys as needed. -Also try pressing space/enter to select options. -Pressing Q or Escape may end the fun before you are ready. :-)
- -When the code looks like lemons, it is probably because the LEMONPEOPLE, -or at least the LEMONLORD was involved. :-)
- -Look at some of the C pre-processor macros in the source code. -Ask yourself why C source is being passed as arguments to some -of those macros.
- -Now you may observe, while it is running, that some C source code -is being written to a file and then compiled. And yet that compiled -code is somehow executed from main. But how? How is main able to -call code that was written and compiled just in time for execution?
- -It was ten yours ago when THE LEMONPEOPLE invaded, juicing all in their path.
- -Attempting to free the Earth from their tyranny, you have endured pulpy and -sour battles.
- -This has now culminated in you reaching the throne room of THE LEMONLORD.
- -Armed with your right-facing curly brace, you charge into battle.
- -(Use left and right arrow keys and space/enter to select options. Press Q or -Escape to quit.)
- -Unfortunately, it became very difficult to get this entry to fit within the -size requirements. It’s currently at 2052 according to iocccsize, and 3994 -according to wc -c.
- -The current size is a third to a half of the original size before compression.
- -Due to this, it does LOTS of things that subtly annoy compilers!
- -(10) data argument not used by format string
- -This occurs because some of the fprintf invocations don’t use all their -parameters. The program should still work fine!
(1) using the result of an assignment as a condition without parentheses
- -Somewhere, I needed to set a variable and then branch on the result. The -shortest way was to combine them. Some self-proclaimed “EXPERTS” think this -is a bad programming practice, but what do they know? :P
(1) implicit declaration of function ‘time’ is invalid in C99
- -An #include statement is expensive, and I’m broke.
(1) control may reach end of non-void function
- -Turns out that sometimes, a return statement is too much. This will never -actually occur, but some C compilers think they know more about my program -than I do! :P
(?) Under some systems, -fPIC is irrelevant for shared libraries. If so,
-you should remove it from the Makefile.
Take a close look at how it works. Notice that it’s passing C code to certain -macros…
- -Guess what? It’s a very simple kind of JIT compiler, though not used as deeply -as would be cool.
- -Essentially, it generates C code at runtime, dumps it to a file, and then runs -a C compiler on that file, telling the C compiler to generate a shared library. -Then it loads the shared library with dlopen, and…
- -Ignores the result?
- -That can’t be right.
- -Well, it is. Instead of using dlsym like a normal programmer, I mark one of the
-generated functions with __attribute__((constructor)). This means that it
-gets called immediately on load, so it can make its functions available.
But wait - how can it link into the main program, either? It has no way to -reference anything in the main executable!
- -But it does: I’m injecting certain addresses into the generated code, which it -then casts to pointers and accesses! It uses this to make certain functions -available to the main program, so the main program’s generated code will then -enter itself where it’s needed.
- -There are also lots of #defines.
No, these are not obfuscation. These are compression.
- -There is a little bit of obfuscation gained from using the stringification -operator. (I can never remember what it’s actually called, but it’s the # -operator in a preprocessor macro) - this allows me to pass C code in arguments -to the macros, meaning that it gets interpreted as C code instead of a string -by the iocccsize tool, so it gets counted as smaller! :D
- -As part of the JIT compiling, the program hides the fact that it needs ncurses: -it just links ncurses with one of the generated shared libraries, and then can -access the contents of the ncurses library!
- -Also, note where functions start and end…
- -I’ve messed with the syntax so that it’s not actually formatted properly. It -almost looks like it is, but it isn’t.
- -This isn’t significant obfuscation as long as you run it through a C source -code beautifier.
- -But wait… if you aren’t careful, running it through a C source code -beautifier won’t work. Remember how I’m interlacing generated C code with -actual C code? Note that this WRECKS some beautifiers. I hope you have a good -one!
- -(There’s an obvious way around this but I’m not going to spell it out for you. -That’d be too easy!)
- -Do note that there are some other miscellaneous obfuscations, but they should -be easy to understand once you figure out the ones above.
- -This program is a very easy program to cause to fail!
- -Some things to check
- -%cinclude "prog.c", is prog.c the name of the
-original source code file?Does your system have ncurses.h (like a nice system) or
-ncurses/ncurses.h (like a rude system) ?
If it’s the latter (or some other path), you’ll need to update line 97.
- -(I had to do this under Cygwin.)
-fPIC (or other arcane invocations) to compile a
-shared library? If so, make sure that you include it in the -DCC argument in
-the build script.-fPIC? (Like Cygwin.) You might
-need to remove it from the build script.__attribute__((constructor))? It needs to.err. Maybe it will help you figure out why a runtime-
-generated program failed. The failing program should be found in t.c.I’ve tested it on the following platforms, in case you need to try it on one:
- -I ran out of time to test it on more systems.
- -Who am I?
- -Yes.
Why doesn’t your program require a pet fish license?
- -THE LEMONLORD’s pet LEMONFISH was not rendered in the game, and so does not -require a pet fish license.
Was this inspired by anything?
- -Yes, this was inspired by a minigame from an open-source codebase of Space -Station 13. I didn’t, however, look at the minigame at all during the -development of this entry.
What’s the length of this REMARKS file according to the iocccsize tool?
- -$ ./iocccsize -i <REMARKS.MD
5092
![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Daniel Vik
-daniel@vik.cc
-http://danielvik.com/
make
-
-
-./prog > foo.c
-
-
-echo 'Want to hear me beep?' | ./prog > audio_file.raw
-
-echo 'No. I want chocolate!' | ./prog | mplayer -demuxer rawaudio -
-
-
-This program sets a new tone for obfuscation. But do you understand -what it says about obfuscation? Perhaps:
- -./prog < prog.c > prog.raw
-
-
-might speak to your coding style? If not, then perhaps:
- -./prog < remarks.markdown | mplayer -demuxer rawaudio -
-
-
-might help? :-)
- -This program converts ascii text to morse audio file and vice versa. As far as -I can tell, there are at least six chocolate references in this program.
- -This program can convert text to morse to a raw 44.1kHz stereo audio file. -Via streaming to mplayer, you can listen to the morse audio.
- -Don’t forget the last ‘-’ as it makes mplayer read from stdin.)
- -$ ./prog e < audio_file.raw
-
-
-or alternatively pass a .wav file as input.
- -The preferred input format 44.1kHz stereo, but it does a decent job on mono -input and different frequencies as well.
- -The program is portable to most platforms. The only system dependency is that -the program relies on writing binary data to stdout.
- -Microsoft compilers adds a carriage return to newlines, and to compile the -program with this platform, the following line can be added after the main -declaration in order for the program to run correctly:
- -_setmode(_fileno(stdout), 0x8000);
-
-
-The program uses a quite simple algorithm for detecting tone on and off events -in the morse signal. Hence the program does not work well with noisy input -signals. I have tested it with several samples of man made morse recordings as -well as computer generated ones.
- -Generally, any recording from ham radio transmissions does not decode due to -noise and echoes. Other man made recordings may decode, but some characters -can be incorrect due to too big variation in length of tones and pauses. -However I found some man made recordings on that decode reasonable well.
- -If a recording don’t decode, you could try to pre-process the input with a -narrow bandpass filter on the frequency of the transmission.
- -![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Freek Wiedijk
-freek@cs.ru.nl
make wiedijk
-
-
-./prog
-
-
-gcc -E prog.c | indent | sed '1,/5.*prog/d'
-
-
-C11 features definitely help this entry to be as concise as it is.
- -The judges would like to think that they had almost understood how this entry works.
- -If you win a bet by demonstrating this entry, please let us know.
- -w word datatypew(*)(w,w*) works just as well-std=c99 -Wall -Wextra -pedanticYthe readable implementation of Y is on lines 29-30:
W_f = \x.f(xx) - Y = \f.W_f W_f
a mixture of strict and lazy evaluation, with a _ force function
-(John Tromp notes that if Turing’s fixed-point combinator
-(\xy.y\z.xxyz)(\xy.y\z.xxyz) had been used,
-all applications could have been strict)
Y to implement factorial on native ints![]() |
-© Copyright 1984-2015,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Dave Burton ioccc@snox.net
-http://snox.net/ioccc
make
-
-./prog "expression"
-
-
-or
- -./prog
-(input expressions)
-
-
-./prog '?0x3343<<2'
-
-echo '?0x3343<<2' | ./prog
-
-./prog
-
-Enter:
-
-a=0xfeedface
-b=0xcafe
-a << 16 + b
-
-grep '[0-9]' prog.c
-
-./prog < test.in
-
-less calc.man
-
-
-“Look, Ma, no hands digits!”
The place where some arithmetic operations are done, for example, -division or modulo, are easy to find. Where are addition and subtraction?
- -We were impressed with the level of detail the author “blogged” the obfuscation process.
- -All useful tools should include sufficient documentation. -See the included man page. ;-)
- -This program is named calc. Onomatopoeia of sorts, in the visual realm. -The formatting was easier: Form Follows Function (although the 2011 Hou entry -did this better). -It was tempting to call it iCalc, with i for integer (and it was written on an iDevice), -but sanity prevailed.
- -Printed in 8 pt Courier, it makes aesthetically pleasing 8.5 x 11 wall art.
- -Dominik Muth observed a syntax error on 1+1, 1-1, 1|1, and 1^1 when using an
-ARM based computer, although 1*1 and others worked correctly.
-This occurs because some platforms by default treat char as unsigned char.
-The original code has this weakness, which can be corrected by adding -fsigned-char
-to the compile line.
-The modified code is agnostic to char signed-ness.
Yes, this is another calculator program.
- -However, unlike any other calculator source code the author is aware of, -this one contains no digits. At all. Anywhere. As in
- -grep '[0-9]' prog.c || echo no digits!
-
-
-Nor are the digits simply obfuscated. There are no character constants. -There is only one single, short string, and it does not contain any obfuscated digits. -And yet the output is in decimal and hexadecimal, and it accepts octal, decimal, and hex input.
- -Flow control is by for and return. It is If-less. Switch-less. While-less. Hope-less.
-Literally, if not figuratively. ;-)
The code size is intentionally 2015, as stated by iocccsize -i, -and can be reformatted without changes (as in rule2.c) to exactly 4096 octets.
- -Finally, calc is interesting, if for no other reason than it is practically useful: -Hex/decimal conversion, arithmetic, byte-swapping, bit-shifting, and logical operations with memory, -on the command line, or interactively.
- -The code follows many industry best-practices:
- -You know what it does just by looking at it.
Numbers and digits have often been used for obfuscation, -so in a bid for better clarity, this code has no digits at all.
In the spirit of clarity, most of the variables are declared before use, so they -are readily visible, with single letter names that don’t clutter the screen, -in a tautological arrangement.
More helpful is the use of typedefs instead of #define, so the types remain useful
-even in the debugger, and source code beautifiers will not undo careful presentation.
#defines are used here in the best spirit of the preprocessor: to shorten
-repetitive constructs, not for obscurity.
All functions are short (and therefore easy to understand?) and do only one thing, well, ….
Curly braces invite endless holy wars over readability. This code only uses them -for function definitions, thereby greatly improving readability, and reducing arguments -about said readability.
One of C’s many blessings (until recently) is a modicum of keywords,
-of which only 8 are used:
-for, return, typedef, void, char, short, unsigned and long;
-10 if #include and #define are counted.
The code helpfully declares “syntax_error!” right up front, filling the reader with confidence.
In spite of its inherent clarity, the code was presented to both indent(1) and -clang-format(1), after running it through the preprocessor, sustaining its better qualities.
That the code is obfuscated is spelled out two different ways in the source; it helps -to reformat the code to see the second spelling.
The author is overly fond of the code that handles input. -There is no memory allocation, nor pre-allocation of arrays, so where does the -memory come from? The multi-base strtol() code is pretty trick. -No special attempt was made to replace operations with obscure mathematical relations, -as the (lack of) beauty is in the parsing – ask not where is the modulus operation, -but how does it know when to mod – okay, but where is add and subtract? -And really, who doesn’t enjoy a setjmp() in the argument list?
Finally, documentation of the source code structure is helpfully provided in rot13 format. -But isn’t it unsportsmanlike to rely upon it? However, even with this helpful guide, -things like reading input lines remain as tricky to read as they are to write.
Calc is C99 compliant, and is ANSI/C90 compliant except for wanting 64-bit long long.
-Changing the two long long typedefs to long, and compiling with gcc -m32
-yields a program that operates on 32-bit values, with wrap-around of shifts mod 32:
1<<48
-65536 0x00010000
-
-
-gcc 4.2.1 without arguments compiles cleanly (e.g. cc prog.c -o prog). -This is my workaday compiler. gcc is also clean with -ansi, and -std=c99.
- -clang 3.6.0 lives up to its namesake, resounding on non-problems. -To stifle these complaints: - -Wno-return-type -Wno-parentheses -Wno-empty-body
- -When invoked with -ansi -pedantic, there are two warnings, which can be ignored:
- -ISO C90 does not support 'long long'With -Wall -std=c99, both are quite noisy, and all can be ignored:
- -array subscript has type 'char' [-Wchar-subscripts]value computed is not used [-Wunused-value]operation on 'j' may be undefined [-Wsequence-point]If the program name begins with an “e”, it echoes stdin to stdout. -This allows for a convenient test suite:
- -ln -s prog eprog
-PATH=. eprog < test.in | diff - test.out
-
-
-If you do not want to puzzle out how it works, see spoilers.markdown.
- -![]() |
-© Copyright 1984-2016,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Gil Dogon
-http://sokoban-gild.com
make
-
-./prog
-
-
-./prog
-
-press and hold the Left Arrow key until you turn 90-degrees to the left
-
-when you see a long tunnel, press the function key F2
-
-Use the Up, Down, Left and Right keys to change your path
-
-Press function higher numbered function keys (F3, F4, ...) to go faster
-
-Press F1 to stop
-
-Turn 90-degrees to one side
-
-Press F4 to and drill into some blocks for a bit
-
-Press F1 to stop
-
-Turn 180-degrees to face the way you came
-
-Press F2 and navigate back down the new hole until you reach the long tunnel again
-
-Press F1 to stop
-
-etc.
-
-Press the ESC key
-
-
-You are in a twisty maze blocks, almost all alike.
- -Those blocks are generated by twisty maze of code blocks, almost all different.
- -Can you find your way around either and understand where you are?
- -How many function keys does your keyboard have? Can you generate very high number function keys such as F30 or F31? :-)
- -Textures? We don’t need no stinking textures.
- -Just run prog with no arguments on an X11-compatible system. The scenery, though pseudo-randomly generated should be strangely familiar, specially to those still in their teen age. You can navigate using the keyboard arrow keys and the function keys. Your speed is a linear function of (n-1) where Fn is the last function key you have pressed, and you always move in the direction you are looking at. Be aware that you are probably some kind of a Creeper as is obvious from looking at the program, hence your movement is destructive to the environment. So after pressing F12 for warp speed, and moving around randomly, you might find yourself in a 3D maze of twisty little passages, from which there is only one Esc(ape) key. Note that in theory if you have a specialty keyboard with 32 function keys you may even press F31 to reach infinite improbability drive speed, though the author had never tested this feature. However a hidden comment in keysymdef.h suggests the existence of a mythical Sun Keyboard with 35 function keys :)
- -This entry, tough pretty thoroughly obfuscated, is not entirely original, nor am I Notch. The inspiration for this entry is a demo code written by the Notch himself, which was released with the following license: “you may use the code in here for any purpose in any way you want, at your own risk”. That version will henceforth be referred to as the original. Though the original in itself was quite nice and rather dense piece of code, it was not written in C, nor entirely and meticulously obfuscated, a state of things I hopefully rectified.
- -Basing it on the original which already had a wonderful simple and concise ray casting through a generated voxel world rendering, I added a few tweaks of my own device:
- -This entry is rather portable I think on modern platforms. It assumes of course basic X-windows availability. There are several other salient assumptions though:
- -The entry, does a thing which is an absolute No-No for X-windows program, i.e. assuming it knows some numeric values for keysyms defined in keysymdef.h . I have searched far and wide the lord Google’s domain, yet was unable to find a version of the file where those assumptions were broken. This enables the important support of up to 32 function keys keyboards without spilling over the size limit, and allows us to use such fun expression for arrow view control as the following:
- - *(a&1?&C:&B)-=(.05 -a/2%2*.1)*!(a-1&4092^3920)
-The entry, on purpose, (see the section about SIMD below) does not use enough bits of precision, so some times the ray will miss the intersection of two voxel faces and push on through. That’s why you may notice some noise along close up voxel edges. Fixing this issue would have taken the entry over the size limit regrettably.
- -Well, of course you have all the usual suspects, used for extreme compression, and such a nice layout: not very informative identifiers, which are being reused all over the place, some rather gruesome looking expressions, a whole load of magic constants with apparently no rhyme nor reason (including a Lagrange polynomial), and a message from our friendly Cetaceans. However it also includes some clever and not so obvious though instructive techniques, to subtly make the code more magical and efficient, at the same time.
- -Those techniques are about the use of 64 bit integers in order to do SIMD work, in a portable way without ever using any SSE/AVX or other non-portable compiler inline functions! The irony though, is that when compiling the program on modern X86 architectures indeed SSE/AVX is used for the long longs. -Following is some “Spoiler” information, So if you want to play tough, stop reading at this point.
- -So how is this done? Quite simply by using the whole long long arithmetic’s capability. I think the C99 standard assures us that long long has at least 64 bits. Most of those bits are unused in normal programs, however here we use them more wisely. For example, in the inner loop of the program you have the innocent looking expression i+=d. What it does in fact, is a SIMD addition of two vectors, each with three signed fixed point coordinates, advancing our ray in 3D space! -To spell it out, the macro producing such vectors is P, and the assignment q=0x820008202625a0 sets our creeper original position to about (32.5, 32.5019, 2441.406) .
- -Evidently when doing such arithmetics, care must me taken to avoid overflow from one component to the other, but since our voxel world is a torus of size 64 in each dimension this hardly matters. A subtle issue, is how to deal with signed quantities. In the i+=d expression above i has 3 positive components, but d has arbitrary signed components, as our ray may face in any direction. It seems things should not work, specially as we defined both i and d as unsigned! However notice that the T (and P )macro converts float to signed long longs. Once sign is extended from a least component into higher bits, it seems at first to be recipe for disaster, however everything works beautifully, and you get precise component results when the final accumulation components in i are positive. This only gets broken a bit when the final accumulation has a least significant negative component. To see this bug in action change the assignment above to q=0x82000820000000, and look towards the negative direction of the main tunnel.
- -Similar technique is used on the RGB components so their brightness can be adjusted simultaneously by the expression: o=o*b>>8 . Of course some spare bits are needed between the components, so they are spread in the long long and reordered as RBG.
- -![]() |
-© Copyright 1984-2016,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Etienne Duble etienne.duble@imag.fr
-http://lig-membres.imag.fr/duble
make
-
-echo Some text | ./prog
-
-
-echo Hello, world | ./prog
-
-DRAFT=1 ./prog < prog.c
-
-./prog
-> [type]
-(...observe...)
-
-./prog < prog.c
-
-
-Beautiful penmanship! However, your fonts may vary.
- -How does this entry compress the font it uses? What’s the purpose of lrand48()? -Why does the program dump core, when it does :) ?
- -This program prints text in your terminal with an interesting -hand-writing effect.
- -It uses the braille patterns range of the unicode standard: this -allows to consider each terminal character as a tiny 2x4 bitmap.
- -Turning the Braille code into something visual might be considered -blasphemous. When I was fighting to make this program work, I started -wondering if it was not the reason for its very erratic behaviour.
- -The file prog.orig.c is the one I submitted.
Gil Dogon noted a few unsafe statements (statements whose behaviour is
-undefined in the C standard and, as such, could cause issues with other
-compilers or optimization levels). These have been fixed in prog.c.
-After this fix, in order to remain rule-2-compliant, a variable name has
-also been shortened in this file.
If you have clang:
$ CC=clang make -e
-
-
-Otherwise (gcc):
- -$ make
-
-
-(You will get a few warnings in this case.)
- -You need a terminal configured to handle an UTF-8 encoding and a -font including braille patterns. -This is the default on most modern GNU/Linux operating systems. -The default terminal application (gnome-terminal) or even a simple -xterm should render things properly. -I tested this on several Debian and Ubuntu systems, 32 and 64bits (no configuration was needed). -I also tested it on FreeBSD 9.3 32bits (font and encoding configuration -was needed in this case).
- -Basic mode:
- -$ echo 'I am testing this thing.' | ./prog
-[... rendering ...]
-
-$ ./prog < lorem-ipsum.txt
-[... rendering ...]
-
-
-Interactive mode:
- -$ ./prog
-> hello world!!!
-[... rendering ...]
->
-
-
-This entry is obfuscated in various ways:
- -On the other hand, the following may help:
- -In order to comply with the size rule, I encoded only a part of the visible ASCII -chars:
- -a-z, A-Z, '.' ':' ',' ';' '!' and '?'.
-
-
-Uppercase and lowercase chars are rendered the same. -The program also understand the space and the linefeed (\n). -Other chars are simply ignored (most of the time ;)
- -This limitation is due to the heavy use of recursivity. After having processed -a large number of characters, the process may exceed the stack size and crash. -(However I did not experience this myself. The top-level recursion might be -removed by the compiler as part of its optimizations.)
- -The program does its best to avoid cutting words at the end of lines, but -it could still happen in case of long words.
- -Given the limited set of characters handled, the program is mostly limited -to simple text documents. -Thus, if you try for example:
- -$ ./prog < prog.c
-
-
-You will not get something that looks like C code. (but you can still try, -if you are curious. :)
- -Defining an environment variable called DRAFT will enable the ‘draft-mode’. -Try for example:
- -$ echo 'testing the draft mode' | DRAFT=1 ./prog
-
-
-The program will run much faster but the rendering will be less precise.
- -I saved the best for last: usually, programs that handle an “interactive -mode” have to check whether their standard input is a terminal or not (by -using isatty()). Did you notice that this program does not perform any such -detection, but still behaves (or seems to behave) appropriately?
- -![]() |
-© Copyright 1984-2016,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Someone Anonymous
-Twitter: @hirekoke
Yusuke Endoh
-https://github.com/mame/
-Twitter: @mametter
make
-
-<tbd-tool-rubl-perl-python?>
-
-
-Connect to port http://localhost:10333 with your browser
-
-
-How did the leopard get its spots? Why are a zebra’s stripes unique?
- -In case you didn’t recognise the portrait of Alan Turing, there are some -pointers to his features like eyes with “stdeye-o” and “<–mouth”. Can you -find any other tributes?
- -What does “Alan Turing” remind you of? Cryptanalysis of the Enigma? Turing machine? Turing test? This program is also based on his work.
- -Compile the program as follows:
- -$ clang -O3 -std=c99 \
- -Wall -Wextra -pedantic -o prog prog.c \
- -Delta_u="Du*laplacian(u)-u*v*v+F*(1-u)" \
- -Delta_v="Dv*laplacian(v)+u*v*v-v*(F+K)" \
- -DF=0.040 -DK=0.060 -DDu=0.200 -DDv=0.100 \
- -DUV_BACKGROUND=1,0 -DUV_DROP=-0.5,0.5 \
- -DTIMESTEP=1.0 -DSPEED=2 -DRGB=255:128:192
-
-
-Then, run it under tcpserver command in ucspi-tcp package, which was created by Daniel J. Bernstein, IOCCC 1989 “Best of Show” winner.
$ tcpserver -v 127.0.0.1 10333 ./prog ioccc.txt
-
-
-Finally, open http://127.0.0.1:10333/ by a modern browser supporting HTML5. You can use the mouse cursor to place drops into the Petri dish interactively.
This is a simulator of reaction-diffusion systems.
- -Reaction-diffusion systems, proposed by Alan Turing in [1], are mathematical models in which two chemical substances are transformed into each other (local chemical reactions) and spread out (diffusion). Their interactions sometimes form non-trivial patterns, such as spots, spiral, dappling, and labyrinths.
- -The systems are generally formulated as follows:
- -du/dt = F(u, v) + Du * laplacian(u)
-dv/dt = G(u, v) + Dv * laplacian(v)
-
-
-The functions F(u, v) and G(u, v) represent reactions of each substance, and the parameters Du and Dv are diffusion coefficients. By changing the functions and parameters, you can see a wide range of behaviors.
See the Wikipedia article of “Reaction-diffusion system” in detail.
- -This program simulates the systems. The field consists of 128 x 128 cells. Each cell includes infomration of an amount of the two substances, and interacts with neighbor cells (in terms of von Neumann neighborhood) in each frame.
- -You can change the model, initial pattern, simulation speed, and color via macro definition.
- --Delta_u=<expression> -Delta_v=<expression>The definitions represent the equations of reaction-diffusion system. For example, the following is the Gray-Scott model in TeX notation.
- -\frac{\partial u}{\partial t} = D_u \Delta u - u v^2 + F (1 - u)
-\frac{\partial v}{\partial t} = D_v \Delta v + u v^2 - v (F + K)
-
-
-You can specify this model as follows:
- --Delta_u="Du*laplacian(u)-u*v*v+F*(1-u)" \
--Delta_v="Dv*laplacian(v)+u*v*v-v*(F+K)"
-
-
-Du, Dv, F, and K are parameters of that model.
-DUV_BACKGROUND=<u0>,<v0> -DUV_DROP=<u1>,<v1>The definitions specifies the initial amount of the two substances u and v. All cells have (u0, v0) by default.
You can specify a pattern file when the executable is invoked (not compile-time). The file should include a sequence of points, see ioccc.txt, center.txt, or line.txt as examples. Each amount in cells near to the point included in the file, will be added by (u1, v1).
-DTIMESTEP=ts -DSPEED=spdThe definitions are for changing the simulation speed.
- -TIMESTEP is a simulation time step. The bigger, the faster but more unstable.
SPEED is a frameskip parameter. The bigger, the faster but more sluggish.
-DRGB=r:g:bThis specifies a color used for rendering.
- -Some interesting parameters are included in Makefile. Do one of the following command and open http://127.0.0.1:10333.
$ make gray-scott-1 && tcpserver -v 127.0.0.1 10333 ./gray-scott-1 ioccc.txt
-$ make gray-scott-1 && tcpserver -v 127.0.0.1 10333 ./gray-scott-1 center.txt
-$ make gray-scott-1 && tcpserver -v 127.0.0.1 10333 ./gray-scott-1 line.txt
-$ make gray-scott-2 && tcpserver -v 127.0.0.1 10333 ./gray-scott-2 ioccc.txt
-$ make gray-scott-3 && tcpserver -v 127.0.0.1 10333 ./gray-scott-3 ioccc.txt
-$ make gray-scott-4 && tcpserver -v 127.0.0.1 10333 ./gray-scott-4 ioccc.txt
-$ make fitzhugh-nagumo-1 && tcpserver -v 127.0.0.1 10333 ./fitzhugh-nagumo-1 ioccc.txt
-$ make fitzhugh-nagumo-2 && tcpserver -v 127.0.0.1 10333 ./fitzhugh-nagumo-2 ioccc.txt
-$ make oregonator && tcpserver -v 127.0.0.1 10333 ./oregonator ioccc.txt
-
-
-These examples are created by drawing (and modifying) the pattern files of Ready, a cross-platform implementation of various reaction-diffusion systems [2].
- -This program compiles clean with no warnings under -std=c99 -Wall -Wextra -pedantic. Since it uses long long for 64bit integers, C99 is required.
You must use a modern browser that supports the latest specification of WebSocket [3]. All the following browsers worked for me:
- -I think Safari 6 will work but I haven’t tested. (I have no recent os x.)
- -I think you may use inetd and xinetd instead of tcpserver. Here is an example of inetd configuration.
10333 stream tcp nowait nobody /path/to/prog /path/to/prog /path/to/initial-pattern.txt
-
-
-But note that I didn’t test well.
- -![]() |
-© Copyright 1984-2016,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Yusuke Endoh
-https://github.com/mame/
-Twitter: @mametter
make
-
-./prog
-
-
-cat prog.c
-
-./prog | diff - prog.c
-
-
-At this point you might be wondering, WTF?*
- -* What The Freak (polite form)
-
-* What's This For? (you may be wondering)
-
-* What the Fish (python form)
-
-
-How is this code obfuscated? Well look again:
- -less prog.c
-
-more prog.c
-
-
-Where did those underscores come from? Well RTFS!**
- -** Read the Freaking Source (polite form)
-** Read The Freakin' Screen (polite form)
-
-
-If you are still puzzled, look at prog.c with your favorite text editor.
- -Follow this instruction literally!
- -cat prog.c
-gcc -w -o prog prog.c
-./prog
-
-
-You will do a double take.
- -Hint 1: Do less prog.c. You will see an emphasized string if your terminal supports bold.
Hint 2: Do wc -c prog.c. This is very long one-liner.
Spoiler: Open the source with an editor like vim or emacs.
![]() |
-© Copyright 1984-2016,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Yusuke Endoh
-https://github.com/mame/
-Twitter: @mametter
make
-
-./prog
-
-
-make -B BACK_TO=ioccc.c
-
-./prog
-
-
-Like Marty and Doc, something nostalgic from 1984 appears live in October of 2015! -The author of this gem is a true Delorean!
- -A question for inquisitive readers: is the implemented subset of PDP-11 instructions Turing-complete? -(For a clue, see the end of the author’s remarks.) -If in doubt, use APOUT.
- -This program is a joke PDP-11 emulator. (“ll-dpd” is embedded in the code. Read it upside down.)
- -You got it? This program is supposed to be used in this way:
- -$ wget http://ioccc.org/1984/mullender.c
-$ clang -o prog prog.c mullender.c
-$ ./prog
-
-
-You can enjoy the legendary winner of the first IOCCC, again.
- -This program uses __attribute__((constructor)), which is a GCC extension, to hijack the main function call. And then it interprets main as an instruction sequence.
It supports the minimal subset of instructions and addressing modes which are needed for mullender.c to work:
- -Instructions
- -Addressing modes
- -Non-trivial combination of instruction and addressing mode may cause undefined behavior (unsequenced modification), such as attempting to autoincrement a destination register. Index addressing mode works well only for R7 (PC register).
- -Note: the program writes a binary to stdout.
- -short main[]={5568,1,-30460,12,2782,0,-29921,2056,-4864,6873,770,30054,11886,
-24948,114,21716,-28851,14043,-8944,32691,-16187,-12247,22692,-9781,-20403,
--11771,16546,18710,17873,9233,31304,-32215,-24382,-28247,-25916,10466,24988,
--3404,-4177,-28528,-531,-3016,17300,-28552,-7708,-26180,-4297,-367,-2312,
--25611,28535,-8533,24004,25421,-1224,-5354,-20807,-21589,-6761,-5203,-1055,
--6715,-26673,-1433,-17732,-24198,14681,-3714,-6660,-14891,-25575,20349,-7701,
--8336,31433,16695,-14773,26819,3096,-12584,-28808,17825,-21200,-32399,15877,
--28890,-3728,-27126,21375,-32630,-7615,32004,-29230,-6611,-5508,-28921,12418,
-27204,-5725,9643,3520,26836,-29347,2101,-29311,9320,29287,-29990,-6593,29825,
--29114,16232,25641,20672,-23501,-32127,-6546,-956,10474,-29647,1070,5516,13760,
--27814,-32488,-28006,-17968,-3146,10963,19234,22132,23988,7142,5523,9639,-6888,
--11428,7964,23099,-16822,16518,31109,-12958,10351,2434,3091,3625,2244,27512,
--28559,-10724,-19377,23625,30056,11478,-21176,27660,26517,-29037,-9390,12297,
--11903,5980,-21927,-7483,6671,11249,29638,-23827,-26358,-6856,-1063,-5303,
-26636,25797,31818,26798,-4243,-18772,-13266,27472,-12005,-10642,-22524,24373,
--13111,-9062,6274,-20002,24150,22189,-14965,-31249,-13934,-6341,-18384,-32054,
--29246,10622,-9260,19428,-15485,2724,23810,16447,11627,18604,2739,27812,30295,
--21538,-31786,11355,-11308,-9006,-4987,25363,-18927,-21130,-31213,-27411,17231,
--19608,20232,27754,16476,11213,-19803,-24048,30918,-25329,21233,-10160,13519,
-11828,26653,-6703,10893,6871,-12417,24471,20310,-12137,-19677,4457,-19530,
-10147,17724,533,-10055,27076,10264,11274,-10511,4809,25208,16065,-5105,-19953,
-3772,-12124,13475,-27559,-9955,26446,15133,15207,-23640,6425,-11010,28688,
--20064,26353,-889,-25008,10380,-14449,-6894,18920,-23900,16902,-31018,16093,
-20875,-19576,4585,13126,18589,24789,19424,31274,-5059,-14538,-3125,-16527,
--25070,-9013,26628,15756,-7652,30841,-1283,17707,25717,-18315,-6342,6880,
--19176,6995,5672,2853,-9044,-3409,-14421,-7522,13108,20582,-25317,1376,-5648,
-13821,17300,1220,-29437,-25832,-8332,-15575,-9744,28297,31995,-1217,23852,
-14382,31059,9160,-3296,20287,-28357,24449,-10323,-21992,-4655,-32548,13237,
--15083,-25226,-21121,2015,-8996,-20247,-27551,-14771,-16089,-6920,-9645,21578,
-7142,-5613,14029,24730,-29253,13931,-3862,-16634,-7388,16951,15771,31302,
--22186,-6716,18416,1698,-26200,-16231,9821,-10886,-4994,-30527,-9448,-16923,
-29549,-11207,-14909,-3643,-27548,17865,28859,29753,17616,16874,-17733,9424,
-21435,-31715,24544,8666,30844,25075,-18267,12027,-5346,2717,19615,-4548,-21763,
-28514,11691,22268,-2338,1406,-27379,-23568,-24525,13633,11295,-14715,7877,
--27669,3475,20345,7779,-17849,2184,7132,4079,-24937,11585,22740,5810,-10855,
-16203,-6371,23235,-7,-24828,-11205,-11006,-10,-17812,-14274,11504,-27517,463,
-4498,-32180,-9775,-3190,-22435,-18662,-30146,-31834,-26449,-19374,-12616,
--10596,14341,-10089,-18449,-16535,21439,21191,-1651,7695,-30009,-23339,-8675,
--20774,21588,-2793,8218,-14337,-10866,14060,-15343,31712,25247,-8539,18074,
--28683,-7363,-7663,-3563,-30718,17771,28687,-30495,30584,14022,-28053,5292,
--31576,-32486,-15470,-1330,23551,-2185,-10829,-13216,-4825,-2964,-14668,24559,
--4930,23731,-1152,-11493,-2321,15987,-27073,-20305,-24065,-25048,32750,-27440,
--1169,-25633,-4356,-24993,30439,-17165,-4580,8662,22655,-4588,-6162,-3122,
-31986,-2569,20371,-12320,-25613,-16133,-25644,23677,12254,5855,26325,-13425,
--15903,-1930,-28488,31222,31153,17607,-2758,7594,-8868,30434,-2518,27956,
--19424,7370,6199,-17602,17347,-14358,25588,11611,-25209,-23701,-27444,-29788,
-2680,-27406,9318,22483,-28356,28482,4577,-14891,17323,-30152,2507,2977,5004,
--11696,-31623,-15149,13357,28938,-14048,19490,-19860,-26050,10842,-24922,
--20986,8847,-31184,28519,-29168,32195,10516,25713,-3493,670,31283,-12769,
--17461,11357,13180,26133,15944,18051,-32167,-27990,16813,17676,21787,-17578,
-11173,19093,2836,656,-15239,4632,23937,4106,-21655,-7494,-21575,-17647,-18465,
--14654,-29990,-10707,-12440,21465,5822,26164,-1404,-14303,-26635,-6900,-23611,
-11998,-18551,971,27579,13325,4579,23059,29281,22291,29880,-17546,25664,-14990,
--526,-35,28218,-3214,11965,11263,6633,30719,32400,-29,-3733,24383,32678,-27542,
--4444,6196,5975,-19722,11902,16840,-11680,11146,-26391,-8980,21573,-9043,2349,
--12887,5916,-2996,10410,-23374,26338,11867,-14518,18281,14450,-5815,13842,359,
-25450,27043,3355,13423,-20880,-26311,-30720,-2503,-6046,-18156,-18558,-14774,
--15664,-29001,3365,-12689,10233,23608,24692,12039,15445,18411,-27469,3764,
--10841,22672,23844,2282,-12443,2851,-27163,13651,13738,17201,-29819,27414,
--29764,-5308,-16171,-32427,-26312,-7460,-27376,-6004,25717,29254,-15015,8754,
-15493,22232,-28513,-23355,23676,7736,10571,-8120,-16677,7696,32549,-2646,25538,
-3498,30960,-28459,24716,12655,-10496,402,26209,482,-16661,-20350,-3403,14015,
-32299,11262,-25886,4092,-7843,-100,-1975,-58,-3729,-19269,-23583,-6929,20000,
--6089,17780,-3250,29830,19954,-29277,27896,10330,9277,-25358,31279,-14454,
-24203,-30170,12872,-21973,-25773,-10502,-6647,-26143,6394,-13479,-24559,23007,
--21844,1505,24702,-23187,-24364,-20470,20765,-7107,15674,9404,17408,17964,
-19820,18952,2154,-26052,30056,-3227,17770,-8557,-31018,-27700,-25974,9003,
-18218,22730,-19981,6737,3532,1562,-23626,14990,28472,-5270,17358,-32204,-29197,
--3647,4296,8588,25302,-23906,30328,-29119,-24392,8992,-16557,31530,-31216,
-14107,13041,-6976,7529,-8296,17865,-1462,8181,-21588,-131,-10177,-25931,-14627,
-8301,3708,-32097,20808,13892,-21179,1192,20853,3249,-8774,20843,3520,24954,
--14215,-25170,-16170,2390,25964,-23923,-17464,-7177,-27568,-9880,-4647,-7323,
-15388,2113,-12338,-7737,26255,26818,-22156,-19610,-911,-17057,-556,29935,27647,
-31806,23676,-18132,-19234,-10869,-3715,24983,-10900,-29564,19856,-16392,-31860,
--25826,24077,12080,15383,-29852,-2266,-27217,31931,-3183,17385,-14211,19050,
--2449,-468,-2871,-11466,973,2866,649,1367,-8688,-24069,20992,25139,-25850,1184,
-15851,785,16951,12160,22337,-21851,1849,-18801,14247,-429,-12682,30881,-11273,
--24819,-9794,8389,-27287,7525,16633,1328,-26650,32607,-8217,31912,7774,-16188,
--3546,-6550,-16279,-32696,1940,2577,-23723,-6484,2009,-424,27833,-21763,-13902,
-7044,27360,-18450,27889,23987,3137,-7669,-5784,-7490,24946,32302,26464,-15513,
-28898,2493,-17645,-4615,-13434,-20884,-4058,-29951,-22281,24784,21083,-8536,
-22147,-11261,-15069,20659,2993,19029,21909,6748,-3263,1401,30960,11000,-16871,
--30566,-14959,-26356,-2885,21526,-26531,31063,12857,4992,-5067,3130,-17602,
--1732,-6593,30200,24679,3267,310,20733,24863,-15669,7875,-4577,-13821,-22325,
-15548,29744,3733,-14547,21459,22122,3854,-2572,30197,-24770,-21263,8793,-8316,
-1571,28191,-16143,-6446,31524,-26496,-17349,-29097,2806,11281,-7041,-683,14149,
-19689,-22094,-1657,-30904,183,-15226,-6358,25461,461,1495,28345,-10554,-4004,
-27119,13484,-21600,-12272,-7272,-14064,-299,10697,11280,19066,-9841,-7265,
--18002,19906,-17247,21482,-10939,-5897,-22300,-13978,27575,-8684,-6222,-19041,
-5788,-30863,-10134,15142,2895,14705,-17713,12940,-21535,-11619,29416,18417,
--24973,24867,-26462,-24910,-32556,-26705,-7187,-7750,-758,-14809,20289,9260,
-13778,-1422,30301,-1922,30646,27662,-15465,-912,29340,13846,-1263,28887,-20019,
-32421,-29411,-27632,-7495,-8368,29230,-6386,-19536,-5235,2054,1854,23563,12348,
--15165,-2936,-28063,-15760,20126,-25531,4963,-5739,23182,16895,-17258,-10470,
--3969,-7742,-140,4475,-24014,-31961,19231,27153,-18551,20157,26443,11530,
--22214,2284,-24238,-31051,-26422,9088,29868,18458,8488,-9515,6799,-12507,54,
--19441,-32665,12561,23560,4725,-28617,-14800,-10224,-13503,-17636,-16823,
--24072,18735,-29798,-23658,-670,-21769,7489,-6468,-8961,-14785,22255,11582,
--29831,16303,-19652,2922,-4362,22966,16173,-18446,-6148,27381,-8493,-32289,
-24005,-3027,-18665,-16472,-17793,-27027,-7443,17854,31365,-17726,-2510,-17546,
-14893,21773,-23634,21117,32533,6637,-1106,-8152,-3672,-113,-2149,-34,-22700,
--4102,-28533,-14104,-10086,4378,13695,-15320,-28258,2246,7595,30021,13281,
--11968,-29983,14274,27152,26713,19434,17058,1142,-3043,-16496,18630,-11976,
-29168,-3634,32746,27287,-268,16711,-8712,-471,12895,17406,-22548,-3969,-10733,
-13128,10530,-31667,7929,-32277,30926,-1983,8401,-7705,6790,4532,1442,26728,
-29600,-15358,21622,9744,11406,15989,-30741,-15044,29913,24534,6774,-3755,17623,
-19647,18762,10042,9653,-5889,2408,-32579,-6285,-28559,-30655,6294,-21175,4390,
-1668,25437,2821,21066,-13680,5274,-27253,-5248,-26307,29744,-26428,25358,17196,
-15199,-29784,-4604,25653,-8048,-23131,-28995,31340,-9558,26186,11268,27916,
-9646,-7389,-11384,-29116,-4100,160,18394,7856,738,-25920,12148,24713,-31664,
-8203,-25556,13494,30352,29161,30898,1432,-5991,25411,1344,-4019,22299,15685,
--16401,-23136,-28110,11874,-18945,1879,2,0,-32256,-20996,-18169,29220,12,0,0,0,
-335,-27277,-30776,20480,0};
-
-
-![]() |
-© Copyright 1984-2016,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Yusuke Endoh
-https://github.com/mame/
-Twitter: @mametter
make
-
-./prog <a number of arguments>
-
-
-./prog @ @ @ @ @ @
-
-./prog @ @ @ @ @ @ @ @ @ @ @ @
-
-./prog $(perl -e 'print "@ " x (2*3*5*7);')
-
-./prog $(< Makefile)
-
-
-For this one liner it is best to avoid prime numbers. The output groups -factors in the x-y dimensions. How many factors can be represented before you -run out of command line argument space? How could you modify the program to -experiment with numbers that have more or larger factors?
- -Visual factorization 1-liner. Try:
- -gcc -o prog prog.c
-./prog @
-./prog @ @
-./prog @ @ @
-./prog @ @ @ @
-./prog @ @ @ @ @ @
-./prog @ @ @ @ @ @ @ @
-./prog @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
-
-
-Inspired by Animated Factorization Diagrams.
- -EDIT: prog.orig.c is the original version that I submitted. Gil Dogon kindly improved it during the review. Thank you!
![]() |
-© Copyright 1984-2016,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Qiming Hou hqm03ster@gmail.com
-http://www.houqiming.net/
make
-
-echo IOCCC | ./prog
-
-
-echo "" | ./prog
-
-
-A good start for understanding this entry might be -https://www.ietf.org/rfc/rfc1321.txt. How does it compute this using only a -single looping construct? The original reference source code for this -algorithm is about 355 lines of code, yet this entry is only 199 lines with -one statement per line and it isn’t using lots of macro expansion tricks like -the reference code!
- -Some things that make you go, “huh?”
- -./prog < prog.c | cut -c-5
-./prog < Makefile | cut -c-4
-
-
-How are those values magically returned?
- -What happens with a large file? Something over 256K
- -./prog < large_file
-
-
-Where does that message come from?
- -This looks like a normal C program.
- -Almost everything is a double.
- -There are tell-tale signs like pow(2,(?/12)) and exp(-?*?) (names redacted). You can also find a bunch of cosines and polynomial evaluations.
It looks like a ????? ???????????, right?
- -Run and find out.
- -Some poor scripting folks only have access to doubles (Jav?script, L?a, BA?IC, etc.).
- -As a C programmer, I feel obliged to show a gesture of sympathy, to experience their pain and provide an answer.
- -Except when absolutely necessary (printf, int main(), array indexing), there isn’t a single integer. Even getchar() and EOF are immediately converted.
Since bool counts as an integer type too, there is no boolean either. No comparison, no if, no ?:, no || &&. Everything is done in a single loop that terminates on printf. Straight up arithmetic.
floor and ceil are technically double-to-double functions, but they feel like cheating. Yes cos, no floor.
Hard requirements:
- -The platform must implement the double type as IEEE754-compliant 64-bit floating point numbers. The 80-bit intermediate format used by x87 is considered as an violation of this. The code should print an error message on such platforms.
The program must start with the CPU / FPU in round-to-nearest mode.
Soft requirements:
- -The compiler must respect volatile. The code is formatted to warn about that, though.
The printed result is only correct on little-endian machines. The program takes care to warn about this issue after printing an incorrect big-endian result. Error messages become garbled, though.
Tested platforms:
- -![]() |
-© Copyright 1984-2016,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Anthony Howe achowe@snert.com
-Montreal, Quebec, Canada
-http://www.snert.com/
-Twitter: @SirWumpus
make
-
-./prog file1 file2
-
-./prog -d file1 file2
-
-
-./prog prog.orig.c prog.c
-
-make test
-./prog -d ABXYEFCD.tmp ACDBECFD.tmp
-./prog ABXYEFCD.tmp ACDBECFD.tmp
-
-rm -f curds.tmp whey.tmp
-cp /usr/share/man/man1/cc.1 curds.tmp
-cp /usr/share/man/man1/cc.1 whey.tmp
-chmod 666 whey.tmp
-make makeholes
-./makeholes -n 1000 whey.tmp
-./prog curds.tmp whey.tmp
-./avgtime.sh 100 ./prog curds.tmp whey.tmp
-
-# Assuming curl(1) installed, grab a really HUGE text file.
-curl -L -o war-and-peace.txt http://www.gutenberg.org/ebooks/2600.txt.utf-8
-cp war-and-peace.txt nuked.tmp
-./makeholes -c'~' -n 1000 nuked.tmp
-./prog war-and-peace.txt nuked.tmp
-./avgtime.sh 100 ./prog war-and-peace.txt nuked.tmp
-
-
-This is the best use of the FNV that we have seen in the IOCCC so far! -The output, when used without -d, is compatible with POSIX diff and -is suitable for use with patch.
- -We welcome back Canada to the list of nations from where winning -entries have been submitted.
- -Is this code a bug or a feature? :-) Or is this an attempt to corrupt the -programming of our youth? Should we heed Kyle’s mom words that she uttered -during a South Park P.T.A. Meeting?
- -“We must stop dirty © language from getting to our children’s ears!”
- - - -Or should we teach our youth to understand the intricacies of this code? -Ying Tong Iddle I Po! We suggest you read the source for yourself, which -might be easier than the academic papers it was inspired by.
- -NOTE: Unlike the original entry source, prog.orig.c, prog.c uses a -64 bit FNV hash and fixes a function call warning.
- -“An O(NP) Sequence Comparison Algorithm” by Wu, Manber, Myers, Miller.
Output compatible with patch(1).
Strokes one of the judge’s ego (I couldn’t email chocolate or curry).
This is a functioning micro diff tool using an O(NP) algorithm, compared to the older O(ND) difference algorithm used by some versions of diff. Its output is based on the default diff(1) output described by POSIX and The Open Group Base Specifications. The output is suitable for use with patch(1).
- -The -d option simply writes the edit distance between file1 and file2.
- -The FNV1a hash is a little slow compared to the trival hash GNU Diff uses. I downloaded a plain text copy of “War And Peace” from Project Gutenberg, used makeholes.c to make 1000 random changes, then profiled and timed the program verses GNU Diff. The bottle neck appears to be in the file I/O and line hashing with an average +0.05s slower. Using a huge file like “War And Peace” for testing offsets the diff(1) optimised file I/O.
There is no hash collision checking, partly because FNV1a appears to generate very few collisions and an assumption that localised collisions within a region of edits are highly unlikely.
- -prog-test.sh
-Basic test program verifies known test edit distances and patch support.
avgtime.sh
makeholes.c
-Random edits (holes) made to a file in-place.
Wu, Manber, Myers, and Miller; August 1989;
-“An O(NP) Sequence Comparison Algorithm”;
-http://myerslab.mpi-cbg.de/wp-content/uploads/2014/06/np_diff.pdf
Fowler, Noll, Vo; 1994
-http://www.isthe.com/chongo/tech/comp/fnv/index.html
Fowler, Noll, Vo on Wikipedia
-https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
“diff”, The Open Group Base Specifications Issue 7
-IEEE Std 1003.1, 2013 Edition
-http://pubs.opengroup.org/onlinepubs/9699919799/utilities/diff.html
Eugene W. Myers; “An O(ND) Difference Algorithm and Its Variations”;
-Algorithmica, 1986, pages. 251-266
-http://www.xmailserver.org/diff2.pdf
Webb Miller and Eugene W. Myers; “A File Comparison Program”;
-Software-Practice And Experience, Vol. 15(11). 1025-1040 (November 1985)
-http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.189.70&rep=rep1&type=pdf
D.S. Hirschberg, “A linear space algorithm for computing maximal common subsequence problem”;
-Comm. of ACM, Vol. 18, June 1975, pages 341-343
-http://www.mathcs.emory.edu/~cheung/Courses/323/Syllabus/DynProg/Docs/Hirschberg-LCS-1975.pdf
Which hashing algorithm is best for uniqueness and speed?
-http://programmers.stackexchange.com/questions/49550/which-hashing-algorithm-is-best-for-uniqueness-and-speed
![]() |
-© Copyright 1984-2016,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Chris Mills
-Twitter: @MisterXopher
make
-
-./prog
-
-
-Pressing the up arrow and the down arrow at the right time.
-
-
-Did you find that mobile application game a bit frustrating? -Well you can adjust the makefile parameters to make life a -bit easier for you:
- -make clobber all DW=199999 DW=22 DH=16 DA=50 DI=-150
-
-
-From the makefile:
- -# Game parameters
-#
-DU=99999 # Time between steps in microseconds.
- # Make it larger if the game is too fast for you.
-
-DW=28 # Pipe-to-pipe spacing, in columns.
- # Farther apart is easier.
-
-DD=20 # Space between pipes.
- # The difference between DD and DW is the width of a pipe.
- # Narrow pipes are easier to fly though.
-
-DH=8 # Height of gap in pipe.
- # Make this larger to make the game easier.
-
-DA=100 # Acceleration due to gravity (scaled by 256).
- # Smaller values make you glide slower.
-
-DI=-200 # Impulse velocity of a flap (scaled by 256).
- # Make larger if you want an less intense tapping experience!
-
-DB='"<o^="' # Sprite for player when gliding.
- # HINT: Try using various emoji.
- # NOTE: The string MUST be enclosed inside double quotes.
-
-DF='"<ov="' # Sprite for player when flapping.
- # HINT: Try using various emoji.
- # NOTE: The string MUST be enclosed inside double quotes.
-
-DG='"Tap to Flap!"' # Instruction text.
- # Change to your native tongue.
- # NOTE: The string MUST be enclosed inside double quotes.
-
-
-Enjoy!
- -TAP!! TAP!! TAP!!
-FLAP! FLAP! FLAP!
-
-
-Better late than never to jump on the bandwagon of 2014’s most successful -mobile game. The game is called Tappy Bird, and has all the sophisticated -gameplay of the original, except with an exciting twist! (you get to fly to -the right instead of to the left).
- -In addition, the game features exciting new customization options! Too hard? -Ran into that damn wall too many times? Now you can change physics! Change -any of a number of parameters (speed, gravity, etc.) of the game to suit your -gameplay!
- -You can even make the game more challenging – resize the terminal window to -make the world taller or shorter. You’ll never be able to get through the -pipes when they are four times as tall!
- -The instructions are printed at the start of the game: Tap to Flap!
- -Hit any key to make your bird fly. Navigate her between the gaps in the pipes. -Your score is shown in the upper left, along with your current high-score.
- -To customize the gameplay, change any of the following options on the compile -command line:
- --DU: Time between steps in microseconds. Make it larger if the game
-is too fast for you.-DW: Pipe-to-pipe spacing, in columns. Farther apart is easier.-DD: Space between pipes. The difference between D and W is the
-width of the pipe. Narrow pipes are easier to fly though.-DH: Height of gap in pipe. Make this larger to reduce the challenge.-DA: Acceleration due to gravity (scaled by 256). Smaller values
-make you glide slower.-DI: Impulse velocity of a flap (scaled by 256). Make this smaller
-if you want an intense tapping experience!-DB: Sprite for player when gliding.-DF: Sprite for player when flapping.-DG: Instruction text. Change to your native tongue.Feel free to try out physics or playfield options to make the game more -interesting. Try setting the player sprites to change the game completely – -maybe you can be a fish, or a pig – the options are limitless! Try using -emoji – you can be a flying beer mug!
- -Note that since the curses library on POSIX doesn’t natively support wide
-characters (needed for UTF-8 support, which is needed for emoji), you may need
-to make some changes to the Makefile to get emoji to work on your system.
-To help you get started, I’ve included some example substitutions for emoji
-sprites and instruction text; for example, type
make EMOJI=beer LANGUAGE=spanish
-
-
-or
- -make EMOJI=globe
-
-
-for some examples (the full list of options is in the Makefile). Don’t
-forget to make clean first. If the output doesn’t look right, you may need
-to link with the “wide” version of ncurses. On MacOSX 10.11, it should work
-with the current -lcurses; on Linux, you probably need -lncursesw.
-See the Makefile to make this change if you need to. Or buy a Mac.
You will also need a UTF-8 compatible terminal and an emoji font installed,
-and you will need to have your LANG environment variable set to use UTF-8.
-Again, if this is too complicated, maybe just go and get that Mac.
Future versions of the game will include monitization via the freemium model -with micropayments for customization options, play-to-win and of course -live-streamed targeted video advertising.
- -![]() |
-© Copyright 1984-2016,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Chris Mills
-Twitter: @MisterXopher
make
-
-./prog compressed_file.Z
-
-
-printf '000I\236\f\31H\260\240\301\203' > ioccc.Z
-./prog ioccc.Z
-
-dd bs=1k count=4096 < /dev/urandom > test1
-compress < test1 > test1.Z
-time ./prog test1.Z | cmp - test1
-
-dd bs=1k count=4096 < /dev/zero > test2
-compress < test2 > test2.Z
-time ./prog test2.Z | cmp - test2
-
-
-Without ASCII art, the source code of this entry would have been exactly 256 bytes. -Compared to 1990/jaw, it is very impressive, -even taking into account the missing atob functionality. Now we wish for a compress(1)-like compressor -using a similar idea.
- -Why is the sad smiley on line 12 in that particular place?
- -This program is in implementation of the unix zcat(1) command for printing
-compressed files that have been created by the compress(1) command.
The adaptive LZW compression
-employed by compress usually requires a fairly large amount of memory to
-build the decompression tables (in fact, compress has a command-line option
-to control the size of the decompression tables, since some of the early
-systems to which it was ported (coughMS-DOScough) did not have enough
-memory to use the full 16-bit codes). This version has no large static or
-dynamic tables. It is able to decompress 16-bit files using a single function
-and a few ints.
To run the program, take an existing compressed file and pass it to the program
-on the command line. On the odd chance you don’t have compress hanging about
-on your system, I’ve provided compressed copies of this year’s IOCCC rules
-and guidelines files. To print them, just do
./prog ioccc_guidelines.txt.Z
-
-
-The basic cleverness here comes from realizing that the compressed data is -itself an encoded version of the code dictionary. When the encoder sees -an input string that is not in its dictionary, it emits the code corresponding -to the longest prefix that is in the dictionary and adds a new entry consisting -of that code followed by the next input character. This means that when the -decoder wants to know how to decode a code, it just needs to find the spot in -the code-stream where the encoder added that entry to the dictionary. The -code at that spot is the prefix, and the first character of the following code -is the suffix. Decoding then just becomes recursion, to follow the chain of -prefixes and suffix characters.
- -Of course, it’s not nearly that simple. Finding the code in the stream is -complicated by several issues:
- -compress encoder reserves a code word that clears the coding tables.
-When this is encountered, the computation of offsets and bit sizes reset.compress decoder is designed to always read a block of eight code
-words at the same time, so that it need only read N bytes to get eight N-bit
-code words. When the “clear” code is encountered, the entire eight-word
-block is flushed (since the decoder didn’t know the word size would change).
-The program needs to account for this extra flushing.Managing all the details involved added a lovely additional layer of -obfuscation to the otherwise elegant recursive decoder. Still, the code -manages it in a remarkably small amount of code.
- -The decoder doesn’t look at the header. If you supply something that is not -compressed data, it’s likely to crash in an interesting manner.
- -In particular, it doesn’t look at the third byte of the header, which encodes
-the maximum code word size and whether “block mode” was used when the encoder
-was run. If you use compress in its default mode, the maximum word size
-will be 16 bits and “block mode” will be enabled. You are unlikely to find
-any files that don’t use “block mode”, since all versions of compress after
-2.0 (circa 1984) use it by default and have no documented way to disable it.
-Reducing the bit depth is still possibly by using the -b flag. Modern
-systems have no problem with the 200 KB or so needed for 16-bit decoder
-tables, so the need for reducing the table size has passed, hence this program
-always assumes 16-bits… However, should you find a file that needs a
-smaller table, feel free to change the hard-coded 16 in the source into the
-appropriate number and recompile.
In the event that you don’t supply an argument, or that argument doesn’t name -a readable file, the program will just silently exit. This is a feature.
- -The program depends on having a little-endian system. On a big-endian system
-you will get a wierd big-endian version of compress, which might have come to
-pass in an alternate universe where the vax on which compress was authored
-had been big-endian. Luckily for us, it wasn’t, and neither are most of the
-systems you might want to compile this for.
![]() |
-© Copyright 1984-2016,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Dominik Muth muth.ioccc@freenet.de
- -make -B [MACHINE=your_machine.h] [TAPE=your_tape.h] [X=[0|1|2|3|4|5|6|7|8|9]] [V=[0|1|2]] run
-
-
-make -B V=2 run
-
-strings prog | grep '(,)'
-
-make -B MACHINE=machine_times2.h TAPE=tape_five.h V=1 run
-
-make -B MACHINE=machine_chaos_5_2.h X=5 run
-
-
-This is something we were fearing all along: that the C preprocessor is Turing-complete -even without conditionals and recursive file inclusion as some kind of a -rewriting system. Now we have the proof!
- -#ifs or other conditional directives, only #defines#includeV=0 (default) only prints the final tapeV=1 additionally prints one tilde character per machine step (slow)V=2 additionally prints details on each machine step (slow; generates large files)run runs ./prog and filters a little statistics out of the verbose outputX (defaults to 3) sets the maximum number of steps: M(X) ~ 8XIf the machine does not halt after M(X) steps, you will see unexpanded macros in the output.
If V=1 or V=2 is used, you may see “warning: string length is greater than the length '4095' ISO C99 compilers are required to support”.
Implementing your own Turing machine is easy. Take a look at the supplied header files for examples.
- -Every symbol used (except “_”) must be explicitly declared using
#define sym_SYMBOL(sym, _SYMBOL) sym
-
-
-Example:
- -#define sym_1(sym, _1) sym
-
-
-The initial content of the tape must be defined in the tape header using a triple like:
- -#define tape ((((,),...l2), l1), c, (r1, (r2..., (,))))
-
-
-l1, l2, … are the symbols to the leftc is the symbol at the current positionr1, r2, … are the symbols to the rightThe empty pairs “(,)” represent the continuations of the tape, filled with underscore symbols (“_”). They are expanded on demand.
All transitions are defined in the machine header using the syntax
- -#define CURRENT_SCANNED (WRITE, MOVEMENT, NEXT)
-
-
-where
- -CURRENT is the current stateSCANNED is the symbol at the current positionWRITE is the symbol to be written to the tapeMOVEMENT is “L” for left, “R” for right, or nothingNEXT is the next stateThere must be a state “A” defined, which becomes the initial state of the machine.
To halt the machine, use the keyword “break” as in
#define A_1 (2, break)
-
-
-![]() |
-© Copyright 1984-2016,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Jens Schweikhardt
-http://www.schweikhardt.net
make
-
-./prog n
-
-where n is a base 16 number of any size
-
-
-./prog 19
-
-
-This code is clean. When you compile with all warnings enabled, -such as with clang:
- -cc -Weverything -pedantic -std=c11 -Dtyp=uint64_t -O3 prog.c -o prog
- -The code compiles without warnings on the systems that we tested!
- -Even more, the code was 100% clean when we ran it against various -static source checkers.
- -This tool references a problem that David I. Bell once described -as having one of the largest “yummo quotients” in number theory:
- - complexity of the solution
-yummo quotient = -----------------------------------
- complexity of the problem statement
-
-
-Erdős privately told one of the IOCCC judges:
- -“Solving the Generalized Riemann hypothesis -would be a good warmup exercise for someone to get ready -to begin to work on the Collatz conjecture.”
- -You may explore this famous conjecture using this entry:
- -./prog 2410
-./prog abfff
-./prog 27f8cebf
-./prog 246f8fddf
-./prog 2e95ab51ffea9de
-./prog e6a5c22fd7bde9f
-./prog 1b7dd73a937485bf
-./prog 7d3237680d190a77e53751b
-./prog 302ab3d052fb87c06228d249581be0e4
-
-
-When you first look at the source, the code looks fairly straightforward. -But look again. Like the Collatz conjecture, simplicity is deceptive! -Oh, and the variable names? They are not simple single letter variables, -they are names of various Proteinogenic amino -acid: -which is yet another simple building block that can be used to -build some very complex structures. :-)
- -p.s. We appreciated that apart from a few powers of 2, the source -code is magic number free.
- -This is the cleanest program ever submitted. If for some input it enters -a non-terminating loop or runs out of memory you will be insta-famous. -It’s a bit like a lottery without the need to buy a ticket and you can -play as often as you like. One notable historic person has even offered -some prize money.
- -The program illustrates the bloat caused by adherence to too many rules, -each of which may sound sane in isolation, but in their entirety lead to -an obfuscated, hard to read and understand monster.
- -The program tests whether a given natural number satisfies the -Collatz Conjecture:
- -Take any natural number n. If n is even, divide it by 2 to get n/2. -If n is odd, multiply it by 3 and add 1 to obtain 3n + 1. -Repeat the process indefinitely. -The conjecture is that no matter what number you start with, -you eventually reach 1.
- -Paul Erdős said about the Collatz conjecture: -“Mathematics may not be ready for such problems.” -He also offered $500 for its solution.
- -For example, the sequence of numbers for n = 6 is
- -- -6, 3, 10, 5, 16, 8, 4, 2, 1.
Continuing past one leads to the cycle 1, 4, 2, 1, 4, 2, 1, … -Interesting factoid: if you allow negative start values, there are -a few more cycles, each of different length:
- -- -−1, −2, −1
- -−5, −14, −7, −20, −10, −5
- -−17, −50, −25, −74, −37, −110, −55, −164, −82, −41, −122, −61, −182, −91, −272, −136, −68, −34, −17
The program computes the sequence for a given positive natural number -and stops at 1. The number n is specified in hexadecimal (without 0x -prefix) as the first argument. The program prints the given number in -zero-padded hex and each iteration along with a line count in decimal. -The example above looks like this (compiled with 64 bit word size):
- -$ ./prog 6
-0000000000000006
-0000000000000003 1
-000000000000000A 2
-0000000000000005 3
-0000000000000010 4
-0000000000000008 5
-0000000000000004 6
-0000000000000002 7
-0000000000000001 8
-
-
-The size of n is only limited by the argument size limit of your -shell/OS (the program implements arbitrary size bignums). -To query this on your POSIX system, run
- -$ getconf ARG_MAX
-262144
-
-
-which reports the limit in bytes, here 256KB. This allows to test -whether a Googol, which is -10100, satisfies the conjecture. But what is a googol in hex? -Fear not, -bc(1) -to the rescue:
- -$ printf 'obase=16;10^100\n' | bc
-1249AD2594C37CEB0B2784C4CE0BF38ACE408E211A7CAAB24308A82E8F1000000000\
-0000000000000000
-$ ./prog 1249AD2594C37CEB0B2784C4CE0BF38ACE408E211A7CAAB24308A82E8F10000000000000000000000000 \
-| less
-[...]
-
-
-Observe how the first 100 iterations melt the zeros to the right. Can you explain -why?
- -For a given n the program behavior is one of the following 3:
- -laugh (more likely) or throw up (less likely) and
-stops. You might have found
-a number for which the sequence diverges. If confirmed, this disproves the
-conjecture.I gave myself the following objectives. Like in real world programming, -not all of them can be met 100%. Think of them as a multidimensional -continuum, where trade-offs have to be made.
- -In the following I address all the tests as specified by your honors in the -guidelines.
- -#include lines#define and #include linesUsing one letter identifiers is quite old. I decided to use TLI (three -letter identifiers). Not the random kind, rather with a connection to -the meaning of life, the universe and the rest. Enter amino acids! Among -the myriad of possible amino acids there are 23 from which proteins are -built. In biochemistry, each is assigned a TLI (see Proteinogenic amino -acid):
- -ala Alanine
-cys Cysteine
-asp Aspartic acid
-glu Glutamic acid
-phe Phenylalanine
-gly Glycine
-his Histidine
-ile Isoleucine
-lys Lysine
-leu Leucine
-met Methionine
-asn Asparagine
-pyl Pyrrolysine
-pro Proline
-gln Glutamine
-arg Arginine
-ser Serine
-thr Threonine
-sec Selenocysteine
-val Valine
-trp Tryptophan
-tyr Tyrosine
-asx Asparagine or Aspartic acid
-glx Glutamic acid or Glutamine
-xle Leucine or Isoleucine
-unk Unknown
-
-
-My own research results complete this list (not yet in Wikipedia due to -the rule “No original -research”):
- -and Androgynine
-xor Xenoricine
-not Notanamine
-tla Triletramine
-
-
-Interestingly, the TLI are the perfect mnemonics for C language source.
-For example, met is “Main’s Exit Type” (int), ala is “A Large
-Algebraic” (bignum), ile an “Incremented Local Entity” (index
-counter), gly means “Grow Larger memorY”, gln is “Grown Larger Now”
-(after realloc), not is a “Not Overflowing Type” (recursive!), unk
-is the “UNit (Known as 1)”, trp is the “Tabula Rasa Product” (zero),
-phe is “Print HEx” and so on.
Huh??!
- -Wow, an identity operation (except for the <stdint.h> and EOF + __STDC__
-trivialities). Did you gain any insight through this?
#define? Which #define directives? How many 4K source files do you
-see that neither use a single #define directive nor abuse the build
-file? Even though the “no #define” rule I submitted myself to made it
-hard, I could use __LINE__ and stdio macros EOF, L_tmpnam,
-BUFSIZ, FILENAME_MAX, TMP_MAX to obfuscate at least something.
Another identity operation. I’ve done it for you already. Use this
-.indent.pro with FreeBSD indent:
$ cat .indent.pro
--bad /* blank line after decls */
--bap /* blank line after functions */
--br /* braces on if line */
--i8 /* indent */
--l999 /* line length */
--npcs /* no space after function call names */
--npsl /* don't break procedure type */
--ut /* use tabs */
--ce /* cuddle else */
--nip /* no parameter indentation */
--di1 /* declaration indent */
--Tand
--Tmet
--Tthr
--Tpro
--Tser
--Tala
-
-
-It looks like a perfect program should:
- -#includes of unsuspicious standard headerstypedefsstatic for internal linkage even! This must be a first in IOCCC history.main lastmainThe program contains not a single magic number (only 0 and powers of
-2, each power from 1 to 512) which are obvious to competent software
-engineers). How many programs have that property? The check for
-__STDC_VERSION__ was a bit tough to arrive at, since 199901L has too
-many bits set. But I realized that I only needed a number larger than
-199409 and less than 199901. 199680 has only 4 bits set and writing it
-as (256 + 128 + 4 + 2) * 512 minimizes the character count. That’s what
-judges get when they don’t like programs that are longer than they need
-to be.
Spoilers ahead. Duh!
- -Pseudocode, with comments matching those in the C source:
- -/* run */
-if (non-NULL and nonempty argv[1]) {
- n = convert(argv[1])
- print n /* 2hx */
- while (n != 1) { /* one */
- if (n is odd) { /* odd */
- m = deep copy of n /* cpy */
- n <<= 1 /* shl */
- n += m /* add */
- increment n /* inc */
- } else { /* eve */
- n >>= 1 /* shr */
- }
- print n /* 2hx */
- }
-}
-
-
-Bignums are represented as the two member structs
- -typedef struct {
- size_t places; /* number of places in base 2<sup>8*sizeof(type)</sup> */
- type *number; /* dynamically allocated memory for number */
-} bignum
-
-
-Here’s where the program shines brighter than a gamma-ray -burst!
- -I challenge you to throw all kinds of compilers, lints, checkers and -analyzers at my program and make it find the slightest of issues.
- -Is clang -Wall -Wextra -Weverything -Dtyp=uint32_t prog.c all you can
-do? Clang has implemented a new warning? Bring it on!
May you win the jackpot!
- -For least surprising results, the execution character set should be
-ASCII. The program computes four bits from every character in argv[1] and
-interprets them as a hex digit. On ASCII the characters a-f, A-F and 0-9
-are converted as expected.
This means however, that the program accepts any string, turns it -into a starting number (which is output as the first line), and starts -crunching. Nothing stops you from executing
- -$ ./prog "$(cat prog.c)" # Kind of quine?
-$ ./prog "$(cat rules guidelines)" # A jackpot? Maybe next year...
-$ ./prog "$(cat /bin/ls)" # Number cut short at first NUL byte.
-
-
-In a certain way, the program is character set and encoding agnostic.
- -EOF macro from <stdio.h> must expand to negative one since it is used
-to decrement a pointer and do some other math.
-None of the tools catches this one. The program self-protects against unusual
-systems with #if EOF + __STDC__ followed by #error goofy!. In the rare event
-your system is goofy, replace all EOF tokens with (-1) and remove the
-#error directive.While the program works best when bytes/characters are octets and the
-number of bits in a type is sizeof(typ) << 3, it will work correctly
-on 24bit or 36bit systems with 9 bits/byte, or systems where
-sizeof(typ) is 1 even for int and so on. On such systems, it will only
-use 8 * sizeof(typ) bits per place. It does not work when CHAR_BIT <= 7.
The open source static checker cppcheck -checks various problems with respect to style, performance, portability -and general fishiness. To enable all checks, run
- -$ cppcheck --enable=all --force -I/usr/include -Dtyp=uint32_t prog.c
-
-
-No issues found.
- -The open source static checker flawfinder
-checks various problems with respect to security like buffer overflows,
-function arguments to known troublemaker functions and more. It doesn’t need to
-pre-process code, so can be run without the typ macro being defined:
$ flawfinder prog.c
-Flawfinder version 1.31, (C) 2001-2014 David A. Wheeler.
-Number of rules (primarily dangerous function names) in C/C++ ruleset: 169
-Examining prog.c
-FINAL RESULTS:
-ANALYSIS SUMMARY:
-No hits found.
-$
-
-
-The open source dynamic checker valgrind -runs an executable and verifies all memory accesses and (de)allocations for -proper bounds and memory leaks. -Since the program frees all memory in all possible execution paths, even when -it must bail out, -valgrind should be happy. An early version of my program however reported this:
- -$ valgrind --leak-check=full --show-leak-kinds=all ./prog 6
-[...]
-==14615== HEAP SUMMARY:
-==14615== in use at exit: 4,096 bytes in 1 blocks
-==14615== total heap usage: 4 allocs, 3 frees, 4,108 bytes allocated
-==14615==
-==14615== 4,096 bytes in 1 blocks are still reachable in loss record 1 of 1
-==14615== at 0x4C236C0: malloc (in /usr/local/lib/valgrind/vgpreload_memcheck-amd64-freebsd.so)
-==14615== by 0x4F62175: ??? (in /lib/libc.so.7)
-==14615== by 0x4F62073: ??? (in /lib/libc.so.7)
-==14615== by 0x4F514EE: ??? (in /lib/libc.so.7)
-==14615== by 0x4F51265: vfprintf_l (in /lib/libc.so.7)
-==14615== by 0x4F3E001: printf (in /lib/libc.so.7)
-==14615== by 0x40101E: phe (in ./prog)
-==14615== by 0x400A9F: main (in ./prog)
-==14615==
-==14615== LEAK SUMMARY:
-==14615== definitely lost: 0 bytes in 0 blocks
-==14615== indirectly lost: 0 bytes in 0 blocks
-==14615== possibly lost: 0 bytes in 0 blocks
-==14615== still reachable: 4,096 bytes in 1 blocks
-==14615== suppressed: 0 bytes in 0 blocks
-==14615==
-==14615== For counts of detected and suppressed errors, rerun with: -v
-==14615== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
-
-
-From which I concluded that printf allocated a single 4K block for
-which no matching free existed. But how to free memory allocated deep
-down in the guts of the Standard I/O library? After some serious head
-scratching it hit me. The only chance I have is telling the system I no
-longer want to do I/O, maybe then it would free that buffer. A reading
-of C99 7.19.5.1, “The fclose function”, was encouraging:
- -Whether or not the call succeeds, the stream is disassociated from the file - and any buffer set by the
setbuforsetvbuffunction is disassociated from the stream - (and deallocated if it was automatically allocated).
So I fclose(stdout) before returning and now:
$ valgrind --leak-check=full --show-leak-kinds=all ./prog 6
-==14571== Memcheck, a memory error detector
-==14571== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
-==14571== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
-==14571== Command: ./prog 6
-==14571==
-0000000000000006
-0000000000000003 1
-000000000000000A 2
-0000000000000005 3
-0000000000000010 4
-0000000000000008 5
-0000000000000004 6
-0000000000000002 7
-0000000000000001 8
-==14571==
-==14571== HEAP SUMMARY:
-==14571== in use at exit: 0 bytes in 0 blocks
-==14571== total heap usage: 4 allocs, 4 frees, 4,120 bytes allocated
-==14571==
-==14571== All heap blocks were freed -- no leaks are possible
-==14571==
-==14571== For counts of detected and suppressed errors, rerun with: -v
-==14571== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
-
-
-A squeaky clean valgrind result!
- -FlexeLint is a commercial lint tool by Gimpel -Software. It supports nearly a -thousand checks, broadly categorized into 4 levels,
- -There is an on-line
-demonstrator you can
-use for checking your C programs and I highly recommend trying it. For a start,
-paste the well know first program in the form and press “Analyze Code”. Note
-the FlexeLint configuration options in comments (no space between /* and lint).
/*lint -w4 turn on everything */
-/*lint +esym(534,*) no demonstrator defaults */
-/*lint -e966 indirectly included header file not used */
-/*lint -esym(9058,_*) tag not used outside typedef */
-/*lint -misra(2) */
-
-#include <stdio.h>
-int main(void)
-{
- printf("hello, world\n");
- return 0;
-}
-
-
-Possible checks include those for MISRA 2004 compliance verification.
-The Motor Industry Software Reliability
-Association
-has produced a list of 121 required and 20 advisory
-rules for C
-programming. I am proud to report that my program fulfills almost all
-rules. To assess the few exceptions, one has to understand that MISRA
-rules are geared towards embedded systems used in the automotive
-industry. That’s why features like malloc and printf are right out.
-But that’s too restrictive for an IOCCC hosted application, so I ignored
-these:
I started out with enabling all messages using FlexeLint’s -w4
-option and disabling all noise from system headers. Then I dealt with
-the remaining messages by addressing them or suppressing them in such a way
-that the set of suppressions was minimal. At the end of the day, this is
-what remained:
// === Tested with FlexeLint 9.00L on FreeBSD 11 ===
-// Compiler:
-// "4.2.1 Compatible FreeBSD Clang 3.6.1 (tags/RELEASE_361/final 237755)"
-
--w4 // Enable maximum pickiness
--passes(6) // Recommended in FlexeLint manual for torture testing
-+fsc // Make string literals have type const char*
-+fnr // ptr-returning functions may return NULL
--strong(AJX,and,pro,ser,ala) // strong types
--strong(AcJcm,thr) // thr is strong, but most arithmetic is okay
--strong(AarJemorX,met) // met is strong, but some use is okay
-+libclass(angle) // All <headers> are system headers
--wlib(1) // Only errors for system headers
--i/usr/include // System headers
--i/usr/local/lib/supp/ansi // Comes with FlexeLint
--d__GNUC__=4 // Pretend...
--d__GNUC_MINOR__=2 // I'm...
--d__GNUC_PATCHLEVEL__=1 // someone else.
--d__builtin_va_list=char* // Fake this compiler extension
--d__inline= // Delete this compiler extension
--d__attribute__(x)= // Delete this compiler extension
-+e900 // Announce number of messages produced
-
-// MISRA 2004 checking
-
-/usr/local/lib/supp/lnt/au-misra2.lnt // Enable all MISRA checking
--elib(960) // Don't check FreeBSD system headers for required rules
--elib(961) // Don't check FreeBSD system headers for advisory rules
--e829 // stdio.h used
--e522 // MISRA 14.2 Highest operation, lacks side-effects
--esym(960,17.4) // pointer arithmetic other than array indexing used
--e971 // char without signed/unsigned
--e974 // stack usage report
-// Use verboten functions, Req. Rules 20.4 malloc() et al., 20.11, exit()
--esym(586,malloc,realloc,calloc,free,exit)
-
--e911 // implicit promotion of smaller than int to int
--e921 // cast from integral to integral
--e925 // cast from pointer to pointer
--e958 // padding required in struct
-
-+e9??? // Enable all 9xxx informational messages, except:
--e9079 // conversion from pointer to void to pointer to other type
--e9087 // cast performed between a pointer to object type and a
- // pointer to a different object type
--e9141 // global declaration of symbol
-
-// Messages due to code in FreeBSD headers.
-//
--dlint // The "lint" macro is tested in x86/_types.h
--elib(537) // Repeated include file
--e793 // external identifiers > 6 chars
--e935 // (unsigned) int within struct (actually the size_t)
--estring(960,_*) // Could be defined at block scope
--e964 // Header file not directly used
--e966 // Indirectly included header file not used
--elib(970) // int outside typedef
--esym(9003,_*) // could be defined at block scope
--elib(9047) // FILE pointer dereferenced
--esym(9058,__*) // tag not used outside typedef
--e9092 // NULL does not expand to a pointer (but plain 0)
-
-
-Which of the rules cause which obfuscation?
- -MISRA 6.1, “The plain char type shall be used only for the storage and
-use of character values.” This forbids using character constants in
-expressions other than assignments to char objects. A consequence is
-that printing digits with '0' + digit is not allowed (even though
-'0' is technically an int!) so I am forced to output hex digits with
printf("%c", (met)tyr + 32 + 16 + ((8 + EOF) * ((met)tyr / (8 + 2))));
-
-
-because of the “no magic numbers other than powers of two” rule. How is this
-an improvement over printf("%c", '0' + tyr + 7 * (tyr / 10), MISRA?
MISRA 6.3 “typedefs that indicate size and signedness should be used in
-place of the basic types.” Well, if you can’t infer the size and
-signedness from typedef int met, you’re not a real C programmer.
MISRA 10.5, “If the bitwise operators ~ and << are applied to an
-operand of underlying type unsigned char or unsigned short, the
-result shall be immediately cast to the underlying type of the operand.”
-Because the program must work for any unsigned type chosen for the typ
-macro, including the narrow types enumerated in the rule, a lot of
-redundant casting ensues. It gets worse with the next rule…
MISRA 12.1, “Limited dependence should be placed on the C operator -precedence rules in expressions.” This requires parentheses for almost -all expressions involving more than one operator, especially those for which -a cast is required, leading to hard to understand expressions such as
- -const ser glx = (ser)((asx > (ser)64u) ? (ser)((ser)asx + (ser)8u + (ser)1u) : (ser)asx);
-not.not[leu] = (and)((and)not.not[leu] | (and)(((and)glx % (and)16u) << (and)lys));
-
-
-MISRA 14.7, “A function shall have a single point of exit at the end of
-the function.” Sigh. Since I must use eloquent prototypes (8.1, 16.3,
-16.4) and static functions (8.10, 8.11), I can only use a few functions.
-Everything usually written with an early return now cause another
-useless indent level. The first three if statements in main cause a
-silly 24 character indent. The maximum indent is forced to 8, which is way
-too high for a sane function.
MISRA 16.10, “If a function returns error information, then that error
-information shall be tested.” A cast to void would draw a lint warning, so
-I use the printf result in expressions,
lys -= 4 * printf("%c", (met)tyr + 32 + 16 + ((8 + EOF) * ((met)tyr / (8 + 2))));
-val += printf("\n") / ((__LINE__ * L_tmpnam) + TMP_MAX);
-val -= (printf(" %d\n", val) > BUFSIZ) ? FILENAME_MAX : EOF;
-
-
-which are, in the absence of errors, equivalent to
- -lys -= 4;
-/*nop*/
-++val;
-
-
-MISRA 13.1, “Assignment operators shall not be used in expressions that
-yield a Boolean value.” Forbids the idiomatic if ((p = malloc(n)) ==
-NULL) and requires separate statements, in other words, bloat.
MISRA 16.7, “A pointer parameter in a function prototype should be -declared as pointer to const if the pointer is not used to modify the -addressed object.” in conjunction with lint’s “Note 952: Parameter could -be declared const” causes const-poisoning for all functions,
- -static void phe(const ala not);
-static void gly(ala *const not, const and his);
-met main(met val, const pro *const his[]);
-
-
-and quite a number of automatic variables.
- -The guidelines state “We like programs that: make us laugh and/or throw -up :-) (humor really helps!)”
- -If your compiler supports a 128 bit wide type (e.g. clang, gcc) then
-you can use it via the typ macro:
clang -Dtyp=__uint128_t -o prog prog.c
-
-
-Indeed, the program can use (and lints clean for) all of
- -clang -Dtyp=uint8_t -o prog8 prog.c
-clang -Dtyp=uint16_t -o prog16 prog.c
-clang -Dtyp=uint32_t -o prog32 prog.c
-clang -Dtyp=uint64_t -o prog64 prog.c
-clang -std=c89 -Dtyp="unsigned long" -o prog89 prog.c
-
-
-This works because the program has no need for corresponding SCN or
-PRI macros to do the scanning and printing of variables of these
-types. With a 128 bit type the program can represent numbers up to
-340282366920938463463374607431768211457 (3.4 * 1039) as a
-single “place”, enough to explore yet untested numbers for the rest of
-your life.
The number of hex digits in the start number is limited by ARG_MAX,
-probably minus some overhead for the environment variables (use
-env(1)
-to trim your environment). In bits this leaves you with 24 *
-ARG_MAX.
The algorithm requires two bignums in memory for addition. -If you hit a divergent number, this will cause out-of-memory (“laugh”) -somewhere near 216,000,000,000 (4GB/2 * 8bits/byte). -Sadly, I don’t have a test case :-)
- -How long would it take to overflow the Not Overflowing Type? Lets -assume we’re processing 2GB numbers. The program copies, shifts by one, -adds and increments 2GB long bit strings, each time completely thrashing -the data cache – at all levels. We have a fast machine that can do an -iteration in one second, on average. To make things easy, we round up -3n + 1 to 4n, and assume we never need to divide by two (which is -quite optimistic). Then each iteration shifts left by 2. This would take -8 billion seconds, or about 250 years. If you want to get famous, you -better remove some of the RAM, use an ancient box, or reduce available -memory resources with the ulimit(1) built-in of your shell.
- -For all intents and purposes, the Not Overflowing Type keeps the promise!
- -![]() |
-© Copyright 1984-2016,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Don Yang
-http://uguu.org/
make
-echo Some text | ./prog
-
-
-echo IOCCC 2015 | ./prog | tee output.c
-make output
-./output
-
-echo IOCCC 2015 | ./prog_c11 | tee output.c
-make output
-./output
-
-echo IOCCC 2015 | ./prog_c++98 | tee output.c
-make output
-./output
-
-
-Before analysing the code in detail we were able to guess two out of four tests -this entry uses to tell the 5 languages/flavors apart. Can you find all four?
- -The way the text is encoded in the output doesn’t cease to amaze. Can you tell -why an array of 512 elements is needed?
- -Fuuko is a sea star generator. Feed her some input through stdin to -get lots of sea star patterns in stdout.
- -gcc -O3 -std=c90 fuuko.c -lm -o fuuko_c90
-echo IOCCC | ./fuuko_c90 > output_c90.c
-
-
-If you compile with a C99 compiler instead of C90, the sea stars will -have eyes.
- -gcc -O3 -std=c99 fuuko.c -lm -o fuuko_c99
-echo IOCCC | ./fuuko_c99 > output_c99.c
-
-
-Don’t like sea stars? Use a C++98 compiler to get dango instead.
- -g++ -O3 -std=c++98 fuuko.c -lm -o fuuko_cpp98
-echo IOCCC | ./fuuko_cpp98 > output_cpp98.c
-
-
-Don’t like dango either? Use a C++11 compiler to get just circles (or -swiss cheese, if you prefer that).
- -g++ -O3 -std=c++11 fuuko.c -lm -o fuuko_cpp11
-echo IOCCC | ./fuuko_cpp11 > output_cpp11.c
-
-
-Don’t like any of these patterns? Use a C11 compiler and there will be -no extra patterns.
- -gcc -O3 -std=c11 fuuko.c -lm -o fuuko_c11
-echo IOCCC | ./fuuko_c11 > output_c11.c
-
-
-Regardless of which of these C/C++ dialects you choose, the output -will all be valid C90 code that reproduces original input on stdout, -filled with pointer dereferences (C stars).
- -Next time people ask you for a few pointers on C, you can run their -question through Fuuko and give them pointers all day long.
- -Fuuko has been tested under these environments:
- -The most obscure parts are in detecting the subtle differences in -different dialects. The standard committees put a lot of effort into -avoiding “quiet changes”, but Fuuko is still able exploit a few of -those. It should be an interesting exercise for the reader to figure -how she did it.
- -Output patterns are usually random (except for C11). The built-in -random number generator is seeded using ASLR. On systems where ASLR -is not so random (such as cygwin), you can introduce randomness by -changing number of command line arguments to Fuuko.
- -Output is somewhat robust: corruption on most of the lines will -usually result in a compiler warning. This is because the output is -vastly redundant: For ~1K of input, expect output to be on the order -of ~1MB, and take ~500MB of RAM to compile.
- -CRC32 of source code is embedded in the source code itself.
- -Process of writing this program is included in spoiler.html
- -Code layout is inspired by Ibuki Fuuko, for her love of sea stars.
- -![]() |
-© Copyright 1984-2016,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Anton Älgmyr
-Twitter: @aalgmyr
make
-
-cat prog.c | ./prog # Printing garbage might break your font
-./prog <file1> <file2> > out.raw
-./prog -d 2 0 out.raw # Decode the first (0th) channel out of two
-
-
-./prog -h | ./prog -d 1 0
-
-# Who needs cat?
-./prog prog.c | ./prog -d 1 0
-
-# Assuming ALSA
-echo '<<<<<< /\_/\_/\ _-_-_-_ !!!!! :.:.:.: >>>>>> ****** ~~~~~~~' |
- ./prog | aplay -c1 -fFLOAT_LE -r44100
-
-# Assuming sox
-echo -n ' MENE MENE TEKEL UPHARSIN ' | ./prog |
- sox -t raw -c 1 -r 44100 -L -e floating-point -b 32 - -n spectrogram -d 10 -X 300
-
-
-Be warned, this is not your garden variety text-to-speech program! Earplugs are advised, -or at least a handy and well-tested volume knob.
- -Pixels are numbered, amplitudes are weighed, frequencies are divided, -and the message can be displayed in fiery letters, but don’t be alarmed.
- -How does decoding of the waveform work? Can you encode an arbitrary text in a sound sample?
- -To put it brief, this entry is akin to a sound based cat. It takes characters as input and outputs them into frequency space as audio. The entry also supports decoding the produced waveforms using the -d flag. Usage instructions is output if run with the -h flag, albeit not in an immediately legible format.
In normal operation, the entry reads characters from one or more sources. If the -h flag is given, usage instructions is used as a source. Else if file paths are present as arguments those will be used. Else stdin is used.
If a character is part of the supported subset of ASCII {10, 32-126} then that character is output into frequency space of an audio signal (44.1 kHz single precision float, endianness should depend on system endianness) through stdout. Any other character will be interpreted and outputted as a space.
Characters are printed using a (slightly modified) pixel font based on gohufont. Pixels are drawn using crosses in frequency space, achieved by simultaneous up and down chirps.
- -Each input source is designated its own channel in the output (one float per channel per time step in the output) so if you have a surround sound system you could listen to a cacophony of chirpy characters.
- -Interestingly, with training you might actually be able to tell characters just from hearing. But even without training you can easily read along with the printed characters and have the sound make sense with the look of the characters.
- -See image spoiler.png for an example spectrogram.
- -There is no error checking done when opening files, so expect segfaults if you provide the wrong path to a file.
- -This program is bound to misbehave if int is less than 32 bits.
- -Flags will only be interpreted correctly if they are the first argument. Reading a file named -d or -h is fully possible if it is not the first file provided, even though I am not sure why you would want to do that.
Providing invalid/unexpected arguments to the decode flag will result in odd behavior. Some erroneous arguments cause segfaults (negative number of channels, channel id outside valid range). One argument in particular causes an infinite loop printing whitespace.
- -A lot of the obfuscations done came naturally from trying to appease the size tool. To name some:
- -ifs#defines, sadlyOn the intersection of size and obfuscation is the data encoding, which was quite fun to design.
- -Some additional obfuscation was done to mathematical formulas. Somewhat known expressions was transformed into equivalent but less recognizable counterparts.
- -I have tried to avoid intentional red herrings in the code, although fishy statements are plentiful.
- -The large string in the beginning of the source file contains font data, encoded in base64 using characters in the range ' ' to '_'. The space was chosen as the zero because the data contains a lot of zeroes, and quite helpfully the size tool ignores whitespace even in strings. Without this fact the program would have been too large and the decoding feature would have had to go. Fortunately this hole in the size spec was readily available. :)
Characters in the font (5x8 pixels, 40 bits) is packed into 7 base64 digits (which was a pain to decode in minimal code).
- -Note that even though floats are used for the waveforms, the standard math library is not used at all! Most arithmetic is done purely on integers. The only major exception is generating a table of sine values which are interpolated to give high resolution waveforms. Can you see when the generation is triggered, and how it is done?
- -A critical issue encountered was that having abrupt starts and ends of signals cause a lot of problems with spectral leakage which makes spectrograms hard to read and audio painful to listen to. To reduce spectral leakage a windowing function was used. Although the one used is quite well known, it is not in a form that should be familiar to anyone. What looks like a polynomial and quacks like a polynomial might not actually be a polynomial, at least not deep inside.
- -The program was written to deal exclusively with file descriptors, so how would one go about printing a char array not from a file descriptor without adding additional logic? Answer: ungetc into stdin, one char at a time (to be standards compliant). This is used to print the usage instructions.
Compiling using
- -gcc -Wall -Wextra -pedantic
-
-
-gives only -Wmisleading-indentation which is sensible considering the source code. While
clang -Wall -Wextra -pedantic
-
-
-is a bit more pessimistic and gives -Wempty-body (I like loops without bodies), -Wstring-plus-int (since apparently some people think string+int is a concatenation) and one of the weirder warnings I have seen from me splitting a negative constant with whitespace. Compiling using
clang -Wall -Wextra -pedantic -Weverything
-
-
-produces a few pagefuls of warnings and makes me feel generally bad about myself. :(
- -The reported size of the source code using the size tool is very intentionally 2018.
- -![]() |
-© Copyright 1984-2018,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Derek Anderson
- -make
-./prog < textfile
-
-
-./prog < prog.c
-./prog < prog.orig.c
-./prog < hint.text
-
-
-With this entry, you won’t need to turn your monitor upside down!
- -Compare prog.c and prog.orig.c and find out why we had to modify the entry, and what confused the author
-(see the author’s remarks). No, it was not the shape of the Roman V that we, or the compiler, didn’t like.
gcc -Wall -Wextra -Wpedantic -O3 -std=c11 prog.c -o prog
-
-
-Also works with a standard of c99, but c90/c89 will not compile due to -for loop initial declarations, along with additional warnings about -variable length arrays and lack of a return statement.
- -This small program, when given text on stdin, will produce a pattern of -squiggly lines. This pattern is deterministic, and it shouldn’t be too -difficult to determine from whence they come. There is even a comment -that describes the highlighted phenomena in the source, for those that -require a small nudge. With denser text blocks, such as an essay or -similar prose, the output can be rather pretty, in an chaotic emergence -sort of way. Try using this file, or the source file as inputs.
- -In its current form, this program can handle lines of length 255; to
-adjust this limit, change the variable a at the top of the source.
-Other adjustments, such as the exact printed characters, are rather
-easy, once sufficient reverse engineering has occurred. Improvements
-such as proper handling of tabs are left as an exercise to the reader.
In developing this program, the author found a potentially interesting
-bug. If the expression (j=k,j) (near the middle of the source) is
-changed to (j=k,k), the program produces different output. The author
-used compiler gcc 5.4.0, compiled for x86_64-linux-gnu. Enabling or
-disabling optimization produces the same results. The author is not
-sure who is the culprit, but instead shrugged and moved on with life.
-Of course, YMMV with your own environment.
The structure of this program, as you may have deduced, is two for
-loops, one nested in the other. There is also a bunch of direct
-variable assignment, such as j=k. There is some filler fluff, such as
-0-0+0, but all that sort should be rather easy to spot. It was mostly
-added for the purpose of making certain things line up right, and only
-secondarily to obfuscate.
![]() |
-© Copyright 1984-2018,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Fabrice Bellard
-https://bellard.org/
make
-./prog > lena.ppm
-
-
-eog lena.ppm # On Linux
-preview lena.ppm # On MacOS
-
-wget http://upload.wikimedia.org/wikipedia/en/2/24/Lenna.png
-pngtopnm < Lenna.png | pnmscale 0.25 | cjpeg -arithmetic -dct float -quality 14 > small.jpg
-
-
-The file small.jpg will be approximately of the same size as the raw image data
-in the program. Compare the level of the detail and the artifacts of
-small.jpg and lena.ppm.
Compressing images is just a matter of simple arithmetic and some magic, isn’t it?
- -We could understand some of the arithmetic but none of the magic.
- -Deciphering the mechanism used for data encoding to make use -of the whitespaces, braces and semicolons should be a slightly easier task.
- -This program outputs a 128x128 RGB image file to the standard output -using the portable pixmap file format (PPM). It contains the famous -“Lena” image which is used in many image compression tests.
- -The uncompressed image is 12 times larger than the source code of the -program which includes the image data and the complete decoder. The -actual image data is 1220 byte long, which gives a compression ratio -of 40. Using a JPEG-like algorithm would not be enough to reach this -level of compression (the Lena image would be barely recognizable). So -the algorithm is based on the latest advances in image compression. It -includes the following features:
- -The image data is encoded to a C string with some tricks to make the -best use of the IOCCC size constraints. The identifiers were shortened -to a single letter to save space. No specific obfuscation was needed -as the algorithms already have a significant complexity.
- -Although the program was optimized to decompress its built-in image, -it accepts to decompress image files from its standard -input. Examples:
- -./prog d < lena512.bin > lena512.ppm
-./prog d < fruits.bin > fruits.ppm
-./prog d < vintage_cars.bin > vintage_cars.ppm
-
-
-The original images for fruits and vintage cars come from -Wikipedia and were resized to a width of 1024 pixels. Warning: the -program is not protected against invalid input.
- -The program should be portable on any Unix system. On Windows the line -“setmode(0, 32768); setmode(1, 32768);” must be added at the start of -the main() function to avoid unwanted carriage return characters in -the output.
- -![]() |
-© Copyright 1984-2018,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Dave Burton
-http://ioccc.snox.net
make
-./prog < any-file
-
-
-./prog < prog
-./prog < prog.c
-
-
-One line, one array, one loop and one statement but it prints many bytes. It won.
- -Feed this anything on stdin.
- -The included script may be used as a driver program for this entry. -It adds several nice-to-have features, and allows salt-to-taste customizability.
- -This code has been compiled and tested on:
- -This started life as a personal challenge: write the shortest hex dump utility in C.
- -The self-imposed ground rules in the hunt for shortest: -the code has to output correctly, -no extraneous newlines, the code must be portable, -and without bypassing the solution using execve(2), -or functions built upon it (system(3), popen(3), etc). E.g:
- -main(){system("hd");} // it's turtles all the way down!
-
-
-is not acceptable. -And, “output correctly” is the output format of this entry. QED.
- -Early attempts ended up at a reasonably short 157 characters. -This was too long for a one-liner, so it had to be formatted as something more interesting. -This solution is pleasing, but a true one-liner was the hoped-for goal. -Here is the 157 character version in it’s entirety:
- -char O,o[ 20];L(O){
-putchar ( O+ 48+39 *(9<
-O));} I(O) {L(~ 15);
-O|| puts(o);} main (l){
-for(;~(l=getchar()) ;I(O
-&=15 ))o[ O++ ]=4<
-(4^l >>5) ?l: 46,L
-(l>> 4),L (l&15);O&&
-I(o[ O]=0 );}//157c
-
-
-While thinking about this in the shower (you are not the only one that does this!) -came the idea which reduced the code to just 119 chars. -This dramatic reduction started to feel close to minimal, and the hunt resumed. -The progression to the present size is interesting, -and it is interesting that the same algorithm can be expressed so differently -by slight rearrangement of its parts.
- -// 119
-char O,o[20];main(l){for(;~(l=getchar());O||puts(o))o[O++]=isprint(l)?l:46,O&=15,printf("%02x ",l);O[o]=0;O&&puts(o);}
-// 116
-char O,o[20];main(l){for(;O++[o]=~(l=getchar())?4<(4^l>>5)?l:46:0;(O&=15)||puts(o))printf("%02x ",l);O>1&&puts(o);}
-// 115
-char O,o[20];main(l){for(;O[o]=~(l=getchar())?4<(4^l>>5)?l:46:0;(O=-~O&15)||puts(o))printf("%02x ",l);O&&puts(o);}
-// 113
-char O,o[20];main(l){for(;~l;(O=~l?printf("%02x ",l),-~O&15:!O)||puts(o))O[o]=~(l=getchar())?4<(4^l>>5)?l:46:0;}
-// 112
-char O,o[20];main(l){for(;~l;(O=~l?-~O&printf("%02x ",l)*5:!O)||puts(o))O[o]=~(l=getchar())?4<(4^l>>5)?l:46:0;}
-// 111
-char O,o[20];main(l){for(;~l;O||puts(o))O=(O[o]=~(l=getchar())?4<(4^l>>5)?l:46:0)?-~O&printf("%02x ",l)*5:!O;}
-// 110
-char O,o[0];main(l){for(;~l;O||puts(o))O=(O[o]=~(l=getchar())?4<(4^l>>5)?l:46:0)?-~O&printf("%02x ",l)*5:!O;}
-// 109
-char O,o[];main(l){for(;~l;O||puts(o))O=(O[o]=~(l=getchar())?4<(4^l>>5)?l:46:0)?-~O&printf("%02x ",l)*5:!O;}
-
-
-There are solutions without the ASCII sidebar that are significantly shorter. -These do not compete in the same category, since their output is materially different. -They are derived from the solutions above, but are still fascinating as concise utilities, -so here is their progression, for the curious:
- -// 102
-I;O(O){putchar(O+48+39*(9<O));}main(l){for(;~(l=getchar());O(++I&15?~15:~37))O(l>>4),O(l&15);O(-38);}
-// 80
-O;main(l){while(~(l=getchar()))printf("%02x%c",l,++O&15?32:10);O&15&&puts("");}
-// 78
-O;main(l){for(;~l;(O=~(l=getchar())?printf("%02x ",l),-~O&15:!O)||puts(""));}
-// 77
-O;main(l){for(;~l;(O=~(l=getchar())?-~O&printf("%02x ",l)*5:!O)||puts(""));}
-// 76
-O;main(l){for(;~l;O||puts(&O))O=~(l=getchar())?-~O&printf("%02x ",l)*5:!O;}
-
-
-It is possible to reduce the size of each of these by one by eliding the trailing newline. -This was not reported above since the newline kept getting appended by processing software, -and it is more interesting to remove characters by changing code than by filtering:
- -$ tr -d '\012' < 109.c | wc -c
-108
-$ tr -d '\012' < 76.c | wc -c
-75
-$ tr -d '\012' < 109.c | cc -o 108 -xc -
-$ verify 108
-$
-
-
-An obfuscated hex dump has been done before: -1986/bright/bright.c is similar in function, -but it uses more characters in just setting up its obfuscation than this entire solution!
- -If you are unhappy with the way DEL (character 127) is handled,
-replace the cryptic expression 4<(4^l>>5)?l:46 with 32>l|l>126?46:l.
-Both take the same number of characters, but the former is a bit more interesting.
-Bonus question: how does the first expression work?
Technically, char o[0]; is illegal (SS 6.7.6.2) according to ISO (N1570).
-And char o[]; is a conditionally supported feature (SS 6.7.6.2, 6.10.8.3).
-However, it works in modern C implementations as an extension,
-including GCC, Clang and TCC, for X86 and ARM,
-on multiple operating systems (Linux, OSX, FreeBSD), so it is functionally correct.
-MicroSoft Visual C++ does not allow char o[] or char o[0],
-and implements its close relative char o[1]
-such that writing more than a single char will cause a fault, which is technically correct.
But how does this work at all, even as an extension?
-o[] allocates one(!) byte in a zero-filled data area (formerly BSS).
-The UNIX-derived systems this code was run upon all place the
-storage of O and o into a zero-filled VM page with nothing following:
-thus, there are plenty of available and unused zero bytes following O, addressed via o,
-and this code only needs 17.
-This is undefined behavior, but as shown, it is widely available.
The 1979 Seventh Edition UNIX (v7) system pre-dates the IOCCC by several years,
-and the source code to sh(1) was a significant inspiration for this contest.
-There are two C compilers present: cc written by Dennis Ritchie, and pcc written by Steven Johnson.
-The nested conditional expressions in 116 and smaller are too complex for cc (“Illegal conditional”)
-but pcc handles them correctly, and neither compiler accepts char o[] or char o[0] nor puts the bytes in
-a zero-filled page (as a paged VM was not yet written for UNIX).
More significant is that v7 printf(3) does not report the number of characters written,
-and therefore 111 compiles but does not work correctly;
-113 is the shortest code that compiles and runs correctly in Ancient UNIX.
- -Interesting digression: v7
- -printf(_doprnt) was written in PDP-11 assembler. -It pre-datesvarargs.h, and assembly was the only way to gain access to the variable argument types. -The first edition The C Programming Language, 1978, page 71, remarks:- -By the way, there is no entirely satisfactory way to write a portable function -that accepts a variable number of arguments, because there is no portable way -for the called function to determine how many arguments where actually passed to it in a given call. -… -
printf, the most common C function with a variable number of arguments, -… is also non-portable and must be modified for different environments.It is fascinating to explore the roots of C through the history of the operating system -it was birthed within. C is often criticized as a difficult, inscrutable language, -but as this contest demonstrates, this is in parody. -Shell-gol is one of those instances where someone preferred a different language, -and (ab)used the preprocessor to re-mold C into something they found comfortable. -Most of the rest of the system, especially in the kernel, -are models of clarity and efficient expression.
So which version is the shortest, portable hex dump?
- -Clearly, the smallest possible program violates modern best practice. -It is not even possible to compile cleanly, but it will compile correctly.
- -Included is prog.nowarn.c, a modern C implementation that is – perhaps – the smallest,
-clean-compiling version using clang or gcc with -Wall -pedantic.
-Note that while this is larger than all but the original attempt,
-it will not work with the original Ritchie PDP-11 C compiler,
-since the expression within the ternary remains too complex.
Try
- -cat prog.c prog.nowarn.c
-
-
-to compare the differences (diff is not helpful on a one-liner).
![]() |
-© Copyright 1984-2018,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Dave Burton
-http://ioccc.snox.net
make
-
-./prog [-tcksri] < file.c
-
-
-./prog -i < prog.c
-./prog -s < prog.c
-./prog -sk < prog.c
-
-
-If you get stuck, try:
- -make test
-
-
-If you get really stuck, try:
- -man ./tac.man
-
-
-They say size isn’t everything, and in the case of IOCCC iocccsize.c -that is saying something! What is this program weighing and how much does it weigh?
- -- - --tac computes C program size -(obfuscated / otherwise) -by splitting code as tokens small, -ignoring space, then counting all. - -It tries quite hard to act the same -as counting tool of I-OCCC fame. -Some bugs were fixed, it's faster too, -and does more things, just add some glue! - -It does far more than print the size: -the token part's a better prize! -With each upon on a single line, -how many things can you design? - -Included is a keyword sorter, -de-obfuscator, freq reporter. -With code produced as little parts, -just add your own creative arts. - -But first you have to figure out -the braces part, without a doubt! -And then the code - it isn't easy: -for as else? That's rather cheesy! - -The rest of it is standard fare: -expressions strange, the globals bare, -confusing symbols one and oh, -and precedence you have to know. - -The keyword list was made external, -because of standards change eternal. -Thus other languages can now, -be counted just like C, somehow! - -I hope you find this code obscure -enough to win, and thus procure -a public place for all to see -how badly I can butcher C! -
tac is the inverse of cat(1): it un-concatenates its input into C tokens,
-writing the token stream to stdout. There are options to suppress the token ids,
-summarize the token counts, and several options to allow it to be compatible
-with iocccsize.
The token-based output is quite useful in analyzing source code (see below),
-and the counter is more accurate than iocccsize (see below); but this can be
-fixed by using the -c compatibility flag, restoring the following problems as
-in the official tool:
{;}” is not counted within a double-quoted string// comments(!), but not /*, changing the countsThe following bugs are always corrected:
- -/*/ as a complete comment (/*/int if for/*/ has three keywords)//* or within a line comment /* to initiate a comment block until following */// comments -
-thus a solitary quote consumes everything until the next quote'"' starts a dquote in iocccsize)#ifndef is omitted as a keyword (but #ifdef is allowed?)tac correctly penetrates 23rd century cloaking technology. ;-)There is one (known) remaining problem with detection:
- -comments between preprocessor hash and keyword are not replaced with whitespace;
-the following counts #include as two tokens, # and include (not as a reserved word):
#/*this will not be counted*/include/*correctly*/<stdio.h>
-Fixing this properly hampers backwards compatibility in counting. This requires -eliding comments during readsource (ISO 5.1.1.2, phase 3), and yet still -counting words correctly absent -k.
- -tac was run over all 366 previous IOCCC winning entries:
find ~/src/obc -type f -name \*.c | wc
-
-
-The discrepancies found are documented and explained in the file “discrepancies”.
- -find ~/src/obc -type f -a -name "*.c" | xargs ./spotcheck ./prog | ./spotdiff |
- grep -v keep | diff -bw - discrep* | grep "[<>] cl "
-
-
-In summary, there are only 6 unique entries out of 366 that have any variation
-in Rule 2 counts; in all cases, the differences are due to bugs within
-iocccsize, described in detail in the file discrepancies. There are only 40
-files (40/366, ~11%, including originals and variations) that differ at all, 31
-only in word count; most word count differences appear related to comment block
-detection, weighted more towards recent entries (2011 and onward = 20/40 ~50%).
This (minor) variation in word count values has not been addressed since
-it is not a qualifying metric, nor is it very useful in a programming context:
-whitespace surrounds English words, not necessarily C tokens, as in a+=1;.
Accuracy (versus compatibility) is demonstrated through a series of small test cases -designed to allow exhaustive, hand-counted values for comparison with the tool values. -These test cases were vital in debugging and regression testing, and provided a way to -determine which tool was correct when there were differences.
- -- -A version of this tool in more clearly written C (tac.c) -is presented for the Judge’s consideration as a more accurate replacement for
iocccsize. -This obfuscated entry is derived from (and compatible with) that code, -but due to obfuscation, has had some significant, deep changes for the contest. -Nevertheless, the more clearly written code remains a spoiler for this entry.
NB: iocccsize gets a different answer from tac on its own (iocccsize.c) source code;
-tac gets the correct answer. This is due to the aforementioned bugs within iocccsize,
-proved by fixing iocccsize.c with the included patch, so iocccsize reports
-the correct answer for itself.
There is no limit on line length, file length, comment length, or identifier length.
- -tac features an accurate tokenizer; which presents each C token on a line by itself.
-This feature enables interesting analyses of C (and C++) code, hard to get any other way.
For instance, here is a simple token counter, useful in finding repeated long tokens, or operator -frequency, or counting the references to identifiers, constants, or breadth of use of the -language:
- -!/bin/sh
-cat $* | ./prog -t | sort | uniq -c | sort -k1nr
-
-
-And here is a C keyword frequency counter:
- -#!/bin/sh
-function iskeyword {
- awk 'BEGIN{f="c11";while(getline<f)k[$1]=0}
- {if($1 in k)k[$1]++}END{for(i in k)print k[i],i}'
-}
-cat $* | ./prog -t | iskeyword | sort -k1nr
-
-
-This script was used to “optimize” the reserved word order so the most frequent IOCCC -winning entry keywords are checked first.
- -- -An interesting aside: as might be expected, obfuscation has changed the frequency of -keyword distribution over time. The top five for the decades:
- -1980s 1990s 2000s 2010s - ----- ----- ----- ----- - 94 if 532 char 375 if 254 int - 69 for 524 if 372 char 217 for - 59 while 417 int 332 int 198 if - 48 char 223 for 184 for 121 return - 43 int 223 void 165 return 104 char -
The keyword list is external to the program, and is easily changed, sorted, checked, verified. -This allows such additional programs in concert with the tool’s primary operation.
- -A poor-man’s de-obfuscator can be based upon the output of tac -t and a handful of
-simple rules (and another use of the external keyword file).
-A more refined version of this is included in the file unob.sh,
-but the simple code below is a serviceable obfuscated C de-obfuscator in a scripting language.
-It really is this easy with tac:
#!/bin/sh
-script='
-BEGIN {
- last=nl="\n";
- f="c11"; while(getline <f > 0) kw[$0]++; close(f);
-}
-
-function iskw(a) { return a in kw }
-function indent(a) { return sprintf("%*s", n*3, " ") }
-function newline() { if (!infor && last != nl) printf last=nl; }
-function show(a) {
- if (last==nl) printf "%s", indent()
- printf "%s%s", space(), a
- last=a
-}
-function space() {
- return iskw(last) ||
- (last ~ /[A-Za-z0-9_+-\/%^[&\]\)=:<>;]$/ && $0 !~ /[:;()\[\],]/) ? " " : ""
-}
-
-/^\(/ { ++paren }
-/^\)/ { --paren }
-
-/^for/ { newline(); infor=1 }
-infor && /^;/ { ++infor; show($0 " "); next }
-infor==1 && /^:/ { ++infor }
-infor>1 && paren==0 { infor=0 }
-
-/^\?/ { tern++; n++; newline(); show($0 " "); next }
-tern && /^:/ { newline(); show($0); --tern; --n; next }
-
-/^#/ { newline(); show($0); newline(); next }
-/^;/ { show($0); newline(); next }
-/^{/ { show($0); ++n; newline(); next }
-/^}/ { n--; newline(); show($0); newline(); next }
-
-{ show($0) }
-'
-cat $* | sed 's/#include/##include/' | cpp -E -trigraphs |
-sed 's/^# .*$//' | sed 's/^#//' |
-./prog -t | awk "$script"
-
-
-I assume you noticed the braces?
- -Every brace is sacred,
-Every brace is great.
-If a brace is wasted,
-Clang gets quite irate.
Keywords follow the 2010s top five, without the if, for interesting flow control.
for can be an else - inconceivable!getopt. But “where’s the beef?”No character constants, several int constants, and one string -(hint: which does not encode letters) – how does this code parse code?
- -Interesting aside: how many is “several int constants”?
- -- -./prog < prog.c 2>/dev/null | awk '$1~/260/{a[$2]++}END{for(i in a)print i,a[i]}' - ... | wc -Which numbers are most often used?
- -... | sort -k2nr | sed 5q -
The code describes its function by careful arrangement of variables up front…
O,0,l,1 are used to confusing effect, local names obscure global names.The keyword list is externalized as an include file. This presents a useful
-feature for the source code: not only can the reserved word script above be
-produced, but the tool can be rebuilt with any set of reserved words, just by
-using a different list. For instance: removing all the secondary keywords;
-removing all the C11 keywords; trying just K&R C. Since C++ and Java share the
-same operators as C, just change the keyword list and tac will correctly
-tokenize both of these; the tokens >>> and :: can be handled with a short
-post-filter (tokenfix, included).
I believe this entry may also satisfy the request for gratuitous use of all the C11 keywords?
-Whether this context satisfies “intended C language context” is a matter of interpretation. ;-)
-And tac is ready for the IOCCC++ contest. And the IOJCC trashcan.
The following reserved word files are included:
- -kandr from my venerable 1978 18th printing "The C Programming Language"
-v7unix 7th edition Unix source code, extracted from c00.c
-kandr2 from my 1988 1st printing "The C Programming Language", 2e
-ansi ANS X3.159-1989
-c99 ISO/IEC 9899:1999(E)
-c11 ISO/IEC 9899:201x(E) N1570
-c++98 http://en.cppreference.com/w/cpp/keyword
-c++11 ISO/IEC 14882:2011(E) N3337 2012-01-16
-c++14 ISO/IEC 14882:2014(E) N4296 2014-11-09
-java8 http://docs.oracle.com/javase/specs/index.html
-ioccc.kw.freq c11 + additional words, sorted on frequency of occurrence in ioccc winners
-
-
-NB: The keyword file used in this code is derived from the list in iocccsize.c,
-which is neither complete (#define, #ifndef, #undef are missing
-– yes, Virginia knows about #define omitted on purpose),
-nor correct (many more are added: I, true, bool, compl, …):
(sed -n '1p' c11; sed -n '2,$p' ioccc.kw.freq | sort) | comm -3 - c11
-
-
-That is an obfuscated way to say “diff”. But it also more clearly shows the, um, diffs.
- -The usage string is similarly externalized, providing a better usability string than -the limits would otherwise allow. If this is considered bending the rules too far, -just -DU=O to get a passible, if cryptic, usage message using no additional octets -than without the define. -This also allows the builder to configure the amount of help a utility should provide -(you want a manpage? Because that’s how you get a manpage.) -– a rather significant point of contention made moot.
- -There is definitely abuse of the Rule2 counter, exploiting a “feature” of iocccsize:
-iocccsize does not Rule2 count {, } and ; when followed by whitespace – even within a string!
-Thus: Freecode, a simple, uncounted, highly obfuscated encoding of a central part
-of this program. (The reserved word list is not Freecoded, both because it is useful
-apart from the program, and because Freecode is not entirely free.*)
The code is ANSI compliant, but it does have a string longer than 509 characters. -It has been tested on OSX and Linux, Clang and GCC.
- -The code uses trigraphs, ironically: it parses trigraphs with trigraph code. -Because that’s funny. And it remains obscure after, so trigraphs are not used for obfuscation. -Thus -trigraphs -Wno-trigraphs (which is also humorous).
- -It’s obfuscated C. Thus -Wno-parentheses -Wno-empty-body -Wno-char-subscripts.
- -The code uses unsigned chars, but C strings are signed. Thus -Wno-pointer-sign. -NB: This is not a portability concern, the one string holds only printable ASCII characters.
- -Thus:
- -clang -ansi -Wall -trigraphs -Wno-trigraphs -Wno-parentheses -Wno-empty-body -Wno-char-subscripts -Wno-pointer-sign -DU=O -DW=\"keywords\" -o prog prog.c
-
-
-Cody Ferguson was relentless in his pursuit of bugs.
-Thanks to his reports, the version of unob.sh is stronger,
-tac groks digraphs, tokenfix corrects for missing digraphs in prog.c,
-and the program manpage was added to the corpus.
manpage is a useful program that turns ASCII versions of man pages (e.g. tac.man) into real
-man pages. It works for C and C-like languages, command lines,
-and was designed to handle man page sections 1-8.
-It works well on most inputs, but tends to need some raw nroff for more fancy constructions,
-such as combined arguments
-(e.g. the -r and -s arguments to tac are not recognised when written as -rs in prose).
Try:
- -manpage tac
-
-manpage -h
-manpage -h | manpage
-manpage -h | manpage -R | less
-manpage -h | manpage -P | lpr
-
-
-![]() |
-© Copyright 1984-2018,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Marcin Ciura mciura@gmail.com
-Twitter: @mciura
make
-
-./prog < text
-
-
-./prog < Makefile
-./prog < hint.text
-
-
-This text was processed by prog. You may get confused. -We’re not really sure: prog.c wasn’t commented. -Who has been thoroughly puzzled by prog? Also how obfuscated is prog? -Having been written in C, how large of a vocabulary has it?
- -“The Elements of Style” by prof. William Strunk, Jr. and E. B. White -is well known for its dislike of the passive voice. Direct, vigorous, -active constructions were instead recommended by the authors. -The development of this program has been driven by this tenet.
- -Only passive sentences from the standard input are output. The offending -part(s) of each sentence will be highlighted. Several kinds of passive -constructions are recognized:
- -Sentences are never broken by periods that follow abbreviations and -initials. Both regular and irregular past participles are properly -dealt with. Note that some words are red herrings: even though their -ending is -ed, they are not past participles.
- -Here is the purpose of every byte inside the c[] string:
V(4);V(2) and V(3);V(808) and V(205).I heard you don’t like state machines so I put a state machine in your -state machine so you can reject this entry while you reject this entry.
- -Both types of state machines in the program are Mealy machines: we can
-think of their transitions as triples (transition_label,
-next_state, output).
A state of type A state machine consists of eight transitions whose
-representations occupy consecutive bytes. The byte
-c[3 + 8*state + transition_label] contains
-(unsigned char)(30 + 5*next_state + output).
The transition_label is either one of character classes:
nil = 0,space = 1,new_line = 2,uppercase = 3,lowercase = 4,period = 5,bang_question = 6,punctuation = 7,or one of word classes:
- -adverb = 0,other = 2,past_participle = 3,to_be = 4,are_were = 5,wh_word = 6 (cf. the output of type B state machines).The output is either one of:
end_of_text = 0,sentence_start = 1,sentence_end = 2,token_end = 3,ignore = 4,or one of
- -passive_construction_start = 1,ignore = 2,passive_construction_end = 3.Type A state machines run continuously. Their state is kept in
-k[2] and k[3].
Below are sample steps of scanning a sequence of characters with
-classes uppercase, lowercase, period, space,
-and uppercase.
state = 7, transition_label = 3 (uppercase), output = sentence_startstate = 14, transition_label = 4 (lowercase), output = ignorestate = 15, transition_label = 5 (period), output = token_endstate = 13, transition_label = 1 (space), output = token_endstate = 18, transition_label = 3 (uppercase), output = sentence_endAnd here are sample steps of scanning tokens with classes to_be,
-adverb, past_participle.
state = 8, transition_label = 4 (to_be), output = passive_construction_startstate = 22, transition_label = 0 (adverb), output = ignorestate = 22, transition_label = 3 (past_participle), output = passive_construction_endType B state machines are built by a variant of the algorithm described -in the paper -How to squeeze a lexicon. -Their states are represented as interlaced sparse arrays of transitions.
- -The transition_label is one of:
word_start = 0,period_or_apostrophe = 1,a_z_letter = 2..27.The output is either one of word classes:
adverb = 0,ignore = 1,other = 2,past_participle = 3,to_be = 4,are_were = 5,wh_word = 6,or
- -ignore = 1,abbreviation = 2.The byte c[186 + (state + transition_label)] = (unsigned char)(2 + transition_label + 28 * output).
The byte c[836 + 2*(state + transition_label)] =
' ' when next_state / 376 == 0,';' when next_state / 376 == 1.The byte c[837 + 2*(state + transition_label)] =
' ' when next_state / 94 % 4 == 0,';' when next_state / 94 % 4 == 1,'{' when next_state / 94 % 4 == 2,'}' when next_state / 94 % 4 == 3.The byte c[2136 + (state + transition_label)] = (unsigned char)(32 + next_state % 94).
A type B state machine starts in a given state with output
-set to ignore. It scans a word backwards, converting character by
-character to transition_label. When it meets word_start, it
-returns, leaving the most recently stored output in v.
-It also returns when
-c[186 + (state + transition_label)] != (unsigned char)(2 + transition_label + 28 * output),
-i.e. when the transition_label in the byte mismatches the
-transition_label used to compute the index. Otherwise, if the
-output in this byte differs from ignore, the state machine
-stores it in v. Regardless of the value of the output,
-it also assigns next_state to state and proceeds to scan
-the previous character. The state machine that determines the word
-class is set up so that it never returns ignore.
Below are sample steps of scanning the word “chiefly”.
- -state = 623, transition_label = 26 (‘y’), output = otherstate = 602, transition_label = 13 (‘l’), output = adverbstate = 594, transition_label = 7 (‘f’), output = otherstate = 549, transition_label = 6 (‘e’), output = ignorestate = 543, transition_label = 10 (‘i’), output = adverbstate = 0, transition_label = 9 (‘h’) mismatches the value stored
-in the byte. Return adverb.And here are sample steps of scanning the string “i.e.”:
- -state = 19, transition_label = 1 (‘.’), output = ignorestate = 24, transition_label = 6 (‘e’), output = ignorestate = 3, transition_label = 1 (‘.’), output = ignorestate = 2, transition_label = 10 (‘i’), output = ignorestate = 1, transition_label = 0 (‘\0’), output = abbreviation.
-Return abbreviation.The judges found a bug in the handling of contractions: prog.orig.c
-outputs “foo wasn'[t bazzed]”. I fixed the bug in prog.c, making
-it output “foo [wasn’t bazzed]” instead, and took the liberty to merge
-one statement into a for loop inside its main() function.
The program uses a 9,437,187-byte buffer so it probably will not run
-on 16-bit and smaller machines without changing the size of array C[]
-and the expression 9<<20 inside the call to read().
I have tested it on:
- -For a clean compile under c89 and c90, add -Woverlength-strings
-to CSILENCE.
![]() |
-© Copyright 1984-2018,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Yusuke Endoh
-Twitter: @mametter
make
-./prog < textfile > output.gif
-
-
-./prog < golem.txt > golem.gif
-./prog < smily.txt > smily.gif
-
-
-To get the best experience, use a GIF viewer that can handle animated gifs. -On OS X you can use Safari using “open -a Safari smily.gif”
- -Some things to consider are that this 2.5KiB gem encodes a 96 character 8x8 -font (naively this could already take 6144 bytes) and a GIF encoder. But -how does it know which characters are closed?
- -You should only give this program printable ASCII characters.
- -Unfortunately this won’t run on your PDP8, if you had one, as it needs at -least 2MiB of memory to run in.
- -This program generates an animated GIF from a plain text. Run:
- -gcc -o prog prog.c
-./prog < invisible.txt > invisible.gif
-
-
-Open invisible.gif and then wait a minute. You will see a hidden message. -Can you tell the difference between letters that leaves the mark and ones that does not?
- -Other examples:
- -./prog < golem.txt > golem.gif
-./prog < smily.txt > smily.gif
-
-
-The program itself has a hidden message.
- -./prog < prog.c > prog.gif
-
-
-![]() |
-© Copyright 1984-2018,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Yusuke Endoh
-Twitter: @mametter
make
-
-./prog
-
-
-make
-
-./prog | tee prog_next.c
-make prog_next
-./prog_next | tee prog_next.c
-make prog_next
-./prog_next | tee prog_next.c
-
-make python
-
-make python3
-
-
-And now for something completely different: A program whose metabolic -processes are a matter of interest only to historians. It has kicked the bucket -and departed to that mysterious country from whose bourne no traveller returns! -This is an EX-tremely obfuscated program!
- - ___-----__
- _-- --__
- _- _--_ \
- _- /\ +-.:.:-+ /\ \
- / \/ |.:.:.:| \/ |
- / |:.:.:.| |
- / |.:.:.:| | ___-----___
- | |.:.:| | / \
- | |:.:.| | < It's ... |
- \ |:.| | \ /
- \ || | ---_____---
- _--\ |
- _- -__ |
- __- --___ |
- _- |
- / |
- | |
-
-
-![]() |
-© Copyright 1984-2018,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Cody Boone Ferguson weasel@xexyl.net
-https://ioccc.xexyl.net/2018/weasel
-Twitter: @xexyl
make
-
-./weasel
-
-
-./weasel words
-./weasel -mq words
-./weasel -q -r8 'EVOLUTION IS A PROVEN FACT'
-./weasel -m 'INTELLIGENT DESIGN'
-
-make test
-
-
-Looking back over the strata of past IOCCC entries, this program marks a new -mutation on our understanding of sequencing of code. In adaptation of the -modern scientific that the C language has evolved, this mutant of a program -may stress your understanding of taxonomy of the C syntax tree.
- -The phenotype of the source suggests a veritable sea of primordial ASCII soup. -The encoded logic of the watchmaker suggests a variation of thought experiment -formulated by Richard Dawkins: but without the need for feeding too many -evolutionary relatives of the primate order in which us Homo sapiens hang -from the phylogenetic tree of life.
- -If you wish your computer to maintain one branch in the Cretaceous C code era, -while using more Cenozoic minded code migration, read rpm.markdown.
- -If you find yourself in an evolutionary dead end, try:
- -man ./weasel.man
-
-
-0. Preface
-1. What it is
-2. How it works
-3. Hints (Keyboards, Options, Spoilers, Example Invocations)
-4. Obfuscation (Techniques, Beauty)
-5. How to build (S and N Constants, Compilation, Portability, Installing)
-6. Final thoughts
-7. Winning comments, thanks, dedications, links, etc.
-
-
-SPOILER WARNING: A great deal of this document and the man page is full of
-spoilers of different types; as such I would recommend that you try running the
-judges suggested invocations as well as running make test before you get into
-the document or the man page, unless you don’t mind any spoilers. I don’t reveal
-much in the way of obfuscation however so if you just want documentation on the
-program, how to compile, etc. then there isn’t need to heed this note.
I was at a loss on how to present my remarks; on the one hand I wanted to give -everything to the judges so they didn’t miss anything. But on the other hand I -didn’t want to reveal as much publicly and many people don’t like to read long -texts. To resolve this I think the best way is referencing the judges' comments: -if you want a quick rundown of the entry try what they suggest and view the man -page (it explains all the options and describes the program briefly):
- -man ./weasel.man
-
-
-If that isn’t sufficient I would recommend reading this section (and -possibly the next) where I attempt to give a brief explanation of the sections -to make reading it easier and faster. In addition I want to point out a few -things. If you want more details read this document more thoroughly (or just -the sections that seem relevant to what you’re after). The FILES file is a -quick list of files and respective summaries in this entry. Because several -sections are quite long I have added a skip to link to skip to the next -subsection or section at the beginning of each section (and subsection).
- -What it is: This is a brief summary of the program; the man page is -more thorough than this.
- -How it works: Explain some of the basic concepts and terms of the
-program; if you’re familiar with genetic algorithms there won’t be any problem
-following this section but it might be of some value to read anyway. There is a
-randomised mode that doesn’t use a genetic algorithm; it can be triggered a
-number of ways but the -m option enables it specially (I discuss this
-thoroughly in Hints).
Hints: Perhaps the longest part of this document because in it I -document the keyboards, options, subtleties (including -features that might appear to be bugs but aren’t - including an -input error), an Easter egg spoiler and quite a few -example invocations. If you’ve read the man page you probably -don’t need this unless there is something specific you’re after.
- -Obfuscation: Some of the techniques that might not be used.
- -How to build: Here I describe briefly
-the constants that can be redefined S and N: the
-maximum size of the chromosome (target string; the maximum length is S - 1
-but it must be >= the default 38) and the number of offspring, respectively. I
-also give example compiler invocations, portability
-notes, an more portability notes and a note on
-rpm.markdown.
On the subject of S and N: As the judges' suggested runs imply you
-can change the target string at runtime; make test runs a script
-test.sh which reads from the file test-strings.txt, running the program
-for each string in the file, waiting approximately two seconds before
-continuing. I explain how to pass options to the script in part of
-Hints.
Final thoughts: You might enjoy what I included; they’re -humorous pieces by Dennis Ritchie and Ken Thompson themselves -from the infamous UNIX-HATERS Handbook.
- -Winning thoughts: What it means to me to win as well as some -dedications and thanks. Here too I include a link to a website which will be -dedicated to this entry beyond what will be published on the IOCCC website
- -Skip to How it works.
- -It is an implementation of Richard Dawkins' Weasel program (Wikipedia). -According to Wikipedia in chapter three of his book The Blind Watchmaker -Dawkins wrote:
- -- -I don’t know who it was first pointed out that, given enough time, a monkey -bashing away at random on a typewriter could produce all the works of -Shakespeare. The operative phrase is, of course, given enough time. Let us -limit the task facing our monkey somewhat. Suppose that he has to produce, not -the complete works of Shakespeare but just the short sentence ‘Methinks it is -like a weasel’, and we shall make it relatively easy by giving him a typewriter -with a restricted keyboard, one with just the 26 (capital) letters, and a space -bar. How long will he take to write this one little sentence?
He refers to the Infinite Monkey Theorem (Wikipedia). As he points out the
-operative phrase is given enough time; but even if it’s extremely unlikely
-technically the probability is greater than 0. He simplified it for the
-monkey; I thought the monkey had it too easy: unlike his limited keyboard I have
-(besides space) every character in the ASCII range 0<=126 that
-isprint() returns non-zero except that only capital letters are included;
-the file prog-simple.c has a slightly smaller keyboard. There are some
-additional features I have added (including two Easter eggs); amongst others:
-ability to change the target string and maximum length. See
-How it works, Hints and How to build for
-more details.
In its simplest invocation this program will work its way (using a genetic
-algorithm) towards the solution of the string METHINKS IT IS LIKE A WEASEL
-(note that I use toupper() so it doesn’t matter what case the input is the
-comparison and output will always be capitalised).
Skip to Hints.
- -Here you can find a general explanation of a genetic algorithm as well as a -brief history. Although the link provides more information (including images to -try and show the way they work) for those interested I will cite the summary:
- -- -Genetic Algorithms (GAs) are adaptive heuristic search algorithm based on the -evolutionary ideas of natural selection and genetics. As such they represent an -intelligent exploitation of a random search used to solve optimization problems. -Although randomised, GAs are by no means random, instead they exploit historical -information to direct the search into the region of better performance within -the search space. The basic techniques of the GAs are designed to simulate -processes in natural systems necessary for evolution, specially those follow the -principles first laid down by Charles Darwin of “survival of the fittest.”. -Since in nature, competition among individuals for scanty resources results in -the fittest individuals dominating over the weaker ones.
SPOILER WARNING: Some of the below might help you follow the code more -easily.
- -For each generation there is a total of N offspring; generation 0 is
-the pseudo-randomly initialised array without parents. Each offspring has its
-own chromosome to be compared to the target string and a fitness score;
-the higher the fitness score the more likely it will be a parent of the next
-generation (randomised mode notwithstanding) as part of the selection process
-(As the generations go by the fitness of the offspring should be higher; when
-the fitness matches that of the target it will be printed and the loop will be
-broken out of).
After determining the two parents crossover occurs: each new offspring
-inherits DNA from the parents; every character in the chromosome string is
-pseudorandomly selected from one of the parents' respective character. Next,
-based on the mutation rate, perform mutation of the chromosome of each
-offspring; in other words some of the characters in the chromosome will be
-assigned a pseudo-random value from the keyboard (in normal mode; in random mode
-every character will be assigned a value). Before mutation the offspring
-chromosome will be printed; after mutation it will show what it was mutated to
-(on the same output line). After the new generation has been sequenced the loop
-goes back to the top and it starts all over until the maximum number of
-generations SIZE_MAX - 1 is reached or the target chromosome has been
-found.
Note that the generation is checked before the scoring takes place by a prefix
-increment equality check; when the generation is SIZE_MAX - 1 the fitness
-test loop will not be entered; instead the outer loop will end after printing:
- -Too many attempts, blaming the monkey Eric even if he isn’t typing or doesn’t exist. Bye.
Why ‘Eric’? Because the judges stated in the 2018 guidelines that when -there is a user input error the program should insult the pet fish Eric even if -such a fish (no, weasels do not equate monkeys to fish but see below) doesn’t -exist. The second to last example limitation example note (it’s improved in the -final but this is relevant) they give is:
- -- -The judges might not have a pet fish named Eric, so might want to state:
- -This entry factors integers between 1 and 2305567963945518424753102147331756070. - Attempting to factor anything else will cause the program to insult your - pet fish Eric, or in the case that you lack such a pet, will insult the - pet that you do not have.
After the final message they ask:
- -- -BTW: What is so special about 2305567963945518424753102147331756070? You tell us!
The answer is this: it is the primorial prime of 97: the product of all
-prime numbers less than or equal to N; and the primorial prime of N == 97 is
-2305567963945518424753102147331756070. There is no reference to this number
-in my entry but it’s nonetheless possible to change the default target to it
-without modifying the source code; there are two hints in this very
-paragraph; the first sentence in fact: the answer to the judges' question and
-the definition. Can you get the program to search the primorial prime of 97
-without passing in specially?
On user errors: if the generation reaches SIZE_MAX - 1 I consider it a
-user (or monkey) error; if the user insists on being so petulant as to try such
-a ridiculous set of parameters in an attempt to make it be no more successful
-than a monkey typing then it shouldn’t be any more successful than a monkey; if
-it by chance reaches the target it’s because a monkey could too! Either way
-unless the number reaches SIZE_MAX - 1 the monkey Eric won’t be blamed. It
-should be noted that depending on the parameters (size of chromosome, number of
-offspring, the string itself) the program could take quite a lot of system
-resources; and whether the OS kills it, Eric the monkey falls asleep or the
-typewriter is taken from him the result could very well be not found without
-blaming him. Of course the judges were talking about fish not monkeys. But since
-this program is inspired by the Weasel program which was inspired by the
-Infinite Monkey Theorem I opted instead to target the monkey Eric even if
-such a monkey isn’t typing or even doesn’t exist (because it’s not the Infinite
-Fish Theorem). So although the user might not be a monkey the program makes the
-assumption that the user could in fact be a monkey called Eric although it
-isn’t insolent enough to say the user is a monkey for certain!
Skip to Obfuscation.
- -I noted that there are a number of additional features and here I will document -some of them.
- -Skip to Options.
- -The keyboard, as noted, has more than just the alphabet and space. To be
-precise the following characters are acceptable; it equates to this in C (note
-it includes a literal space ' ' but it doesn’t include other
-isspace() characters) and this is why some of the characters are escaped:
const char keyboard[]=" !\"#$<%:>&'()*+,-./0123456789;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`{|}~";
-
-
-The simpler keyboard looks like:
- - const char keyboard[]=" !\"&'(),.0123456789;?ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
-
-The program makes sure that the target string only has characters the keyboard -can actually produce but there is a certain type of input error that might -appear to be a bug; see specifically Input Error Example.
- -Skip to Spoilers.
- -There are a number of options you can pass to the program besides the target
-string; some I will document here (the summary being in the man page). You can
-join options but there is a caveat with spaces and -r option as well as
-the target string (see below).
Enable quiet output:
- - -q
-
-
-This means don’t print the generation and offspring output; only print (some) of -the options set (this is always done but wouldn’t usually be seen due to verbose -output) and the final answer.
- -Change the mutation rate to <rate>:
-r<num>
-
-
-Please note that there cannot be a space between the -r and the number.
-This is to simplify the parsing of options. As for combining options you can do
-any of the following (amongst others):
-r5q
- -qr5
- -qr
- -q -r5
-
-
-The third invocation will set quiet output and have no valid value to parse for
-the mutation rate and strtol() in this case returns 0. strtol() can
-legitimately return 0 but in no instance is it valid input in this program: the
-valid mutation rate is >= 1 && <= 100.
When the mutation rate is out of range it does something interesting: take a -look at the output and compare it to the output when the range is valid. Can you -figure out another way to trigger this? In fact there are two more ways (one is -an option I’ve mentioned and the other one is to do with the number of -offspring)! If you want something of a walk through I suggest you follow the -following:
- -Enable quiet mode and set an invalid mutation range; for example specify:
- --qr101
-Take a look at the first few lines. Kill the program and try invoking it -with the following options:
- - -qr5
-Look at the first few lines again and compare it to the output of step #1. -With the default string most modern systems shouldn’t take much time to - given -decent parameters - come to an answer here but if necessary kill the program.
Repeat the steps only this time don’t enable quiet mode. Look at the -offspring output. If you still don’t see what it is and want to know see -Spoilers below.
Finally any argument that doesn’t start with a - passed into the program
-will become the target string. The same rule applies to the number for -r:
-it must be a single parameter which means you’ll need to quote the string if it
-has more than one word (that is it contains spaces) or anything else interpreted
-specially by your shell e.g. parentheses. For instance if you just want to find
-METHINKS you could do one of:
$ ./weasel METHINKS
- $ ./weasel "METHINKS"
- $ ./weasel 'METHINKS'
-
-
-If you wanted YOU ARE A MONKEY:
$ ./weasel "YOU ARE A MONKEY"
- $ ./weasel 'YOU ARE A MONKEY'
-
-
-If you do one of:
- - $ ./weasel "METHINKS IT IS A" "MONKEY"
- $ ./weasel METHINKS IT IS A MONKEY
-
-
-It will search for MONKEY in both cases; in other words it’s the last one.
-If the string is too long given the value of S (see
-How to build) it will be truncated.
If you actually do want to search for a string starting with a - you must
-disable further parsing of options by using the - option itself; for
-example if you were to do any of:
$ ./weasel -q- -- -test
- $ ./weasel -q- -test
- $ ./weasel -q -- -test
-
-
-The target string will be: -TEST. This means though that here:
$ ./weasel -q -- -test -r5
-
-
-The string to be searched would actually be -r5 and the mutation rate
-will remain the default because after the - option is seen it will no
-longer parse additional options: only target strings if anything left on the
-command line. Because of the joining of arguments this means that the first two
-examples of the last set of three above are equivalent i.e. the following two
-are equivalent:
-q-
- -q --
-
-
-As for the caveat I referenced what does the following do?
- - $ ./weasel -qr 5
-
-
-In fact it will set quiet output and set the target string to be ‘5’. So the
-mutation rate will be out of range, thus enabling that Easter egg, but it will
-likely come to an answer fairly quickly because it’s just a single character. A
-note on the parsing of the - option; if the program is currently parsing
-argv[N], for example, and it encounters a -- then depending on where
-the other options are in the command line it might still parse the options. Thus
-you have:
$ ./weasel -qr-r5
- quiet output
- mutation rate out of range
- target 'METHINKS IT IS LIKE A WEASEL'
- mutation rate 5
- Generation 440 Offspring 20: METHINKS IT IS LIKE A WEASEL
-
-
-Similarly this would set quiet output, then an invalid mutation rate and then a -mutation rate of 5:
- - $ ./weasel --qrr5
-
-
-If you were instead to do one of (for example):
- - $ ./weasel -q -- -r
- $ ./weasel -q -q- -r
-
-
-Then it would set quiet output then see the -- (the - option
-itself) and then the target string would literally be set to -r because
-it no longer cares about the - for option parsing. In other words options
-are only parsed if the first character is - and if the parser hasn’t seen
-the - - in an earlier element of argv. This is not a bug!
Skip to Example Invocations.
- -The Easter egg: Since Dawkins references the Infinite Monkey Theorem it -simulates a monkey using a typewriter! This mode has the following changes:
- -Selection is omitted; this means no sorting by fitness score (each offspring
-is initially set to be the first two in the list) but do pseudo-randomly
-select characters for every character in the target string; that is to say if
-the string is of length 28 (the default) then all 28 characters in each
-offspring of each generation will be assigned a pseudo-randomly positioned
-character in the keyboard. If you want to enable this specially you can use the
--m option (-m for monkey).
Skip to Input Error Example.
- -The following examples are used to demonstrate better the command line parsing.
-In order to do that though I had to first document the -m option because
-if the mutation rate is out of range monkey mode is activated (that’s the first
-Easter egg). But what happens if you later set a valid mutation rate? Should
-monkey mode be disabled? If yes how do we know if monkey mode was specially
-requested? There are at least two ways to go about it: I took the monkey safe
-(‘fool safe’) method; if you explicitly request monkey mode you cannot disable
-it in the same invocation of weasel!
$ ./weasel -qr101r5r101r1r test
- quiet output
- mutation rate out of range
- mutation rate out of range
- mutation rate out of range
- target 'test'
- mutation rate 0
- monkey at typewriter
- Generation 16844 Offspring 22: TEST
-
-
-So in this case I joined the options in the following order:
- --qQuiet output.
- --r101Mutation rate 101 (out of range).
- --r5Mutation rate of 5 but note that during parsing I only print invalid mutation
-rate (only after parsing do I print the final mutation rate whatever it ends up
-being); so while it appears there is a bug, showing mutation rate out of range
-three times, this is expected (given the next one, -r101). This means here
-the typewriter was taken from Eric the monkey.
-r101Mutation rate to 101: this too is out of range (this is the second mutation rate -out of range message). The typewriter returns to Eric.
- --r1Set mutation rate to 1. Take that typewriter away!
- --rSet mutation rate to 0; when there are no valid characters passed to
-strtol() it should return 0: this is the third message about being out of
-range. Note here that rand() returns an int and strtol()
-returns a long but I compare the return value of rand() to the
-mutation rate; if there are any systems where the widths differ this shouldn’t
-matter because of truncation but I do in any case specifically check for R <
-0 || R > 100. Either way the invalid range returns the typewriter to Eric.
testFinally I requested it find the string test (will search for TEST).
Given that it was a short string it did find the answer relatively quickly, even -in monkey mode.
- -Another example:
- - $ ./weasel -q -r101 test -r5
- quiet output
- mutation rate out of range
- target 'test'
- mutation rate 5
- Generation 109 Offspring 13: TEST
-
-
-In this case I also enabled quiet mode but I didn’t join the options; the
--r101 reports that it’s out of range and sets monkey mode. I then specify
-the target string and then set a valid mutation rate. This disabled monkey mode
-which means that it’ll use the genetic algorithm.
One more example of monkey mode:
- - $ ./weasel -q -mr101 test -r5
- quiet output
- mutation rate out of range
- target 'test'
- mutation rate 5
- monkey at typewriter
- Generation 465298 Offspring 10: TEST
-
-
-Here I also requested quiet output and then explicitly requested that Eric the
-monkey types. After this I set the mutation rate to be 101 which would have
-set monkey mode (in this case only temporarily as I later set it to a valid
-number) but since I have also requested monkey mode that won’t matter. Then I
-set the string to test and then set a valid mutation rate of 5. Now note
-that it is actually set to 5 but also note that monkey mode remains active: it
-also took a lot longer to come to a conclusion for even four characters. This
-example does demonstrate one other thing in a subtle way though.
When the program prints out each iteration (I’ll give an example next) it goes a -lot slower; this makes sense because it’s an expensive operation. Here are the -times for the same but without quiet output enabled:
- - real 0m17.065s
- user 0m1.245s
- sys 0m2.402s
-
-
-Whereas with quiet output:
- - real 0m0.127s
- user 0m0.125s
- sys 0m0.001s
-
-
-Of course it isn’t only down to the printing but the point is it slows it down
-significantly. Adding an option to print every X lines would go over the limit
-(iocccsize -i reports 2052!).
Finally I’ll show a default example in normal output (I omit many lines showing
-instead […]). Note that the real/user/sys times are from the time
-bash shell built-in utility: that isn’t output from my entry.
target 'METHINKS IT IS LIKE A WEASEL'
- mutation rate 1
- Generation 0 Offspring 1: 4V YGY.GH/}_|>Q1M.R8;KD[=(05
- Generation 0 Offspring 2: Y_^S0_HZ399^/|9,MP%^{817"XX#
- Generation 0 Offspring 3: F%88H1&[V1P>QOI}- U]0[V-Y%*[
- [...]
- Generation 1 Offspring 23: AHA#.\=ZT'0>?~-S.;1A L|1<S:^ -> AHA#.\=ZT'0>?~-S.;1A L|1<S:| (mutation)
- Generation 1 Offspring 24: AHA#.\=ZT'0>?~-S.;1A L|1<S:^ -> AHA#.\=ZT'0>?~-S.;1A L|1<S:^ (mutation)
- Generation 1 Offspring 25: AHA#.\=ZT'0>?~-S.;1A L|1<S:^ -> AHA#1\=ZT'0>?~-S.;1A L|1<S:^ (mutation)
- **
- Generation 2 Offspring 1: AHA#.\=ZT'0>?~-S.;1A L|1<S:^ -> AHA#.\=ZT'0>?~-S.;1A L|1<S:^ (mutation)
- Generation 2 Offspring 2: AHA#.\=ZT'0>?~-S.;1A L|1<S:^ -> AHA#.\=ZT'O>?~-S.;1A L|1<S:^ (mutation)
- [...]
- Generation 979 Offspring 1: METHINKS ITZIS LIKE A WEASEL -> METHINKS IT IS LIKE A WEASEL (mutation)
- [...]
- **
- Generation 979 Offspring 1: METHINKS IT IS LIKE A WEASEL
-
- real 0m0.074s
- user 0m0.040s
- sys 0m0.001s
-
-
-Keep in mind the way I display the generations and the fact that generation 0
-has no parents; it is generation 1 that starts working towards the goal. You’ll
-see also (mutation) at the end of the line at this point (if you enable
-monkey mode you’ll find that it shows something else). The lines that only have
-** are separators: you won’t see this between generation 0 and 1 but you will
-between future generations - as well as the final answer (if the answer is in
-generation 0 you won’t see the **).
-One final thing to consider is that the program doesn’t directly read from a -file. This combined with the way the shell works could possibly confuse some -people. Take the following invocations:
- - (1) $ echo test > test
- (2) $ ./weasel test
- (3) $ ./weasel < test
- (4) $ cat test | ./weasel
- (5) $ < test-strings.txt ./weasel
- (6) $ cat | ./weasel
-
-
-Only the first invocation of ./weasel will search for TEST because
-the string test was explicitly passed to the program (If the file test
-wasn’t found by that path it would still have searched for TEST).
The second invocation will search for the default string if there is a file or
-directory called test; else you will get an error about no such file or
-directory (unless your shell for some reason doesn’t consider it an error; bash
-most certainly does consider it an error and halts).
The third invocation would if there exists a file test cat that file and
-pipe the output to ./weasel; however it will search for the default
-string. If there is no such file to cat then an error will be reported but
-without quiet mode you’d probably not even see the error.
The fourth invocation will also search for the default string unless the file -doesn’t exist in which case you’d get an error like in the second invocation.
- -The fifth invocation will actually search for the default string even with the
-file test-strings.txt existing. As far as I am aware it’s equivalent to the
-third invocation except that the file exists in this case.
The final invocation will search for the default and then read from stdin;
-it won’t do anything with it however.
What this amounts to is if you want input from a file you have to read from the
-file and pass each string to the program itself. I’ve included a script
-test.sh and a file of sample input test-strings.txt that you can play
-with.
Try:
- - $ make test
-
-
-This will essentially make sure the program is compiled and then do:
- - $ chmod +x test.sh
- $ ./test.sh
-
-
-The script will first try compiling the program (if necessary) and if it fails
-for any reason it will exit; else it will read each line in the file
-test-strings.txt (if the file doesn’t exist or can’t be read the script will
-exit with return status of 1) and pass it to the program. After finding the
-string it’ll sleep approximately 2 seconds and then read the next string
-(passing it to the program, continuing until all the strings have been read and
-processed).
You can pass additional options directly to the script but remember that it -stops when there are no more strings in the file - so if you try:
- - $ ./test.sh -q test
-
-
-The final string test won’t be searched for; it will however run the program
-in all invocations with quiet output enabled. The following are some notes about
-how the shell and the program interact with each other:
Because the script quotes the strings that it reads from the file if you were to
-put in the file: -q STRING quiet mode would be enabled; however the
-default string would be searched for. If the quotes were removed from the script
-it would print the final word specified. To be specific with the quotes: if in
-the file you had the line -q STRING -m TEST it would enable quiet output
-and monkey typewriter mode; but it would search for the default string. Without
-the quotes on the other hand it would enable quiet output, monkey typewriter and
-search for TEST. In other words if you want to pass options to the
-script you will have to directly pass the options to the script like the above
-example shows (but the strings will still only be read from the
-test-strings.txt file).
Skip to Obfuscation.
- -There is a type of input error, as I said, that might appear to be a bug. What
-actually is going on though is due to a technicality on how spaces are printed
-and the fact the program does not accept spaces other than a literal space
-; when a character in the string to be found isn’t in the keyboard the
-program prints an error message and then exits (returning 1). But since the
-keyboard doesn’t have '\n' if you were to type a ' and send a
-'\n' before the closing ' you might see something like:
$ ./weasel '!!
- > '
-
- '
- ' not in keyboard " !"#$<%:>&'()*+,-./0123456789;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`{|}~"
-
-
-I showed that ' is in the keyboard already; however the user sent a
-\n (hence the secondary prompt > on line two) before literally typing the
-closing ' (also line two). But in order to make it clear what character is invalid I
-surround the character with 's so what you actually see after typing the
-closing ' and hitting Enter (or however you send the '\n') there is
-the third blank line; but then the program prints ' followed by the
-invalid character ('\n' itself which means another line break) and then
-finally the closing '. Specifically isspace() characters aren’t
-distinctly seen like a letter, digit or symbol is: isprint('\n') == 0 &&
-isspace('\n') == 1. You can add these characters but the output will be
-rather confusing and hard to read.
Skip to Beauty.
- -The following might be some of the techniques used in this entry:
- -Helpful and descriptive names for all variables and constants (like S)
-as well as some C keywords.
The way main() is declared is:
/* Special C main() handler (encapsulation): */
-#define r(main) main
-r(k main(k a, E **V)) {
-
-
-It appears to be recursively defined but is it? And is it truly -encapsulation? And is it executing code of any kind? It mightn’t seem like it -isn’t encapsulation and also isn’t executing code but assuming it’s -encapsulation and executing code is it actually nothing? And if it’s nothing why -is it there? If it is something what is it doing? Could it be both? Or maybe it -really isn’t nothing or nothing? :)
A special C parser called H(). It might help to observe that there
-might be recursive calls and much of the program might use it. Or so it seems.
-Then again it might not help to not notice it.
Digraphs. In their simplest form it’s probably not a big deal but consider:
-some source code formatters don’t like them at all (neither, incidentally, does
-splint, which completely baulks). There also is a trick; if you try
-translating them then depending upon how you do it there can be functional
-changes in the program!
The fact the program can by default print the primorial prime of 97 (but that -default isn’t the default - except when it IS the default!) and yet that number -isn’t seen at all. See also technique #7.
Another usual suspect: the source is formatted in a beautiful design that -could be described artistic; on the other hand some might suggest it’s just a -blob of octets but I disprove this when discussing beauty later on in the next -section.
The string METHINKS IT IS LIKE A WEASEL is searched for by default -(except when it’s not searched by default) but it’s nowhere to be found in the -source file in that form. Why? Because anyone familiar with the Weasel program -won’t recognise the string and put together what it is by looking at the source -code.
In case you wondered deciphering #5 won’t decipher #7 (neither will deciphering -#7 help you decipher #5).
- -Skip to How to build.
- -On the subject of beauty: the judges stated in the guidelines the following:
- -- -We want to get away from source that is simply a compact blob of -octets. Really try to be more creative than blob coding. HINT!
And if you’ll notice that although it might look like a compact blob of octets -at first glance if you look throughout the file you’ll see two statements to -set your thinking straight:
- -- -NO BLOB CODING
- -THIS IS NOT A COMPACT BLOB OF OCTETS
So you see even if your eyes are trying to deceive you they’re quite wrong. Yes -some of it might look like a blob but this is clearly false; as all good -programmers know if something is potentially confusing or misleading it should -be made clear in the comments! :)
- -Skip to Compilation.
- -These two #defined constants can be redefined at compilation to modify the
-behaviour of the program in a number of ways (see the
-Compilation subsection for example invocations). Both are
-capped to be no greater than SIZE_MAX - 1. This is handled by the C
-preprocessor.
S
This determines the maximum size of the target string but it must be at least
-38; this is because 38 >= 29 and because strlen("METHINKS IT IS LIKE
-A WEASEL") == 28 (which is the default target string - it would hardly be an
-implementation of the Weasel program otherwise).
There is obviously a reason 38 is the chosen size but the only hints I
-provide are those in How it works and specifically an Easter egg I
-referenced there (it’s not the only Easter egg but it’s the only Easter egg I
-won’t spoil; yes this ironically and amusingly means I’ve left a rotten egg
-somewhere!).
N
This is the number of offspring per generation. Anything less than 4 will be set -to 3 (that’s not a typo!) and this is part of an Easter egg.
- -Be aware that depending on the size of S and N (individually and
-together) the program will use varying amounts of memory and the larger the
-values the more memory it’ll require.
Skip to Portability.
- -The following options must always be passed to the compiler:
- - -DQ='typedef' -D'g(o)'='goto o;' -D'w(x)'="x:" -D'H(main)'='r(main)'
-
-
-If you want to increase the number of offspring to 50 and the size of the
-chromosome to 75 you would pass to the compiler:
-DQ='typedef' -D'g(o)'='goto o;' -D'w(x)'="x:" -D'H(main)'='r(main)' -DN=50 -DS=75
-
-
-If you wanted to change N to 3:
-DQ='typedef' -D'g(o)'='goto o;' -D'w(x)'="x:" -D'H(main)'='r(main)' -DN=3
-
-
-Remember that it cannot be less than 3; more correctly if it’s less than
-4 it’s redefined to 3 so you could have passed in -DN=2 and have the same
-result. Remember too that S cannot be less than 38. Both S and
-N are capped at SIZE_MAX - 1.
Skip to An aside on bugs.
- -The entry works for both C99 and C11 (it requires at least C99 even if you
-translate digraphs). The program doesn’t require third-party libraries and
-should work on any Unix based system. It works on both 64-bit and 32-bit (but
-inevitably some data type sizes will be smaller and this I believe includes
-SIZE_MAX). I don’t think Windows gcc ports would have many issues (if any)
-either but I have no way to test this. I have tested the following systems and
-configurations:
Fedora 26:
-
- $ clang --version|head -n1
- clang version 4.0.1 (tags/RELEASE_401/final)
- $ gcc --version|head -n1
- gcc (GCC) 7.3.1 20180130 (Red Hat 7.3.1-2)
- $ /lib64/libc-2.25.so |head -n1|cut -d',' -f1-1
- GNU C Library (GNU libc) stable release version 2.25
- $ lscpu |grep Endian
- Byte Order: Little Endian
-
-
- CentOS Linux release 7.4.1708 (Core)
-
- $ clang --version|head -n1
- clang version 3.4.2 (tags/RELEASE_34/dot2-final)
- $ gcc --version|head -n1
- gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-16)
- $ /lib64/libc-2.17.so |head -n1 |cut -d, -f1-1
- GNU C Library (GNU libc) stable release version 2.17
- $ lscpu |grep Endian
- Byte Order: Little Endian
-
-
- Fedora 27:
-
- $ clang --version|head -n1
- clang version 5.0.1 (tags/RELEASE_501/final)
- $ gcc --version|head -n1
- gcc (GCC) 7.3.1 20180303 (Red Hat 7.3.1-5)
- $ /lib64/libc-2.26.so |head -n1|cut -d, -f1-1
- GNU C Library (GNU libc) stable release version 2.26
- $ lscpu |grep Endian
- Byte Order: Little Endian
-
-
- macOS:
-
- System Version: macOS 10.13.4 (17E199)
- Kernel Version: Darwin 17.5.0
- $ gcc -v
- Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
- Apple LLVM version 9.1.0 (clang-902.0.39.1)
- Target: x86_64-apple-darwin17.5.0
- Thread model: posix
- InstalledDir: /Library/Developer/CommandLineTools/usr/bin
- $ uname -srmv
- Darwin 17.5.0 Darwin Kernel Version 17.5.0: Mon Mar 5 22:24:32 PST 2018; root:xnu-4570.51.1~1/RELEASE_X86_64 x86_64
-
-
-Skip to Installing.
- -Any undocumented bugs are the result of insolent monkeys tampering with any
-number of things. That includes but is not limited to running the program on a
-non-ASCII system; non little-endian; meddling with S or N too much,
-changing the references to SIZE_MAX to be larger than SIZE_MAX or a
-signed value (size_t is unsigned) or too small of a value; changing data
-types or variables; expecting really long strings - including but not limited to
-the complete works of Shakespeare (hint: isprint('\n') == 0 so it won’t
-ever find any string with '\n') - to be found by the program in a quick
-and easy fashion if ever; or any other meddling including being petulant and/or
-unreasonable monkeys. I will say though that there is at least one place I see
-after having won that could be slightly more efficient (can you find it?); I am
-however leaving it as it is because this is what won.
Skip to Final thoughts.
- -I have included a RPM spec file for those with a Red Hat based Linux -distribution; see rpm.markdown for details (including why I implemented -this) if for some (strange?) reason you’re interested.
- -Skip to Winning comments.
- -The judges suggested that making them laugh helps entries chance of winning. -Well laughter helps everything so in case you haven’t seen - and even if you -have seen - Dennis Ritchie’s anti-foreword to the ghastly UNIX-HATERS -Handbook or Ken Thompson’s revelation that C and Unix are a hoax (at the end of -that book) I include it below; because I agree that looking at a lot of twisted -code must be quite difficult (though maybe not as much as if you were to have to -look at Microsoft Windows code or code for Windows in any case ? :)) and these -two things I think are rather amusing (in order of least to most):
- -Dennis Ritchie’s Anti-Foreword:
- -- -Anti-Foreword
- -By Dennis Ritchie -From: dmr@plan9.research.att.com -Date: Tue, 15 Mar 1994 00:38:07 EST -Subject: anti-foreword
- -To the contributers to this book:
- -I have succumbed to the temptation you offered in your preface: I do write you -off as envious malcontents and romantic keepers of memories. The systems you -remember so fondly (TOPS-20, ITS, Multics, Lisp Machine, Cedar/Mesa, the Dorado) -are not just out to pasture, they are fertilizing it from below.
- -Your judgments are not keen, they are intoxicated by metaphor. In the Preface -you suffer first from heat, lice, and malnourishment, then become prisoners in -a Gulag. In Chapter 1 you are in turn infected by a virus, racked by drug -addiction, and addled by puffiness of the genome.
- -Yet your prison without coherent design continues to imprison you. How can -this be, if it has no strong places? The rational prisoner exploits the weak -places, creates order from chaos: instead, collectives like the FSF vindicate -their jailers by building cells almost compatible with the existing ones, albeit -with more features. The journalist with three undergraduate degrees from MIT, -the researcher at Microsoft, and the senior scientist at Apple might volunteer a -few words about the regulations of the prisons to which they have been -transferred.
- -Your sense of the possible is in no sense pure: sometimes you want the same -thing you have, but wish you had done it yourselves; other times you want -something different, but can’t seem to get people to use it; sometimes one -wonders why you just don’t shut up and tell people to buy a PC with Windows or a -Mac. No Gulag or lice, just a future whose intellectual tone and interaction -style is set by Sonic the Hedgehog. You claim to seek progress, but you succeed -mainly in whining.
- -Here is my metaphor: your book is a pudding stuffed with apposite -observations, many well-conceived. Like excrement, it contains enough undigested -nuggets of nutrition to sustain life for some. But it is not a tasty pie: it -reeks too much of contempt and of envy.
- -Bon appetit!
Yes he misspelt ‘contributors’! But then again we’re talking about obfuscation -and since it doesn’t break his message it’s not broken - it’s just obfuscated -albeit not very much (and it still ‘compiles’!); and isn’t that what this -contest is about? :)
- -Ken Thompson’s ending:
- -- -Creators Admit C, Unix Were Hoax
- -FOR IMMEDIATE RELEASE
- -In an announcement that has stunned the computer industry, Ken Thompson, -Dennis Ritchie, and Brian Kernighan admitted that the Unix operating system and -C programming language created by them is an elaborate April Fools prank kept -alive for more than 20 years. Speaking at the recent UnixWorld Software -Development Forum, Thompson revealed the following:
- -“In 1969, AT&T had just terminated their work with the GE/AT&T Multics -project. Brian and I had just started working with an early release of Pascal -from Professor Nichlaus Wirth’s ETH labs in Switzerland, and we were impressed -with its elegant simplicity and power. Dennis had just finished reading Bored of -the Rings, a hilarious National Lampoon parody of the great Tolkien Lord of the -Rings trilogy. As a lark, we decided to do parodies of the Multics environment -and Pascal. Dennis and I were responsible for the operating environment. We -looked at Multics and designed the new system to be as complex and cryptic as -possible to maximize casual users' frustration levels, calling it Unix as a -parody of Multics, as well as other more risque allusions.
- -“Then Dennis and Brian worked on a truly warped version of Pascal, called "A.” -When we found others were actually trying to programs with A, we quickly added -additional cryptic features and evolved into B, BCPL, and finally C. We stopped -when we got a clean compile on the following syntax:
for(;P("\n"),R=;P("|"))for(e=C;e=P("_"+(*u++/
- 8)%2))P("|"+(*u/4)%2);
-
-
-- -“To think that modern programmers would try to use a language that allowed -such a statement was beyond our comprehension! We actually thought of selling -this to the Soviets to set their computer science progress back 20 or more -years. Imagine our surprise when AT&T and other U.S. corporations actually began -trying to use Unix and C! It has taken them 20 years to develop enough -expertise to generate even marginally useful applications using this 1960s -technological parody, but we are impressed with the tenacity (if not common -sense) of the general Unix and C programmer.
- -“In any event, Brian, Dennis, and I have been working exclusively in Lisp on -the Apple Macintosh for the past few years and feel really guilty about the -chaos, confusion, and truly bad programming that has resulted from our silly -prank so long ago.”
- -Major Unix and C vendors and customers, including AT&T, Microsoft, -Hewlett-Packard, GTE, NCR, and DEC have refused comment at this time. Borland -International, a leading vendor of Pascal and C tools, including the popular -Turbo Pascal, Turbo C, and Turbo C++, stated they had suspected this for a -number of years and would continue to enhance their Pascal products and halt -further efforts to develop C. An IBM spokesman broke into uncontrolled laughter -and had to postpone a hastily convened news conference concerning the fate of -the RS/6000, merely stating “Workplace OS will be available Real Soon Now.” In a -cryptic statement, Professor Wirth of the ETH Institute and father of the -Pascal, Modula 2, and Oberon structured languages, merely stated that P. T. -Barnum was correct.
So is it a hoax about a non-hoax, a non-hoax about a hoax, a non-hoax about a -non-hoax or is it a hoax about a hoax ? :) And if it’s any of those what does it -mean about Unix and C? And if a hoax is involved what is the hoax? The pedant -and Tolkienist that I am has to state that Tolkien didn’t consider The Lord of -the Rings a trilogy (and he made that very clear) but that doesn’t take away -from the humour by any stretch (if anyone wants me to elaborate or debate the -matter do send me an email - I love Tolkien’s legendarium and having another -person to talk about it with is more than welcome!). Ken suggested that there -is a lack of common sense but since he was part of its creation I don’t think -it’s a bad thing; on the contrary it makes all of us C programmers even more -talented! :) I do wonder if he tested that bit of C code though:
- - for(;P("\n"),R=;P("|"))for(e=C;e=P("_"+(*u++/
- 8)%2))P("|"+(*u/4)%2);
-
-
-How is R=; valid? Since I don’t have the context maybe there is something
-I’m missing but either way it’s a funny piece. It could also be for irony itself
-(actually I had previously thought of somehow implementing something like that
-for the contest but decided for the message by itself in the end). I would
-prefer believing that whether true or not.
I feel incredibly honoured, privileged and I am extremely happy and proud to -have won! I am more proud and happy about this than anything I have ever done in -my life and I don’t think there can be anything else I can be more proud of in -the future (except winning again should I find or think of another interesting -thing to try and implement in an obfuscated way). Because winning is one thing; -but to be included amongst very clever and talented veterans whom I highly -respect is an incredible badge of honour that I will proudly wear (literally too -as I hope to get my entry on a shirt) for the rest of my life. This type of -badge is something I feel most only dream of but never come close to earning. -That I did is by far the best feeling I can think of.
- -Thank you Simon Cooper, Landon Curt Noll and Leonid A. Broukhis, and thank you -to everyone who has been an important and special part of my life. I want to -specially name some:
- -I dedicated this program to my beloved but recently late dog Venus; instead of -drowning in grief I channelled it to creativity. And to have won a contest -requiring creativity, cleverness and novelty is a tribute to an equally -creative, clever and unique dog that she was. I miss you terribly Venus but I’m -so happy to have had you in my life.
- -But I want to also dedicate it to (and thank) my dear friend Martijn Schoemaker
-whom provided me with the spark a very long time ago (and whom has stood by me
-and helped me in more ways than he can know - #including C); if it wasn’t
-for you Martijn I wouldn’t have been able to win so consider this a recursive
-thank you thank you! :) I would also like to give thanks and much love to my
-best and closest friend Vicky Wilmore who means the absolute world to me; thank
-you for being such a wonderfully beautiful person and friend - that truly is
-what ‘just you’ means, sweetheart, and don’t you forget it! <3 Finally I would
-like to thank my mother for being the best mum anyone could ask for, who’s
-always been here for me and whom I also inherit the keen analytical mind from. I
-love you all!
I want to also thank Dave Burton for acknowledging me in his hint.markdown file -for as he put it ‘being relentless with pursuit of bugs’. To think that it was -circumstantial to my entry too makes it all the more unlikely but that doesn’t -take away the significance of it; for I am a very symbolic person and being -acknowledged for this type of thing is great but to be acknowledged for it by -someone who has won more than once is even more special to me: thank you Dave! -It means a great deal to me and I am glad I could help! :)
- -I would also like to say to the judges about their commentary as well as the -category title: they’re all very dear to me and that includes not just the -remarks but the example invocations. They fit my views precisely. As for the -test-strings.txt file modifications: very amusing and I certainly do not object. -Thank you again for such an honour and privilege! That this isn’t a dream is the -best reality imaginable! :)
- -Congratulations to one and all for winning; it’s an honour to win such a -wonderful contest requiring creativity, cleverness, uniqueness and -inventiveness but to win beside all the other wonderful entries is truly -special!
- -Shortly after the entry has been published I will have more information on the -winning entry at https://ioccc.xexyl.net/2018/weasel including how to -contact me (besides what’s already published on the IOCCC website). There also -is an errata page so that in the case I find anything I would like to -correct in the documentation or other supplementary files I can note them there.
- -If you wish to contact me please do so; although I have a Twitter account I don’t -really use it so please send me an email instead. I do have Facebook as of a -little under two years but I’ll worry about that at such a time (I presume in -fact ‘if’) it becomes relevant.
- -![]() |
-© Copyright 1984-2018,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Edward Giles
- -sudo apt install libsdl2-dev # Linux
-Something else # MacOS
-make
-./prog
-
-
-./prog ioccc.txt
-./prog prog.c
-
-
-Can you explain the behavior of the program when ioccc.txt is given to it as input?
- -How would the description of the state machine look like when translated from -Polynomish to English?
- -This entry graphically displays a simulation of sand falling. -It uses SDL to draw the interface.
- -The code makes the following assumptions about the underlying system:
- -In order to simulate the motion of the sand, a cellular automaton is used. The -state transition table is not stored directly. Instead, the program stores the -coefficients of a polynomial that map each state to the correct one. These -coefficients are stored as raw hexadecimal in the V[] array, and they are -reinterpreted as doubles when used. This allows more numeric precision in fewer -characters (base 16 > base 10), and makes the purpose of the array less clear.
- -The code is laid out graphically as a bucket pouring sand, and it is far easier -to observe this high-level layout than the code’s actual function.
- -The preprocessor is used to both obfuscate the code as a whole and abbreviate -the calls to SDL. Additionally, throughout the code, the variables were named -so that they are short and easily confused with each other.
- -![]() |
-© Copyright 1984-2018,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Qiming HOU
- -make
-./prog < input.json > output.html
-
-
-View output.html in a browser.
grep -e '[-?+*/^&|.<>=]' prog.c
-
-(cd ..; ls -lS */prog.c) | \
-awk 'BEGIN { print "["; } { print "{\"winner\":\"",$9,"\", \"size\":",$5,"},"} END { print "]"}' \
-> ioccc.json
-./prog < ioccc.json > ioccc.html
-
-
-What’s not right with the output? How to fix it?
- -This entry exhibits a way of obfuscation we haven’t seen before, we think. -The rulez of programming in an imperative language are violated, aren’t they?
- -Try figuring out how to increase the number of different colors, if you can.
- -Nowadays almost every programmer needs to do some Web chore. With all the open source stuff readily available, often we just need to call a bunch of libraries to generate an HTML page from a JSON feed.
- -This entry takes such decadence to an extreme. It just calls a bunch of libraries to generate an HTML page from a JSON feed, literally. There is no variable (function parameters included), no operator, no flow control statements except a few decorative returns. In compliance to production coding standards, the code is littered with fashionable jargon, doxygen comment, and license text.
- -As one would expect from such an approach, this program is much more resource intensive than it should be. And one needs a C99-compatible libc (with the common UNIX stuff) to build this and an HTML5-compatible browser to open the result. And it terminates with an assertion failure, but who cares if the web page is already generated?
- -![]() |
-© Copyright 1984-2018,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Christopher Mills mrxo@sonic.net
-Twitter: @MisterXopher
make
-./prog
-
-
-make
-./prog
-(At the ">boot" prompt, type return)
-(At the ":" prompt, type "rk(0,0)rkunix")
-NOTE: To quit, press Control-E
-
-
-Do small machines only need small programs? This program weighs in at just -3636 bytes, which is considerably lighter than the original machine it can replace.
- -This program can take you back to the start of everything, it is possible to -run v0. Just type:
- -make
-./v0
-
-NOTE: To quit v0, press Control-E
-
-
-You will be greeted with a familiar prompt of “login”. The username and -password are “dmr” and “dmr”. To make things more familiar you’ll need to -create ‘.’ as it hasn’t been invented yet on this image!
- -@ ln dd dmr .
-
-
-An “ls” will reveal that C hasn’t been invented yet! IOBCC anyone? The -compiler is “bc”. It producess assembly, which will then need to be assembled -together in this order “ops.s bl.s hello.s bi.s” to produce a.out!
- -But wait, we said this was the start of it all! This program can also run a -program that replaces an even larger machine that can run BSD 2.9. To start this,
- -make
-./prog
-
-(At the ">boot" prompt, type return)
-(At the ":" prompt, type "rk(0,0)rkunix")
-NOTE: To quit prog, press Control-E
-
-
-This should now be very familiar and it is possible to compile and run one of -the very first IOCCC entires “mullender.c”
- -But wait, there is even more! Try:
- -make
-./v6
-
-(At the "@" prompt, type "rkunix")
-NOTE: To quit v6, press Control-E
-
-
-- -This IOCCC entry is dedicated to the late Dennis M. Ritchie
Since this is the 25th “annual” IOCCC, I thought I should mark the occasion -with a look back to its earliest roots. At the same time the contest enters -its 34th year of providing a safe forum for poor C code, the C language -itself is fast approching its 50th anniversary, along with the UNIX operating -system whose history is so entwined with.
- -The program delivered here is both a full machine emulation of the original
-PDP-7 that Ken Thompson used to write the first version of UNIX and a full
-machine emulation of the PDP-11/40 used by subsequent UNIXes. The Makefile
-can build versions that can run each of the following:
For reasons to be described in a bit, the last (BSD 2.9) is the default.
- -To run BSD 2.9, do make to build prog and then ./prog to run it.
You should see a prompt from the first-stage bootloader that looks like
- - >boot
-
-
-Type RETURN at this point and you will get to the second-stage boot loader
-that looks like
40Boot
- :
-
-
-The 40 in the prompt indicates that the bootloder has correctly determined -that we are running on a PDP-11/40.
- -At this point, type the rather cryptic command rk(0,0)rkunix – this tells
-the system to look at the first partition on the first RK05 fixed disk, find
-the rkunix file and load it. You should eventually see the following:
>boot
-
- 40Boot
- : rk(0,0)rkunix
-
- Berkeley UNIX (Rev. 2.9.1) Sun Nov 20 14:55:50 PST 1983
- mem = 135872
-
- CONFIGURE SYSTEM:
- xp ? csr 176700 vector 254 skipped: No CSR
- rk 0 csr 177400 vector 220 attached
- hk ? csr 177440 vector 210 skipped: No CSR
- rl ? csr 174400 vector 160 skipped: No CSR
- rp ? csr 176700 vector 254 skipped: No CSR
- ht 0 csr 172440 vector 224 skipped: No CSR
- tm 0 csr 172520 vector 224 skipped: No CSR
- ts 0 csr 172520 vector 224 skipped: No CSR
- dh ? csr 160020 vector 370 skipped: No CSR
- dm ? csr 170500 vector 360 skipped: No autoconfig routines
- dz ? csr 160110 vector 320 skipped: No CSR
- dz ? csr 160110 vector 320 skipped: No CSR
- dn 0 csr 175200 vector 300 skipped: No autoconfig routines
- vp ? csr 177500 vector 174 skipped: No autoconfig routines
- lp ? csr 177514 vector 200 skipped: No CSR
- Erase=^?, kill=^U, intr=^C
- #
-
-
-Congratulations, you are running BSD UNIX 2.9 in single-user mode as root.
- -On the other hand, if you did a typo somewhere, the boot loader has probably
-crashed and halted – if so, type Control-E to quit the simulation and try
-again. If you did really badly, you might have corrupted the virtual disk.
-If so, consider a make clean to start from scratch.
Assuming you managed to type 15 characters correctly, You should be at the -root prompt. Most of the commands you are familiar with work here (this was -only a quarter of a century ago – how much could things have changed?). -Let’s try some:
- - # ls
- .cshrc .profile boot hkunix mnt tmp
- .login 2.9stamp dev lib mullender.c unix
- .msgsrc bin etc lost+found rkunix usr
- # df
- Filesystem Mounted on kbytes used free % used
- /dev/rk0 / 1958 1688 270 86%
- # cc mullender.c
- # ./a.out
-
-
-The program you’ve just run was the winner of the first IOCCC contest from -1984 (or was it 1894?), a personal favorite of mine. It is rather -tightly bound to running on either a PDP-11 or a VAX. Now you have one.
- -Hitting Control-C will return you to the BSD UNIX prompt. Hitting Control-D
-will log you out of the single-user session and get you back to the :login:
-prompt. Here you can log in as root and get a full timesharing session.
-Feel free to try things like vi. I’ve taken the liberty of editing the
-.login and .profile files to set the console to a less traditional setup
-so that you don’t have to wait for the Model 33 KSR teletype to move its
-carriage. I’ve also predefined TERM to vt100, which will probably work
-well enough with whatever sort of ANSI terminal emulation you are using.
Note that I have not mounted the /usr disk here, so some commands from
-/usr/bin will be missing, along with all of the man pages. They are
-available online if you need them. Adding a second RK05 disk was
-possible, but I didn’t get around to it… As the Judges can no doubt attest,
-“Mid 2017” creeps up on you quicker than you expect. :)
Once you’ve had enough fun in BSD 2.9, type Control-E to exit the emulation.
- -Research UNIX v6 and BSD 2.9 use the same executable, but require a different
-disk image. Type make v6 to build it, then type ./prog to run it.
You should see the boot loader prompt which is a single @:
@
-
-
-At this point, you again must type a special incantation: rkunix. After that
-you should see:
@rkunix
- mem = 1035
- RESTRICTED RIGHTS
-
- Use, duplication or disclosure is subject to
- restrictions stated in Contract with Western
- Electric Company, Inc.
- #
-
-
-You are now running a single-user session of v6 UNIX. You might want to start
-with stty -lcase because otherwise everything will be IN ALL CAPS.
Again, if you failed typing seven characters without making a mistake, you -may need to use Control-E to quit the simulation.
- -Assuming you’re more careful than that, we can try a few commands:
- - @rkunix
- mem = 1035
- RESTRICTED RIGHTS
-
- Use, duplication or disclosure is subject to
- restrictions stated in Contract with Western
- Electric Company, Inc.
- # STTY -LCASE
- # ls
- bin
- dev
- etc
- hpunix
- lib
- mnt
- rkunix
- rpunix
- tmp
- unix
- usr
- # cat > foo.c
- main()
- {
- printf("Hello, World!\n");
- }
- # cc foo.c
- # ./a.out
- Hello, World!
-
-
-Why is Version 6 interesting? Well, it was the oldest version that I could
-find a boot image of that had a C compiler… This C compiler is recognizably
-C, but not quite the same syntax as we have today. It’s much closer to the
-B language from which it is derrived. In particular, this C compiler
-would not be able to compile mullender.c (as simple as it is), because the
-following syntax features don’t exist yet:
short data type doesn’t exist yet. Only int (short will show
-up when long comes, and the port to the Interdata 7/32 starts to make
-the idea of portability become important).=. It still uses
-the older form taken from B, which looks like array[] { 1, 2, 3 };It can still compile “Hello World!” (note that you must type a Control-D after
-you finish entering the code, to let cat see an end-of-file).
This version of UNIX doesn’t go into multi-user mode if you do a Control-D. -Single-user mode was entered because the front-panel console switches were -set to the magic number 0173030 (this can be changed with a re-compile).
- -Once you are done with Version 6, Type Control-E to exit the simulation.
- -Note that since both BSD 2.9 and UNIX v6 use the same PDP-11/40 emulation
-code, and they use the same name for the disk (rk05.fs), if you want to go
-back to the BSD simulation, you should either delete rk05.fs or do a
-make clean before you do a make.
We now set the Wayback Machine to the very start of it all, 1969.
- -The story here is interesting and well worth a read. Bell Labs was -pulling out of the Multics project and Ken Thompson and his collegues had -become accustomed to the relatively nice programming environment. They also -enjoyed the early computer game Space Travel and wanted another system -to run it on. They found a PDP-7 which was already obsolete at the time to -port Space Travel to. The primitive programming environment influenced -Thompson to recreate parts of the Multics experience in the much more -hardware-constrained PDP-7 environemnt. In the summer of 1969, with his wife -out on a month-long vacation, Thompson re-wrote a filesystem emulation he had -been experementing with to include an assembler, a shell, an editor and an -operating system kernel and hence created the first version of UNIX (although -it hadn’t been named that yet).
- -You can try out this version by typing make v0. Since this version is a
-native PDP-7 emulation, it gets its own binary. Type ./v0 to run it. You
-should see the login prompt.
login:
-
-
-There are two user accounts ken and dmr, with the passwords ken and dmr
-respectively. Let’s try the Dennis Richie’s dmr account:
login: dmr
- password: dmr
- @ ls
- . ?
-
-
-Even though this is not Ken’s doing, I feel this gives me licence to
-include this quote from the BSD fortune program:
- -Ken Thompson has an automobile which he helped design. Unlike -most automobiles, it has neither speedometer, nor gas gauge, -nor any of the numerous idiot lights which plague the modern -driver. Rather, if the driver makes any mistake, a giant “?” -lights up in the center of the dashboard. “The experienced -driver”, he says, “will usually know what’s wrong.”
What’s the deal here? Well, that’s a slightly long story. The short version
-is we have gone so far back in the history of UNIX that we don’t have
-filesystem paths yet. In other words, we can’t say something like
-/bin/ls yet, and the shell can’t store that path in $PATH to search for it.
-We also haven’t invented . or .. yet. In fact, the filesystem isn’t even
-the traditional UNIX tree structure, it’s a directed graph of hard links…
ls needs to be able to read ‘.’, the current directory. dmr’s home
-directory doesn’t have that yet, but we can make it, because the home
-directory has a hard link to dd, which is the directory that holds all
-of the user home directories (this will eventually become /, the root
-path). We can do
@ ln dd dmr .
-
-
-To make the new link (note that ln doesn’t support paths either, so you have
-to give it three arguments – a directory in the current dir, a file in that
-directory, and the new name).
Now ls will work, and we can try some other things while we are here:
login: dmr
- password: dmr
- @ ln dd dmr .
- @ ls
- dd
- system
- as.s
- b_readme
- bi.s
- bl.s
- db.s
- hello.b
- ops.s
- .
- @ cat b_readme
- Here is how to compile and run hello.b:
-
- @ bc hello.b hello.s
- @ as ops.s bl.s hello.s bi.s
- I
- II
- ops.s
- bl.s
- hello.s
- bi.s
- @ a.out
- Hello, World!
-
-
- @ bc hello.b hello.s
- @ as ops.s bl.s hello.s bi.s
- I
- II
- ops.s
- bl.s
- hello.s
- bi.s
- @ a.out
- Hello, World!
- @
-
-
-The last command is invoking the compiler for an exteremely early version of -the B programming language, the predecessor to C. Thompson missed the -convinience of writing code in a high-level language – Multics was written -a version of PL/1 – and wanted the same convinience on UNIX. He preferred -BCPL (a typeless language) to PL/1. As Dennis Ritchie wrote:
- -- -B can be thought of as C without types; more accurately, -it is BCPL squeezed into 8K bytes of memory and filtered -through Thompson’s brain.
A look at the B reference manual will show the strong correlation with C, and -shows the source of a lot of C’s mysteriousness – some of which is preserved -simply so that C could compile the dozens of lines of existing B code…
- -Thompson’s assembler was also extremely simple. It didn’t even know about
-opcodes – these need to be defined in the first assembly file, with the
-assembler OR-ing the opcode fields together (space was the “operator” for
-logical OR). There is no link step – all files are provided to the assembler
-on the command line, concatenated together and assembled, producing a single
-a.out (assembler output) file. Even after UNIX got a linker, a.out
-remained the default name of the binary generated by the linker (and hence
-also by cc).
This system is still has the familiarity of UNIX, with all the two- and
-three-letter commands, device files, shell redirection, the same core system
-calls (read, write, open, close, creat, fork, etc.). There are a
-number of differences still:
read and write do I/O on (18-bit) words. Character I/O to files needs
-to unpack those to bytes, and of course deal with NUL characters.exec was performed by the shell directly. Arguments are passed as
-four words (eight bytes), and space padded. This matches the format for
-file names for open and creat.wait does not yet exist. A more complicated mechanism for sending and
-recieving messages (smes and rmes) are used instead.As usual, when you are done exploring UNIX v0, type Control-E to exit the -simulator.
- -The program came about when I was looking for something to honor the pending
-50th anniversary of the C language (because of the mercurial nature of IOCCC
-contest scheduling, I chose not to wait for the actual 50th anniversary).
-I had though of writing self-hosting compilers for a stripped-down version of
-C, or maybe even a version of the B language… At the same time, I was
-obsessed with the idea of allowing mullender.c from 1984 to run. Although
-that was still a possibility on an interpreted version of B or a stripped-down
-version of C, it felt cheap, as it would be mullender.c only in spirit.
It was during this time that I discovered that in 2016, members of the Unix -Heritage Society got access to printouts of assembly-language source for the -original version of UNIX. With what was a huge amount of work, -they scanned in the printouts, fixed up the OCR translations, built assembler -and file system tools from scratch and made an accurate simulation of -Thompson’s PDP-7 that allowed them to get the system up and running. Although -source for the entire kernel and about half of the user-space commands were -present (including the runtime and libraries for the B compiler), the -remainder needed to be written from scratch, including the shell. The final -results of the project are available on github.
- -None of this was remotely easy (as I was to discover myself). The PDP-7 is -long gone, and the documentation for it is less complete than one would like. -In addition, the devices attached for it were a bit of a mystery. The disk -system is referenced only in an old price list. It was a RB09 fixed disk, -probably made by Burroughs. It is close to what was called the RC10 for the -PDP-10, but with a different interface. And the system also included a custom -display device called Graphics-2, which had been built in-house by AT&T. -It can’t be completely ignored, because the kernel itself pokes at it (the -UNIX crew used it as a second terminal – a “glass TTY”).
- -I decided that implementing this PDP-7 would be possible as an IOCCC entry.
- -The emulator emulates the full machine:
- -The PDP-7 is an odd duck by modern computer standards:
- -ADD for one’s complement
- and TAD for two’s complement). The EAE is entirely one’s-complement.XCT instruction, that executes the word loaded from memory as an
-instruction.LAW that loads the instruction opcode into the
-accumulator.MUL instruction expects
-the second operand to be stored in memory after the instruction. This
-pretty much requires the use of self-modifying code.The simulation handles everything I was able to discover about the PDP-7, even -things that the UNIX code itself doesn’t use. For instance, it correctly -implements the “trap mode” feature (a primitive form of supervisor mode) even -though the kernel does not enable it. It also implements the microcoding of -the EAE instructions even though the UNIX environment uses only the standard -encodings. If you wanted to do a 11-bit multiply instead of an 18-bit one, -it will probably work.
- -The simulation starts by loading a boot program off of the virtualized paper
-tape, which is in a modified version of the RIM boot loader format. The
-RIM format encodes each 18-bit word as three six-bit characters, using one bit
-to denote the final word (which is executed directly and is usually a JMP or
-HLT instruction). The load address comes from the console address switches.
-Both of these are controlled by compile-time flags.
The emulator continues emulating instructions until it sees a HLT instruction
-which will cause it to exit. Console I/O is emulated by setting the terminal
-into raw mode and polling via read. Line-clock ticks (at 60 Hz) are done
-by polling gettimeofday. Dynamic frequency code arranges to reduce the
-polling interval to a few polls per tick, so that simulation remains
-responsive. Since we use the real wall-clock time, this means that the
-emulated system will see time advance at the correct rate.
So now I have a system that can run UNIX v0. One problem remains… I don’t -have permission to submit UNIX v0 to the IOCCC. It is not my code and the -copyright for it remains the property of whoever owns that part of what was -once Bell Labs – I believe it is Nokia at this point. I have worked around -this problem in two ways:
- -First, I didn’t submit the source code or binary image for v0 UNIX as part of
-my IOCCC entry. I merely submitted a Makefile that can issue a curl
-command to fetch a prebuilt v0 disk image from the github repository. I am
-hoping this is considered part of “Legal abose of the rules” which is supposed
-to be “somewhat encouraged”. As per RULE 12, I am justifying said abuse here,
-in the remarks file.
Secondly, the choice to run the UNIX v0 code is optional. If you are worried
-about Nokia’s lawyers running you to ground for running a 50-year old copy
-of a binary image for a machine that is almost completely nonexistant, you
-can just not do so. Delete the lines from the Makefile and sleep well.
-You still have two other UNIXes to play with.
What about the other two UNIX variants? These are both covered by licences -that allow me to use them. Back in 2002, Caldera International released -Research Unix versions 1-7 and 32V under a permissive BSD-like license. -BSD UNIX is based off of v7 UNIX, and of course has its own permissive -BSD licence. And in 2017, Nokia also released versions 8-10 under the -condition that it will not assert copyright rights for non-commercial use.
- -So the newer UNIXes are in the clear. I doubt anyone actually cares about -version 0 either, but technically it’s still under copyright.
- -So if I have a PDP-7 emulator, how do I run operating systems that expect a -PDP-11? Simple… I emulate a PDP-11/40 on the PDP-7. I have written -PDP-7 assembler code to emulate a PDP-11/40 with the following equipment:
- -This required a few tweaks to the emulator. The first problem is that the
-RK05 disk is about 2.5 MB, but the RB09 is only about 2 MB. That’s easily
-solveable – just add more tracks to the RB09. UNIX v0 is unlikely to notice
-(although the number of tracks is a compile time parameter, and the v0
-build commands set it to the correct value).
The second problem is that we are simulating a system that can have up to -124 Kwords of memory on a system with only 8 Kwords total. That meant I needed -to virtualize the PDP-11/40’s physical memory (and add a few more tracks to -the disk to hold the virtualization).
- -A large amount of time was spent tuning this code to be efficient. The -memory virtualization uses part of the 8 Kword memory as an LRU cache, and -uses a number of first-level microcaches to avoid having to do the LRU updates. -This also serves to offload the complexity of the PDP-11’s segmentation logic -from a large number of memory accesses (the PDP-11 does as many as eight -accesses per instruction). Despite the super fast emulated disk, the PDP-7 -code in the emulator is slow, mostly because it has to do a bunch of divides -to convert the linear disk offset into a BCD-coded track and sector for the -emulated RB09. I/O polling is again used, except this time it uses the -PDP-7’s “skip on flag set” I/O instructions. As with the PDP-7 emulator -itself, the PDP-11 emulator dynamically measures the instruction throughput -relative to the line-clock tick, so that it only polls for I/O a few times -per tick.
- -The one remaining problem is building the disk images themselves. Since the
-PDP-11’s disk is 16-bit, but the PDP-7’s is 18-bit (which the emulator stores
-in 32-bit ints), a conversion program is needed to unpack the binary disk
-images from 16 bits per word to 32. This in turn needs to be done in the
-Makefile using standard POSIX tools, which aren’t exactly good with binary.
-I had a wierdly clever way to do this with od, awk and uudecode that
-I will leave as an exercise for the curious, but I decided it would be easier
-to do it with the PDP-7 emulator itself, feeding a simple program in on its
-boot tape. This required an additional tweak to the emulator, since by default
-its console TTY is not eight-bit clean (in fact, UNIX v0 expects to see the
-MSB set on the terminal reads, and sets it on writes, what is called “mark”
-parity). This is also enabled by a compile-time setting (used only for the
-builddisk program).
Despite the complexity of the PDP-11 instruction set and its emulated I/O -devices and the corresponding primitiveness of the PDP-7’s instruction set, -the emulation itself is a suprisingly small amount of code, not really taxing -the 8 Kword memory, with about 2.25 Kwords of actual code and a similar -amount of space for the memory virtualization cache and disk block buffer, -leaving nearly half (3.5 Kwords) of the memory unused. The simulator executes -somewhere around 250 PDP-7 instructions per PDP-11 instruction. On my laptop, -the PDP-7 is running somewhere in the neighborhood of 70 MIPS, which means the -PDP-11 is running at about 0.3 MIPS, which is probably not too far off of its -actual speed (the cycle time of an 11/40 was around a microsecond for simple -instructions, but could be proportionally larger for instructions that did -multiple memory accesses, which many did).
- -As an aside, although the idea of emulating the PDP-11 on an emulated PDP-7 -came about from the realization that I needed a response to the late-discovered -licence issue, I’m quite pleased with the result – it enables an interesting -window on the dawn of the UNIX era. I feel that someone should complete the -circle here by emulating a VAX 780 on the PDP-11 and run 4.2BSD on it, so that -we can get the original runtime environment used for the first IOCCC.
- -The following command flags control the compilation:
- --DI="image.fs": Name of the disk image file. This must be created
- offline, and be of the correct size to avoid segmentation violations.-DA=4096: Setting of the console address switches. This tells the RIM
-bootloader where to load the boot image.-DS=0: Setting of the console data switches. The PDP-7 emulation can
-read these with the microcoded OAS (OR switches into AC) instruction.
-By proxy, the PDP-11 emulation can read them via the CSW device.-DW=MAP_PRIVATE: This sets the memory mapping for mmap. Setting to
-MAP_PRIVATE makes the disk image be copy-on-write. Setting it to
-MAP_SHARED makes the disk image be sharable. Do the latter if you want
-to preserve the disk contents between sessions.-DT=: List of initializers for the termios structure. The v0 UNIX
-expects the terminal to be in half-duplex mode, echoing its input, with
-swapped CR and NL. The PDP-11 UNIXes don’t.-DX=5: The ASCII code of the control character that causes the simulation
-to abort. If set to 0, there is no abort code.-DY=128: Controls console I/O parity. If set to zero, the console is
-eight-bit clean. If set to 128, the high bit is set on keyboard reads and
-masked off on printer output (“mark” parity). UNIX v0 expects the latter.-DV=270: The size of the disk, in tracks. The UNIX v0 disk has 200
-tracks (each has 80 sectors of 64 18-bit words). The PDP-11 UNIXes
-increase this to 270, to allow for the larger RK05 disk emulation
-(406 tracks of twelve 256-word sectors), plus the space for the 124 Kwords
-of virtualized memory and the 8 Kwords of emulator code.-DP="xxx": RIM bootstrap program paper tape image. Be careful with the
-quoting here – there is at least three levels going on. In particular,
-you will need to escape $ as $$ to protect it from make.The ASCII art represents a torn piece of paper tape.
- -None of this could have been possible without the hard work of
- -Finally, thanks to my spouse for putting up with the many hours I spent on this -nonsense, and treating “I’m working on my IOCCC entry” as an acceptable answer -to queries about how I was spending my free time. Similarly, I apologise to -those friends and coworkers who had to listen to me complain about obscure -corner-case bugs in my code. The obsession is over, at least until next -time…
- -![]() |
-© Copyright 1984-2018,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Timo Poikola ioccc2018@ig.fi
-https://ig.fi/
make
-
-./prog
-
-
-On terminal supports 24 bit color, has black background, and size at least 125x38, try:
- -./prog
-
-
-It is said by some students of Astronomy:
- -Oh, Be A Fine Gal, Kiss Me!
-Oh, Be A Fine Gentleman, Kiss Me!
-
-
-Many Mnemonic variations exist. -You might wish, on a star, to better understand the colors being displayed. -And those in the deep south might wish to go north for a better view.
- -gcc -o prog -std=gnu11 -O3 prog.c
-
-
-or
- -make
-
-
-You can generate an A3 sized poster by make docs. This command creates a pdf file poikola.pdf.
- -It was a starry night when my wife pointed her finger up and asked: “What is this star and may I have some Easter eggs?”
- -So I had to sit down and solve those tricky questions with Nano and a C compiler.
- -Basically, the program draws animated ASCII art of the Big Dipper using Annie Jump Cannon’s spectral classification system of stars and I think the -colors of the output are as accurate as possible.
- -This program also tells once in a year if it is correct time to find and eat some Easter eggs.
- -The program has also at least three other functions, obvious and not so obvious.
- -This program has been tested on xterm and Konsole and also Linux virtual terminal. Color support in the terminal is not necessary, but the effect is better with it. -This entry has partial support for terminals with a white background but the best viewing experience is achieved when the terminal in use supports 24-bit colors, -has a black background and the size is at least 125x38.
- -Special note for Mac users: Terminal does not work as expected you might need xterm from XQuartz or some other -working terminal. Thanks to Dave Burton for spotting this problem.
- -The main reason for the header unistd.h is getdelim() but once I included it I also abused other functions and defines. This header is mutually exclusive with -std=c11.
The program was developed with little-endian machines; I tried to support big-endian too, but this support is somewhat limited.
- -This program has been compiled in
- -Please do not feed little babies chocolate.
- -I incorporated the Fletcher 16 checksum algorithm into the source for security reasons; it might be challenging to make changes without breaking the main functionality of the code.
-The space after #define p return is necessary.
The computus uses an algorithm described in the journal Nature in 1876. It should be valid for Gregorian calendars.
- -o, b, and a are used in totally unrelated tasks.__ATOMIC_SEQ_CST.begin; and end; instead of curly brackets.
-They are used also in my code, but I had to shorten them to meet size requirements.$, but then I rejected it.If you think you understand how this program works, can you answer these questions:
- -aI_ after line 21?Because the rot13 is too easy to decode with the plain eyes, I decided to use the Caesar cipher with the key 18.
- -Lzw xajkl tsffwj ak wfugvwv mkafy AWWW 754 xdgslk gf dafw 47. Al ak hjaflwv gfdq gf dalldw-wfvasf esuzafwk.
- -![]() |
-© Copyright 1984-2018,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Scott Vokes
-Twitter: @silentbicycle
make
-./prog < example-1.txt
-
-
-./prog < example-2.txt
-./prog < example-tab.txt
-./prog < ioccc.txt
-
-
-What this program does is not witchcraft and there are no spectres, but you -might have a meltdown trying to work it all out.
- -This entry is designed to mislead in many ways. However, if you find yourself -wanting to know the possibilities for navigating a graph, you will get the -answer you seek with no hocus pocus.
- -This program reads a directed graph (as lines with integer node IDs), -and prints the graph’s nodes in reverse-topologically sorted order, -grouped into strongly connected components. Given a set of nodes -representing targets and edges representing dependencies between them, -it produces a build order with any dependency cycles gathered.
- -For example, the following input (provided as example-1.txt):
0 4 8
-1 0
-2 1 3
-3 2
-4 1
-5 4 6
-6 5 2
-7 3 6 7
-
-
-would be interpreted as:
- -0 -> 4, 8
-1 -> 0
-2 -> 1, 3
-3 -> 2
-4 -> 1
-5 -> 4, 6
-6 -> 5, 2
-7 -> 3, 6, 7
-
-
-So, node 0 has edges to / depends on nodes 4 and 8, node 1 depends on -node 0, and so on. Then, it groups the graph’s nodes into -strongly connected components and prints them in reverse-topologically -sorted order:
- -0: 8
-1: 0 1 4
-2: 2 3
-3: 5 6
-4: 7
-
-
-It uses Tarjan’s strongly connected components algorithm for the -grouping and reverse-topological sorting, along with a bonus hidden -implementation of counting sort, which sorts each group.
- -For other details about the input format, see “Issues and -Limitations”.
- -To build:
- -${CC} -o prog prog.c -std=c11 -O3 \
- -Wall -Wextra -pedantic -Wno-missing-prototypes
-
-
--Wno-missing-prototypes is necessary because there aren’t any
-prototypes. (They would put the program well over the size limit.)
Note: The program can also be built with -std=c99 or -std=c89.
If building with -Weverything, then -Wno-strict-prototypes
-may also be necessary – the function pointer declarations for
-_ and B may get warnings otherwise, for reasons described
-under “Obfuscations”.
This entry uses functions that have a variable number of arguments,
-but despite what the rules say, there is no need to be careful about
-va_list implementation differences. :) . There are several
-references to a function pointer, _, but it’s called with different
-numbers of arguments in different places. (In particular, look at
-spell.) Because the function pointer declaration has an empty list
-of parameters, the argument count and types are unconstrained. _ is
-set to different functions in several places, but it is always called
-with appropriate argument(s) for its possible current functions. This
-is allowed by the standard – The section on F,I,N,D,M,Y,C,L,U,E has
-further details.
It uses _ in three different scopes: as a goto label (function
-scope), as an enum name, and a _ function pointer (which is required
-to have file scope, since it starts with ‘_’). There are also other
-_s: it appears in a string, obscured by a headecimal escape sequence
-(\x5f), and the cauldron is supported by a giant underscore.
-(Does this program qualify for Best One Liner?)
Most of the variables are not only global, but used for unrelated -purposes at different times, so just renaming them while studying the -program should make it even more confusing. The few variables local to -functions have their names reused for different things in other -functions.
There is an enum early on that defines several single-letter -identifiers: F,I,N,D,M,Y,C,L,U,E. These are used for array offsets, -both individually and in combination. The first several values are -also a clue: ISO/IEC 9899:1999 chapter 6.7.5.3 verse 14 describes how -function declarators with an empty parameter list behave. (As does -3.5.4.3 for ANSI C, which explains the 0x3543 that appears soon -after.)
Several parts of the program’s state are stashed in otherwise unused
-offsets of the node arrays. These locations are accessed in multiple
-ways, such as using I[p] (where I == 7) as well as p[F+L] (6+1),
-or b[M-N] (14-5) and U[b] (where U == 9).
The other identifiers are misleading, punny, or both. spectre does
-not exploit CVE-2017-5753 or CVE-2017-5715, for example – it just fits
-the witch theme. cast doesn’t cast, hex has nothing to do with
-hexadecimal, bubble is not bubble sort, there is no undefined
-behavior in nasal_demons, and main has absolutely nothing to do
-with a hand.
For well-formed input, how the program determines when to exit is a
-bit obscure. main ends with a goto leading back to an earlier _
-label, so it just loops forever, and exit only appears in code paths
-related to error-handling. It looks like cast calls meltdown with
-its second argument set to 0, which would call exit, but running in
-gdb with a breakpoint on cast reveals that it isn’t being called…
Instead of using isdigit(), the program checks the numeric value of
-each char, and literals that would suggest comparing against e.g. ‘0’
-are specified in octal in one place, and produced by arithmetic using
-the enum elsewhere.
Common conventions are subverted: i is not a loop index, argv and
-argc’s names are swapped.
NULL does not appear in the program. Instead, argc[argv] (which is
-required to be a null pointer) is saved and passed to where its value
-is needed.
Oh, and the program is squashed into the shape of a bubbling cauldron, -on top of a giant underscore, so there’s that.
Despite appearances, it does not handle numbers in hex, or provide
-a curses(3)-based interface.
The expected input format is zero or more lines of space-separated -integers. If other characters appear in the input, it will either -reject the input entirely and exit with a non-zero status, or skip -number(s) adjacent to the non-digit characters, depending on where the -characters appear. Tabs and multiple consecutive spaces are handled -correctly, however.
Individual lines of input longer than 0x3543 - 1 bytes will be
-split and processed as if they were multiple lines of input, which can
-produce incorrect results. This magic number’s significance is
-described earlier.
The algorithm expects its input to represent a fully connected graph. -While the output is otherwise topologically sorted, if there are nodes -completely unconnected to the rest of the graph (with or without -self-cycles), they will be output as soon as they are processed – -this means that, when there are disconnected nodes, reordering the -input lines can produce different output. Addressing this by adding -another pass is would put the program over the size limit.
While the node IDs don’t need to be consecutive or start at 0, the -implementation doesn’t have special handling for sparse graphs. If you -give it a graph with nodes numbered 0 and 2147483647, it will attempt -to allocate sufficient memory (potentially around 32 GB) for the -entire range of graph nodes, even if those are the only ones. If -memory allocation returns NULL, it will gracefully exit, otherwise it -will succeed, eventually, perhaps after a great deal of swapping.
Node IDs >= 2147483648 will cause the program to print an error -message and exit with a non-zero status. This shrinks the code that -detects overflowing the array size by a bit.
A very large group of nodes in a cycle can cause a stack overflow. -This typically takes over 100,000 nodes, and depends on the order the -nodes are visited. Addressing this would put the program over the size -limit.
The implementation depends on the characters ‘0’, ‘1’, … ‘9’ having
-the values 48 through 57, rather than using isdigit(). As noted
-above, this program has nothing to do with a hand.
![]() |
-© Copyright 1984-2018,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Don Yang
-http://uguu.org/
make
-more generated1.c
-more generated2.c
-more generated3.c
-
-
-make
-./left < prog.c
-./right < prog.c
-./left < prog.c | ./left
-
-./shift < prog.c
-
-./msg0
-./msg1
-./msg2
-
-
-Code should be readable in any direction! This tool will help you rotate your -code so you don’t have to stare at it sideways or even upside down. Rotating -this program left and recompiling will reveal other tools including a right rotate -and a shift program.
- -Strange things happen when the world is upside down! It is entirely possible -that this is remark is completely misleading.
- -What exactly does the shift program do?
- -Like a great sliding puzzle (hint) this entry has 6 more programs that will -reveal messages and one more tool that can be used to reveal the final -message hidden in the original source. All of these can be created using -combinations of ./left, ./right and ./shift and the additionally generated -programs.
- -The final message can be revealed using
- -./msg9 < prog.c
-
-
-But what combinations will generate ./msg3, ./msg4, ./msg5, ./msg6, ./msg7, -./msg8 and finally ./msg9?
- -Nuko is a text rotator: given some text in stdin, Nuko will write the -same text to stdout, but rotated 90 degrees counterclockwise.
- -gcc prog.c -o left
-./left < input.txt > rotated_counterclockwise.txt
-
-
-Due to static memory allocation, only the first 1K columns by 1K rows -are rotated, the rest are silently ignored. But fear not, a separate -tool with dynamic memory allocation is included:
- -./left < prog.c > r1.c
-gcc r1.c -o right
-./right < input.txt > rotated_clockwise.txt
-
-
-For variety, this second tool rotates clockwise instead of -counterclockwise. Also, it can handle files larger than 1024x1024, -depending on how much memory you got.
- -Of course we wouldn’t stop with just two rotations, if we continue to -rotate counterclockwise once more, we get another program. This -program outputs a single message to stdout, which is the name of the -series that Nuko came from.
- -./left < prog.c | ./left > r2.c
-gcc r2.c -o msg0
-./msg0
-
-
-There is one final rotation, which produces a tool that removes -leading whitespaces:
- -./left < prog.c | ./left | ./left > r3.c
-gcc r3.c -o shift
-./shift < input.txt > no_leading_space.txt
-
-
-Where this might be useful, besides ruining the formatting of certain -files, is that it completes the set of tools needed to solve the -puzzle that is embedded in prog.c
- -Notice how the edges of prog.c contain two notches. By rotating -prog.c and removing leading space, the code would be shifted one space -toward one of those notches (and creating a new notch on the other -side). This shifted code behaves slightly different from the original -program. For example, here are two more messages that can be -produced:
- -./shift < prog.c | ./right > msg1.c && gcc msg1.c -o msg1 && ./msg1
-./shift < prog.c | ./left > msg2.c && gcc msg2.c -o msg2 && ./msg2
-
-
-In total, there are 9 embedded strings that can be produced via a -sequence of rotates and shifts, one of which can be used to extract -the 10th final string from prog.c. The intent is to simulate those -wooden puzzle boxes that can be opened by pushing and shifting various -well-concealed seams. Thus, finding the correct sequence of rotates -and shifts is left as an exercise to the reader (but if you are really -lazy, just read the Makefile).
- -Source code for all the tools needed to solve this puzzle are embedded -in prog.c, all you need is a C compiler.
- -Code compiles when rotated 4 ways. This required a bit of - patience to achieve. Code still compiles even with one column of - text shifted. This required even more patience.
All rotated and shifted variants compiles without warnings. This - involves various tweaks to satisfy cases where compiler is overly - protective, including but not limited to the “1125” at line 4 as - opposed to “1025”, to satisfy -Waggresive-loop-optimizations.
CRC32 of the code is embedded in the code itself.
Process for writing prog.c is available in spoiler.html
Nuko and the rotated tools accepts only ASCII files where each -character maps to exactly one byte. Also, end-of-line sequence is -assumed to be LF only, as opposed to CR-LF. All control characters -are treated like normal printable characters, so files containing tabs -will look weird after rotation, for example.
- -Nuko has been verified to work with these compiler / OS combinations:
- -Nuko compiles without warnings with all compilers above, even with -“-Wall -Wextra -pedantic” for gcc and clang.
- -![]() |
-© Copyright 1984-2018,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Ondřej Adamovský oa@cmail.cz
- -make prog
-./prog file.unl
-
-
-./prog spam.unl
-
-./prog sierpinski.unl | less
-
-./prog advent.unl
-
-
-Even after pre-processing and indenting, the C code of this entry -is about as understandable as the Unlambda code.
- -Pretending that we don’t know a bit of functional programming :) and lacking a better way -to understand the entry but to fuzz it, -we stumbled on a string of bytes which crashed it:
- -````.0`.0`.0`c.0``sssss
-
-
-Functional programming is not a panacea against core dumps, after all.
- -»A highly structured state state machine«
- -The purpose of this program is to allow you to play Colossal Cave Adventure as -implemented by Kunihiko Sakamoto. As that was written in Unlambda programming -language designed by David Alexander Madore it has to be an Unlambda interpreter.
- -The program grew a bit too long so I had to use several macros to downsize it.
-That unfortunately reduced my options for program layout. I decided to separate
-it into two portions. The initial macro section where I had limited resources and
-you should disregard its shape, unless you like it, and the rest is a separator in the
-form of a single line followed by a section signifying the function of the program,
-a block with removed shape of lambda character. Even the official IOCCC size tool
-acknowledges this: When you call ./iocccsize -i <prog.c, using the
-2019 version of iocccsize,
-iocccsize returns 955, which is the Unicode codepoint of the λ character.
It might be a surprise for you that according to the IOCCC size tool the program is -actually a oneliner. It certainly was for me. I like to think the tool is overwhelmed -by the sheer length of the dividing line and totally overlooks the rest of the program.
- -When built directly
- -make
-
-
-the program (prog) accepts a single parameter with the name of an Unlambda program. You can -download the Colossal Cave Adventure (the advent.unl file) and run it like this
- -./prog advent.unl
-
-
-You can also try other programs from the Web. Many example programs are in the official -Unlambda distribution on the Unlambda homepage. The most complex programs there are -entries from quine contest.
- -There is an alternative build path that requires IOCCC size tool to complete. Put the tool -source iocccsize.c in the project directory and call
- -make identify
-
-
-It will build the tool and use it to build an alternative program prog2, which in turn will
-produce an Unlambda program identify.unl. make identify runs this program to identify
-itself.
The base program (prog) implements an interpreter of Unlambda 2.0. It recognises all its -builtins (k, s, i, v, c, d, .x, e, @, ?x and |) including the syntactic sugar function -(r) and formating properties in the form of ignoring whitespace and comments -to the end of line introduced by the # character.
- -In case of wrong usage (missing Unlambda program file or missing parameter) or use of an unseekable -Unlambda program source if it uses the c function, the program returns message fail. It -also informs you about syntactic errors in the Unlambda program should there be any (but only -when the execution reaches them).
- -The Unlambda source file may contain several Unlambda programs. The interpreter will run -them all in sequence.
- -If you want to familiarise yourself with the language, visit its Wikipedia page for -a brief introduction or its homepage for an indepth discussion. For further reading you -can visit Wikipedia pages on Lambda Calculus and Combinatory Logic.
- -You can also play with an online interpreter by Github user inazz. There you can -debug one of example programs provided or try your wits in writing your own.
- -Here are some pointers where to start when trying to understand the interpreter:
- -More on this in the Spoilers section.
- -The program does not require any special treatment by compilers. Some warnings
-had to be suppressed when compiling with -Wall -Wextra -pedantic. Those were
-produced because of the formatting of the source code, not any programming
-technique. Compilation with -Weverything produced many more warnings, but those
-are only relevant for multi-source-file projects and some are really questionable
-(e.g. -Wdisabled-macro-expansion).
Development was done on Debian 9 on x86-64 architecture using mainly Clang 3.8.1-24 -and GCC 6.3.0. The source is C11 compliant and does not use any special properties -except the following:
- --O3 option does this optimization well and said example does
-not segfault with it. I was not able to force GCC to optimize it out (probably
-an operator fault).You can examine the progSpoiler.c file. It is the original final version of -the interpreter, before I started the downsizing. It accepts one more optional -parameter that specifies filename for the output Unlambda function (it’s the -Unlambda function, that remains after all function applications are done). -When no filename is provided, stderr is used.
- -The function output is used for this additional functionality. You can use -it while debugging to visualise current variables.
The Unlambda functions are represented by a record consisting of an array of five -multipurpose arguments. The first one refers to the function implementing its -application, the second and the third ones are for arguments of the function, -the fourth one is for stack building, and the fifth one is the reference counter.
- -The function argument is used not only for evaluation of the functions, but also -as a state variable to decide whether we want to call it, or do something else.
The interpreter reads the Unlambda source as it interprets it, translating -the incoming character to a function using a constructor stored in translation array T.
- -This means the interpreter must reposition in the source file whenever current -continuation is called.
The state of the interpreter is represented by trees representing evaluated -Unlambda functions stored on the C stack as local variables, plus the source file -position. When a current continuation is created, the stack is unwound using the -fourth argument of the nodes, stored in the continuation, and rebuilt back resuming -the evaluation. When its called, the stack is unwound and thrown away, and the -stack stored in the continuation is restored.
- -This makes implementation of a complete debugger a bit more challenging.
- -For this to work, the functions that do the work (i.e. make series of applications -and/or evaluations each of which may be a call to current continuation), the s -combinator and the ` application operation had to be broken down to pieces, one -for each application/evaluation and corresponding helper functions for stack -rebuilding. (the helper functions are named beginning with r instead of f)
The ` application operation does the reading of the Unlambda source when needed. It -also implements the promise function. Whenever it would apply it, it overwrites -the Apply constructor in translation array T, changing its function to build -unevaluated subtree that is later evaluated whenever the promise is applied.
To further the obfuscation, I shortened the function names while downsizing, -but preserved their meaning (with the exception of Apply functions, which I -renamed to Y to possibly confuse with Y combinator). Simple functions retained -their names to misguide the reader to believe to know what is what. The names -of continuation and exit functions were swapped. The names of S and Apply -functions were shuffled both for S functions and Apply functions in the same way -to hide the meaning of f and r prefixes.
The alternative build path make identify output commemorates a previous IOCCC winner which uses
-similar methods to mess with the size tool.
It is not a bug, it is a feature. :)
- -The crash is caused by a stack overflow. Conventional Unlabmda interpreters implement -the Unlambda execution stack using data structures on the heap. This interpreter uses -the C call stack for this purpose. In a conventional interpreter, the judges program would -consume memory until the user (or the operating system) would lose patience. The C call stack -is usually of a limited size and protected, so this interpreter crashes, when the judges -program depletes the stack. You can always increase the maximal stack size through -the system settings (on Linux) or compiler options (on Windows) if your Unlambda program -needs it. Nevertheless, it will not help the judges program which quickly depletes any limit -you define.
- -The judges, pretending not to know what they are doing, created a program that grows -Unlambda execution stack indefinitely. You may consider it an Unlambda antipattern. -Normally, infinite cycles in Unlambda work by creating two functions and applying one -to the other which creates further functions to apply. The application of the function -frees its position on the stack. This program builds one ever growing function that will -never be complete and able to be applied.
- -![]() |
-© Copyright 1984-2019,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Dave Burton
- -make
-
-
-./prog < prog.c
-
-
-A tiny, but punctually correct way of POSIX counting for text files. This one -line, one word, 127 character beauty continues to expand the number of classic -unix utilities available as winning entries.
- -Feed it anything on stdin.
-The output should look familiar.
Compiles cleanly with:
- -WARN="-Wno-implicit-int -Wno-missing-variable-declarations -Wno-parentheses"
-clang -Wall -Wextra -Weverything -pedantic $WARN -include stdio.h -o prog prog.c
-
-
-Included is a test script, useful for the corner cases.
-As in all good Unix programs, it is silent upon success; any output demonstrates an error.
-Instead of checking correctness, the check script can simply output the results:
-(The Makefile contains the spoiler):
out=cat ./check ./prog
-
-
-Interestingly, and a spoiler here: MacOS and FreeBSD implement the common utility “correctly”. -Centos and Ubuntu both share a “flawed” utility that changes output format based upon input redirection or pipeline(!). -As well, the latter two also behave slightly differently on what they count as whitespace: -\a and \b are both counted whitespace(!), even though the relevant man pages on these systems -omit these characters from the description.
- -This program follows FreeBSD and MacOS, the arbiters of correct for these purposes.
- -Requires the C locale and ASCII character set.
-Input should be less than ten million octets toavoidthisproblem.
You can enjoy this code from beginning to end.
-No whitespace was harmed in the creation of this program.
-All your base belong to us, but the constants seem a bit … off?
The script cow provides a closer analog, and perhaps a more useful interface.
Included is a version without compilation warnings:
- -clang -Wall -Wextra -Weverything -pedantic -include stdio.h -o prog.clean prog.clean.c
-
-
-The flags are not supported. Although they could easily be added into cow.
-This exercise left to the reader.
![]() |
-© Copyright 1984-2019,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Marcin Ciura
-Twitter: @mciura
make
-
-./getwords.sh en | grep .. | ./prog aeiouvwxyz
-
-
-./getwords.sh en | grep .. | ./prog aeiouhjklmnvwxyz
-
-./getwords.sh en | grep .. | ./prog mrjocktvquizphdbagsfewlynx
-
-./en.sh
-
-./fr.sh
-
-./ru.sh
-
-
-A few letters, one at a time, with no repeats. -How many different ways can this be done?
- -While a quick brown fox might jump over the lazy dog, -it has too many repeat letters to allow this entry to repeat. -It is better that Mr Jock, TV quiz PhD, bags few lynx.
- -Speaking of jumping, can you rewrite the code to -remote all of the goto jumps in this code?
- -This entry reads from standard input a list of words in any language -written with an alphabet and outputs perfect pangrams composed of these -words. A perfect pangram is a series of words that contains every letter -of the alphabet exactly once.
- -Example execution:
- -$ grep .. /usr/share/dict/words | ./prog abcdefghijklmnopqrstuvwxyz
-qualm fjord wiz pyx vs beg kc nth
-quartz jinx vs fed kc womb glyph
-quid jamb fez vs pyx kc growl nth
-quiz fjord pyx vs bag kc mewl nth
-quiz fjord pyx vs gab kc mewl nth
-quiz fjord pyx vs gem bawl kc nth
-quiz fjord pyx vs meg bawl kc nth
-quiz fjord vex bawl kc gyp ms nth
-quiz jamb flex vs kc gyp word nth
-quiz jamb pyx vs kc flog drew nth
-quiz jamb pyx vs kc frog lewd nth
-quiz jamb pyx vs kc frog weld nth
-quiz jamb pyx vs kc golf drew nth
-quiz jamb pyx vs kc grew fold nth
-quiz jamb pyx vs kc grow nth fled
-quiz jamb pyx vs kc growl fed nth
-
-
-Rearranging the words into more or less meaningful expressions is the -user’s duty.
- -This entry implements Algorithm X (Exact cover via dancing links) -from Section 7.2.2.1 in fascicle 5C of The Art of Computer -Programming by Donald E. Knuth. As of June 2019, you can download an -incomplete draft of the fascicle from Knuth’s -website.
- -prog LETTERS [N]
-reads allowed words from standard input and writes perfect pangrams
-with at most N words composed of LETTERS to standard output, one
-per line. If N is not given, the number of words in the pangrams is
-unlimited. The characters in LETTERS must not repeat. The length of
-LETTERS must not exceed 97 characters.
The exit status is 0 if no error occurred, 1 if the input word list -is too long, and 2 if the command-line arguments are missing.
- -getwords.sh LANGUAGE_CODE
-outputs a sorted list of unique words in a given language, one per
-line. It requires aspell with a dictionary for LANGUAGE_CODE.
wrapprog.py LETTERS [N]
-works similarly to prog LETTERS [N] except that it merges
-anagrams before passing them to prog and expands them in
-prog’s output. This way, it finishes the job faster than
-prog when there are millions of perfect pangrams. It requires a
-UTF-8 locale.
de.sh, en.sh, fr.sh, it.sh, pl.sh,
-and ru.sh output German, English, French, Italian, Polish,
-and Russian perfect pangrams, respectively. They require a UTF-8
-locale.
I dare submit this entry to categories algorithms,
-internationalization (I have not found active use of <wchar.h>
-among the programs that won IOCCC in the past), and obscure bugs (see
-the questions about Linux core dumps below).
To a casual eye, this entry may look similar to
-2005 klausler.
-However, prog is internationalized and way faster. On my machine,
-./klausler abcdefghijklmnopqrstuvwxyz printed only 3,965 perfect
-pangrams until I killed it after 144 hours running, while the
-equivalent
-tr A-Z a-z < /usr/share/dict/words | egrep -v '^[^ais]$' | ./prog abcdefghijklmnopqrstuvwxyz | wc -l
-finished in 62 minutes, reporting 1,640,569,315 perfect pangrams, and
-the example from section What is this? finished in 1.35
-seconds. On the other hand, prog can only output series of words
-with nonrepeating characters, unlike klausler.
In contrast to prog.orig.c, prog.c does not call
-fflush(stdout) after outputting each line, thus running faster.
-I am grateful to Witold Jarnicki for suggesting this change.
-The original prog finished the example above in 100 minutes
-instead of 62 minutes.
If your word list contains meaningless one-letter words, pipe
-grep .. [FILE] through prog to eliminate the pangrams that
-contain them.
According to prog and aspell, some languages, e.g. Spanish,
-have no perfect pangrams.
Why does yes | ./prog y hang on Linux? Change static int to
-int and static wchar_t to wchar_t, and recompile
-prog. Why does yes | ./prog y dump core now? Change the line
-#define P 9<<23^1 to #define P 9<<23 and recompile
-prog. Why does yes | ./prog y exit gracefully?
Answer: Nf bs Whar 2019, guhf znavsrfg ohtf va tyvop 2.22–2.29:
-1 naq
-2.
The source code uses goto three times. While it could easily get
-by without goto M and goto H, I challenge the adherents of
-structured programming to refactor goto T, which jumps back into a
-nested if block.
With the supplied Makefile, both gcc and clang compile
-prog.c without warnings in C11 and C99 mode. For a clean
-compilation with gcc -std=c90, add -Wno-format to
-CSILENCE in Makefile.
![]() |
-© Copyright 1984-2019,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Volker Diels-Grabsch
-https://njh.eu
make
-
-./prog < file > file.Z
-
-
-dd bs=1024 count=2048 < /dev/zero | compress > ref.Z
-dd bs=1024 count=2048 < /dev/zero | ./prog > dg1.Z
-cmp ref.Z dg1.Z
-
-compress < ../mills/Shakespeare.txt > ref.Z
-./prog < ../mills/Shakespeare.txt > dg1.Z
-cmp ref.Z dg1.Z # Oops, the files differ
-zcat < dg1.Z | cmp - ../mills/Shakespeare.txt # Decompresses correctly. What is going on?
-
-
-Finally, IOCCC now has its own text compression program, and it is short -enough to qualify for the Best Short Program award! That said, can you -compress it down to a one-liner, still producing files in the UNIX compress format, -albeit sacrificing the compression ratio?
- -Can you explain why the zero file compresses identically by the entry and the -standard compress tool, but the text file compresses differently? The judges know. :)
- -Usage:
./prog < guidelines.txt > guidelines.txt.Z
-
-
-Check for correctness:
zcat guidelines.txt.Z > guidelines2.txt
-diff -s guidelines.txt guidelines2.txt
-
-
-Of course you can
-also use 2015/mills2 instead of zcat to verify the output
-file. The achieved compression ratio roughly matches that
-of the classic Unix compress tool. And the source code is
-very compressed, too: It has exactly the same size as the
-paragraph you are reading right now. And exactly the same
-shape. Nevertheless, it is portable C99 code that runs on
-32-bit and 64-bit platforms. It compiles without warnings
-on both GCC and Clang even with -Wextra and -Weverything.
![]() |
-© Copyright 1984-2019,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Volker Diels-Grabsch
-https://njh.eu
make
-
-
-./prog
-sha512sum prog.c || shasum -a 512 prog.c
-
-
-Before running this one, stay calm. Chill out, have a cup of tea. Is this bad?
- -To understand what is going on here, please check if you are dreaming, or are you dreaming -that you are dreaming? Or is it, wake up from the simulation?
- -This program prints its own SHA-512 hash. To verify, run:
- -sha512sum prog.c; ./prog
-
-
-Output:
- -43bd0c4381a5078d2850fca9ae5e0647596bcc03cd67d8d973ad02ff35c316c728e7b347ca70abe6c74e745e63646cc7643cb0cffcd3d9a969cbf31a7ce5bf68 prog.c
-43bd0c4381a5078d2850fca9ae5e0647596bcc03cd67d8d973ad02ff35c316c728e7b347ca70abe6c74e745e63646cc7643cb0cffcd3d9a969cbf31a7ce5bf68
-
-
-It started as a complicated “hello world” program that prints some -random hex digits instead of “hello world”. Then, the digits were -adjusted until the resulting program matched its own SHA-512 hash, -via brute force through all 2512 possibilities. Just kidding.
- -This wasn’t brute force, but involved quite some math, using a variant -of Jane Doe’s algorithm for generating SHA-512 collisions efficiently. -If you still don’t believe me, you are right.
- -No crypto was broken in the making of this program!
- -The trick is that under the hood, this program is a quine! That is, -it is aware of its own source code in string representation. But -instead of printing that string, its SHA-512 hash is computed and -printed. So two major steps were needed to obfuscate this program:
- -Note that both steps were achieved mostly algorithmically. The code -is otherwise as short and as clean as possible. The implementation is -portable C99 code for 32-bit and 64-bit systems that compiles without -any warnings on current GCC and Clang versions even with -Wextra and --Weverything. The program is composed of mostly pure functions, and -the “#define"s are only used to shorten redundant parts of the code, -they are not meant to obfuscate much. Having that out of the way, how -are step 1 and step 2 achieved then?
- -Regarding step 1, note that the large string literal “`x{bh}ndbq…” -in the last line doesn’t look like C code. Moreover, it is too short -to contain even a compressed representation of all preceding and -subsequent code. Instead, the preceding code including the ‘“’ -character has already been run through the SHA-512 computation by an -external script. The internal state of the SHA-512 computation at -that point has been extracted and encoded into the string. This works -because the preceding code is exactly 1280 bytes, which is a multiple -of 1024 bits, the block size of SHA-512. The program itself then just -continues the SHA-512 computation from that point, adding the last -1024-bit block, finalizing the hash and printing it. The last block -is taken directly from the string literal at runtime, plus the -subsequent code which consists of just ‘”’, ‘;’ and ‘\n’. Those 3 -characters are short enough to be hidden in … well, let’s leave this -as an exercise for the reader.
- -To summarize, the main trick here is to move the string constant to -the end, so the preceding code can be precalculated and the subsequent -code is short enough to be hidden anywhere.
- -Regarding step 2, almost all macros, functions and variables have -meaningless single-letter names. Moreover, the SHA-512 computation is -reduced to the special case of adding just one block and immediately -finalizing it, where the total size is known in advance.
- -But this is not enough! For SHA-512 we need 8 initial hash values and -80 round constants, which are very characteristic. If any of them -appeared in the source, a quick web search (e.g. for 0x428a2f98d728ae22) -would tell the reader immediately what’s going on. Because of the -precomputation, the 8 initial hash values are not needed, but the -80 round constants are.
- -It is almost impossible to hide those 640 bytes in the source. -Luckily, the round constants where not chosen by fair dice rolls. -They are the fractional parts of certain irrational numbers, namely, -the cube roots of the first 80 primes. So the round constrants are -calculated at runtime, which makes the program shorter and adds -another layer of obfuscation.
- -While this sounds like just iterating primes and executing pow(), this -turned out to be harder than expected. If we were computing SHA-256, -it would have been as simple as that, because the round constants -would have been 32-bit values. However, SHA-512 needs the cube roots -at 64-bit precision, while double has only 53-bit mantissa precision.
- -Using higher-precision floating point is no option here, because the -program is meant to be portable C99. And implementing -arbitrary-precision arithmetic would have been overkill and would have -increased the program size dramatically.
- -Instead, the program just multiplies. That is, it computes cubes -instead of cube roots. It steps through cube root candidates via -bisection, and calculates their cubes until those match the given -prime. Thus, we don’t need floating point and can use 64-bit integers -instead. But that still doesn’t solve the problem as it poses the -following new challenges:
- -The reason for challenge 1 is that in portable C99, the result must -fit into the same data type. To multiply two 64-bit integers we would -need a 128-bit integer for the result. So we can at most multiply two -32-bit integers to get the 64-bit product at full precision. While -GCC and Clang both support 128-bit arithmetics, that isn’t standard -and wouldn’t have been portable C99.
- -The reason for challenge 2 is that cube root of the 80th prime is -around 7, so we need to compute with 3 bits for the integral part and -64 bits for the fractional part.
- -The reason for challenge 3 is that the cube of a 67-bit number is -3*67=201 bits, but fortunately we only need to check if it is close -enough to the actual prime. It won’t be exactly e.g. “409.0000…” -anyway, but must be accurate enough to distinguish the correct cube -root from its neighbours, e.g. the same number with the 64th -fractional digit increased.
- -The solution here is to split the 67-bit input into 3 integers of -24-bit each. Those are cubed using the multiplication formulas -numbers with 3 “digits” of base 224 each. During that calculation, -at most two values are multiplied at once, and the accuracy of -intermediate values is reduced using right-shifts as far as allowable -for the computation. Finding woking right-shift values was mostly -trial-and-error, producing correct results for the first 80 primes, -but not much more. Moreover, for some terms it was possible to leave -them out entirely, especially higher-order terms of the last digits. -Luckily, in the end, all intermediate results did fit into 64-bit -integer addition and multiplication, but that was not obvious at the -beginning.
- -That’s it.
- -Well, I could continue with details about the encoding of the internal -state values into the string, how to avoid escaping issues, how to -find short notations for various loops, how to get rid of if(), where -the final “\”;\n" is stored, how to eliminate intermediate values and -arrays by reordering of operations, and so on. But those were all -minor issues compared to the challenges described above. What’s -documented here is all you need to know to write your own version of -that program.
- -I’d like to finish with an open problem:
- -Is it possible for the cubing and bisection to be implemented with -just two parts instead of three? That would simplify the formulas a -lot. For example, one could split the 67-value into two 34-bit parts, -but whenever one multiplies two of them, one needs to right-shift one -of them by at least 4 bits, or both by 2. Or, one splits the 67 bits -asymmetrically? I wasn’t able to make it work with 2 parts, but that -doesn’t have to mean anything.
- -![]() |
-© Copyright 1984-2019,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Gil Dogon
- -make
-
-./prog < pattern.mc
-
-
-./prog < glider.mc
-
-./prog < infinite_5x5.mc
-
-./prog < mosquito5.mc
-# Press the minus key a few times until you see white specks,
-# then press space, and the ] key a few times.
-
-./prog < message.mc
-
-
-1991/davidguy, -2011/blakely,…
- -…This entry likely concludes the IOCCC category “Cellular automata simulators”, -it would be very hard to beat it on its field.
- -FYI: The .mc extension stands for Golly macrocell format.
- -We truly have not much more to add, except two things:
- -If a large sparse pattern is given, at the start of the program -you are much more likely to see a blank board rather than the loaded configuration, -and to see it, you may need to zoom out a few times.
if you’re using a virtual machine with less than 4 Gb of available -model RAM, you’d want to reduce the value of the Z define in the Makefile -to 0x10000000, otherwise the entry will promptly crash.
In the interest of saving lives, this entry was not fuzzed.
- -Just run with no arguments on an X11-compatible system using one of the supplied input .mc files as standard input. Press ‘-’ several time to zoom out if neccessary, then press space. For acceleration press ‘]’ several times. Thats rather quick dont you think?
- -Which brings us to the present moment in time.
- -Yes, this program is Conway’s game of life graphic simulator implementing Bill Gosper’s hash life algorithm. The entry’s UI is rather terse and somewhat obfuscated, as it should be. Also, when you accidentally, or not, press any of the keys not specified bellow, some stuff will happen or not, there is no guarantee whatsoever.
- -The program should be used as follows:
- -The standard input should contain a Golly macrocell format file for a two state automaton. See: http://golly.sourceforge.net/Help/formats.html. Of course only Conways GOL rules are supported, so rules in the files are ignored. The supplied input examples should be quite interesting. Except one, all are taken from Golly’s standard distribution. Information and credits to their designer are in the header comment of each.
- -Notice that when going backward in time we ignore current timestep setting and just jump by the amount that was specified before. However going forward is always using the current time step.
- -There is a minimal text printout by the program, so you can know what Generation your are in(G:), Internal memory allocated till now (M:), and then which Level is the current macrocell (L) and which zoom Scale you are watching (S).
- -This entry is quite portable hopefully on most modern platforms. It assumes X Window support of course. More than 2GBytes memory is recommended. Configuration through makefile is provided for the display windows size and for the memory usage. The makefile provided configuration (Z=0x20000000) will need a system with 4GB DRAM to run nicely. There are several other salient assumptions though:
- -Foremost the entry is very strict, unsafe and picky regarding its input. Anything straying from the standard Golly macrocell legal format will result in undefined behavior, meaning mostly a very defined core dump. Since aforementioned core is rather large by default (about 4Gb) it is highly recommended to ‘set limit coredumpsize 0’ in the shell before playing with fire …
- -This entry needs quite a lot of memory to be effective, but by modern standards that is not too much. It does not do any garbage collection, so sooner or later memory will run out, resulting, surprise, surprise, in a core dump. On the plus side, this enables the nice time reversal feature… Anyway the amount of memory used can be controlled by the Makefile -DZ=… argument. With the default Z, the program will support in total about 240 million 64bit longs for the internal memory, which should be sufficient for about 100 million nodes+leafs, as each node is 3 longs and each leaf is 2. -Important: Makefile Z define must be apower of two!
- -Zooming out past about S58 scale will enter a buggy twilight zone as only long integers are used in the drawing code. Reverting to doubles could have remedied that, but then I’d need to use a lot of ldexps which would take the program over the size limit. Also the program will crash once the universe goes past level 64, though this is simply fixed by modifying a single constant in the program, can you find it ? Anyway 258 squared is quite a big enough universe for such a tiny progam to simulate, no ?
- -In case cell memory did not run out, or your pattern did not grow too big, and you have had patience enough and did not increase speed too much, you can run out of the history buffer after 33333 steps.
- -If all of the above did not happen and result in the expected core dump, you will encounter the final limitation, which is the absence of an escape key. Just close the window or use ^C to exit ….
- -Oh don’t get me started on the torrent of litanies gcc emits when used with -Wall ! Does it think I have not memorized by heart C’s precious operator precedence table (or at least have a cheatsheet nearby) that it dares suggest extra parentheses that would take the program over the limit ? And what if I do not use a variable here or there, do I have to pay extra tax for every orphaned variable?
- -There is the reasonable warning about some longs printed as ints but its OK too, trust me.
- -Then there’s the warning about ‘gets’ being unsafe, which is indeed the only one that appears by default in some versions of gcc linker. Yes Virginia, I know it is unsafe, and I would not recommend anyone using this entry as part of a web daemon, or a spaceship, no, Seriously Dont do that!
- -Well almost none of the obfuscations are done on purpose, but mostly out of necessity, so all identifiers possible to be one character, are, and they are mercilessly reused. In the main There’s even a nice little identifier first used as a global and then reused (shadowed) in the same scope, and this did not produce even a lile squeak of a warning from the compiler! Macro compression is raher sparingly used, however Magic numbers abound everywhere, and bit twiddling is magical too. Do you know for example why we have unsigned F=-1 ? (No warning there of course :) Hint:Later in the program you have F/=17. Did that make any sense? Further hint: print the resulting F in hexadecimal…
- -And yes, the layout hint involves a mix of the most trendy typographical character juxtaposed against a very ancient one, Not to mention the program includes some famous name dropping and documents itself as usual.
- -Those wait for you, curious and interpid reader, in the attached apohlife.c file, Which is a partially obfuscated version of the program I wrote with a lot of helpful annotations and comments for myself and posterity, revealing some of the magic under the hood. This program is also a somewhat improved version which uses ldexps in the draw routine and has bigger constants, so it can zoom up to level 1024 if memory allows, and it tries its best to avoid dumping core on the poor user when its memory runs out, rather it enters freeze mode where you can still travel in calculated frozen space-time. Well, its no nice and tame, it even has an escape key, usage message, and to top it all it even avoids gets!
- -To Tom Rockiki, the original co-writer of Golly, a personal friend and hashlife master, who reviewed some earlier versions of the entry and freely shared some of his vast knowledge regarding GOL programming and hashlife. As a free bonus, Tom has allowed me to show his code which is probably the most efficient yet most obfuscated way of calculating the GOL function on a 64 bits 8*8 leaf:
- -c
-unsigned long life8x8(long a) { unsigned long aw = a << 1, ae = a >> 1, s0 = aw ^ ae, s1 = aw & ae, hs0 = s0 ^ a, hs1 = (s0 & a) | s1, hs0w8 = hs0 >> 8, hs0e8 = hs0 << 8, hs1w8 = hs1 >> 8, hs1e8 = hs1 << 8, ts0 = hs0w8 ^ hs0e8, ts1 = (hs0w8 & hs0e8) | (ts0 & s0); return (hs1w8 ^ hs1e8 ^ ts1 ^ s1) & ((hs1w8 | hs1e8) ^ (ts1 | s1)) & ((ts0 ^ s0) | a); }
-
-This uses only 19 bitwise operations and six shifts to calculate the inner 6x6 next generation bits of the input 8x8 !
![]() |
-© Copyright 1984-2019,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Etienne Duble
-https://lig-membres.imag.fr/duble
-Twitter: @etienne_duble
make
-
-
-./prog /tmp/drawing
-
-(open another window / terminal)
-
-./prog /tmp/drawing
-
-(open more terminals....)
-
-./prog /tmp/drawing
-
-
-After starting the program, use the cursor keys, then try some modes, like “p” -or “l” (they toggle).
- -This program is a graphics editor, running on the terminal.
- -It provides collaborative features: one can join the drawing session -of someone else by just opening the same file!
- -The program can run on Linux, FreeBSD, Mac OS X, and in most terminals. -See section ‘Limits, Portability’ for more info.
- -To build, type make (assuming gcc) or make CC=clang.
Then you can start the program. It expects a file path as its first argument:
- -$ ./prog /tmp/drawing
-
-
-(If not started this way, prog will refuse to start.)
If the file does not exist, you will start with a blank drawing.
- -If someone else (or another instance of yourself, maybe??) is already -editing this file, you will join the session!
- -The mode and current color is indicated at the bottom left corner of -the editor.
- -./<the-file>.
-(This will fail if someone is still editing the file, though.)ls --color <drawing-files...> will probably select different colors
-to indicate whether a drawing file is being edited or not. :-)You will probably have a hard time analyzing this entry, because:
- -Did you notice the enum declaration? Could it be just an int or const int
-variable, instead? (spoiler: http://c-faq.com/ansi/constasconst.html)
If your keyboard has no arrow keys, you can probably find alternate keys by -reading the source code.
- -I tested the program on several Linux systems, on FreeBSD 12, and on -Mac OS X (mojave).
- -On Linux, the program uses an OS-specific detail to hide communication -artefacts, and avoids the need to remove them on exit. -Since this is Linux-specific, it was not possible on FreeBSD or Mac OS. -Its behavior is a little more dirty there.
- -The program should work on most terminals that support 8-bit colors,
-inverse video mode, and movement escape codes, e.g. xterm, gnome-terminal,
-terminator, etc.
Note: the drawing files prog generates are probably even more portable than
-prog itself!
The drawing area size is set at compilation time.
- -The default size is the one of my xterm (see top of Makefile). -You may set it to the full size of your terminal window by typing:
- -$ make fullscreen
-
-
-IMPORTANT NOTES:
- -The file prog.orig.c is the one I submitted.
Judges proposed a small update: the program was using macro FD_SET inside an
-expression, which breaks compilation on Mac OS X. Wrapping this macro into a
-function was enough to fix this compilation issue.
However, that was not enough to make the program work on Mac OS X. If you analyse
-the program you will see that it heavily relies on OS resources. And, for this
-first version of the program, you even needed to increase default sysctl
-parameters to make it work on FreeBSD (this was the purpose of file check-os.sh).
-I tried hard to tune Mac OS X the same, but failed.
The simple fact Judges proposed this update meant they wish it could work on Mac.
-And if judges wish something, it has to be done. ;)
-So I refactored a little more the program to reduce OS resources consumption.
-Or maybe not reduce consumption, but consume them differently…
-And I obtained prog.c. With this version, no need to touch sysctl parameters,
-and it works on Mac OS X too!
-I must confess it was challenging to remain below the size limit with this little
-change.
![]() |
-© Copyright 1984-2019,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Yusuke Endoh
-Twitter: @mametter
make
-
-
-./prog
-
-gdb ./prog || llvm ./prog
-
-
-The purpose of this program is to crash. You’ll want to have memorized “man -ascii” when debugging it to reveal its purpose.
- -Compile prog.c with no optimization.
- -$ gcc -g -O0 -o prog prog.c
-
-
-Then, run it. You will see a segmentation fault.
- -$ ./prog
-Segmentation fault (core dumped)
-
-
-Let’s debug. As usual, run it under gdb.
- -$ gdb ./prog
-(gdb) run
-Starting program: /home/.../prog
-
-Program received signal SIGSEGV, Segmentation fault.
-0x0000000000000000 in ?? ()
-
-
-Okay, check the backtrace.
- -(gdb) backtrace
-#0 0x0000000000000000 in ?? ()
-#1 0x0000555555555201 in x23 () at prog.c:35
-#2 0x000055555555571a in x64 () at prog.c:100
-#3 0x0000555555555747 in x65 () at prog.c:101
-#4 0x0000555555555774 in x66 () at prog.c:102
-#5 0x00005555555557ce in x69 () at prog.c:105
-#6 0x0000555555555828 in x6e () at prog.c:110
-#7 0x0000555555555747 in x65 () at prog.c:101
-...
-
-
-See the line numbers and lookup the ASCII table.
- - 35 = '#'
-100 = 'd'
-101 = 'e'
-102 = 'f'
-105 = 'i'
-110 = 'n'
-101 = 'e'
-...
-
-
-The original program can be used as a GDB command file.
- -$ gdb -q -x prog.c ./prog | cat
-Reading symbols from ./prog...done.
-
-Program received signal SIGSEGV, Segmentation fault.
-0x0000000000000000 in ?? ()
-#0 0x0000000000000000 in ?? ()
-#1 0x0000555555555201 in x23 () at prog.c:35
-#2 0x000055555555571a in x64 () at prog.c:100
-#3 0x0000555555555747 in x65 () at prog.c:101
-#4 0x0000555555555774 in x66 () at prog.c:102
-#5 0x00005555555557ce in x69 () at prog.c:105
-#6 0x0000555555555828 in x6e () at prog.c:110
-#7 0x0000555555555747 in x65 () at prog.c:101
-...
-
-
-By using this, you can confirm that it is actually a quine.
- -$ gdb -q -x prog.c ./prog | sed -n -r 's/#.*:([0-9]+)/\1/p' | awk '{printf "%c",$1}' > prog2.c
-$ diff prog.c prog2.c
-
-
-![]() |
-© Copyright 1984-2019,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Edward Giles
- -make prog
-./prog infile.wav outfile.wav
-
-
-play MonodyVocals.wav
-./prog MonodyVocals.wav
-play out.wav
-
-
-Do you need to pretend enjoying a more spacious living environment than you actually are in, -or the great outdoors with mountains and canyons, when recording your outgoing voicemail message? -Then don’t waste another minute! Record yourself, send the audio file through this entry, -and let your callers be surprised.
- -This program takes a WAV audio file as input, and applies an artificial reverberation effect to it. It works by feeding the audio through a number of delay lines of various lengths, with various amounts of feedback, to create a smooth echo that fades away over time. A number of parameters of the effect can be altered, to change its sonic characteristics.
- -BlockDiagram.png is a block-diagram of the internal structure of the reverb algorithm, which is most likely easier to understand than the source code.
- -MonodyVocals.wav is for testing the program: It is an extract of the unprocessed vocals from Monody by TheFatRat, featuring Laura Brehm. The track was published under a free license.
- -This program has also been successfully compiled on Windows, with both the Tiny C Compiler and Microsoft’s C/C++ compiler. However, the latter reports warnings about loss of information when converting floats, and that void (*)() and void (*)(void) are not the same thing.
Interesting fact: The size of the program from ./iocccsize -i is 2019.
How to use:
- -./prog input [output [size [dry [wet [damping]]]]]
-prog.exe input [output [size [dry [wet [damping]]]]]
-
-
-input: The path to the input file. Required.output: The path to the output file. Optional, defaults to out.wav.size: The perceived size of the room, i.e. the approximate amount of time taken for the echo to fade away. Optional, default 1.6 seconds.dry: The amount of unprocessed signal (“dry” in audio terminology) to add to the output. Optional, default 0.3 or 30%.wet: The amount of processed (“wet”) signal to add to the output. Optional, default 0.5 or 50%.damping: The amount by which high frequencies are damped out as the echo continues. This models the tendency for higher frequencies to be absorbed more than lower ones. Increasing this value causes the echo to be less “harsh” and more “muffled”. Optional, default 0.06 or 6%.The values size, dry, wet, and damping can be specified either as decimal numbers (e.g. 0.35) or as percentages (e.g. 35%).
The default settings are designed to make the effect obvious rather than subtle, so it may be a good idea to adjust the ratio of “dry” to “wet”, to give a more pleasant result:
- -./prog in.wav out.wav 1.8 80% 15%
-
-
-The program only supports WAV files, and only mostly. Other audio formats, such as MP3, are not supported because they are difficult to decode, but there are free programs such as ffmpeg that can perform the conversion. Some of the advanced features of the WAV file format are also not supported, such as metadata, 3 or more channels, or a bit depth other than 16 bits. Fortunately, WAV files that don’t use these features are very common. The program validates the input file, so passing it a file it can’t process will cause the program to print Bad input file or Wave file must be 16 bits,1-2 channels. depending on what it thinks the problem is. If the output file cannot be opened, the program will print Can't open output file.
float is a floating-point type of any size, such that all zero bits represents the number zeroint16_t and int32_t are 2’s-complement, sizeof(int16_t) == 2 and sizeof(int32_t) == 4.The main obfuscation is that digital signal processing algorithms are inherently opaque. They just consist of iterating through a list of floating-point numbers and performing a series of arithmetic operations on each value. Even if this entry were entirely cleaned of all other obfuscation, it will appear to the average programmer to do the following:
- -size parameterNote that no part of the above description of the code’s function had anything to do with echoes in a room. The purpose of the code is therefore hidden.
- -The source code, on cursory inspection, appears to be a jumbled series of characters arranged into three arcs, representing sound waves. The overall layout distracts people from the fact that it is source code rather than only ASCII art, and the random appearance of the code discourages people from trying to decipher it.
- -#defines are used to abbreviate the code, which has a side effect of making it very slightly harder to read.
k is just a general-purpose replacement for 16.i is the number of delay-lines to allocate and use (currently 24).q is an abbreviation for multiplying two elements of w[] together.u() is used to display percentages with proper rounding.j() imposes an upper limit on a floating-point value, and then negates it. This operation is used eight times.D() abbreviates a call to setvbuf, used to speed up file I/O.l() is used to clip audio samples to the acceptable range, and convert them to 16-bit integers for output.g() handles errors.C() contains the bulk of the signal-processing code, as well as a preprocessor obfuscation trick: If you were to read the body of the macro out of context, it will appear to have multiple mismatched square brackets, since [ occurs more than ]. However, this macro is always invoked with arguments such as C(v],+10) which contain an unmatched ] character. When the macro is used in this manner, the extra [s in the macro’s body are matched with the ]s added through the first argument.Every variable name is one letter long. This allows the code to fit into the IOCCC size limit, and it also makes the purpose of a given variable much less clear. For example, it is not evident from the name of the variable t that it contains pointers to the delay-line arrays.
As many values as possible have been crammed into arrays. float w[] contains:
w[0] to w[3])w[4] to w[9])w[10] to w[20])int32_t f[] is even more multi-purpose. It contains:
f[0] to f[11])f[12])f[13])f[14])f[15])f[16] to f[39])f[40] to f[63])f[64] to f[87])All of the strings are concatenated together and “encrypted” by breaking the string into 4-byte chunks (by casting it to an int32_t*), and then XORing the sequence of ints with a known numeric sequence. The “decryption” is not done in-place, to avoid writing over the string constant.
int32_t *c is a pointer that points into f[], except that it is often incremented or decremented when it is accessed. In order to determine which indices of f[] are being accessed through c at any given point in the code, you would have to locate the places where c is modified.
In order for this program to read and write WAV files, it needs to parse the header. The necessary information, such as the sample rate and channel count, is defined by the standard to be in somewhat arbitrary locations within the file. Therefore, even if you know which indices of f[] are being accessed, it takes extra effort to look up the WAV file format and determine which field that corresponds to.
Some array accesses (which make up most of the program) have been replaced with harder-to-interpret equivalents, for example:
- -X[1] -> 1[X]f[14] -> 10[f+4]X[0] -> *XAssignments return the assigned value, allowing them to be included into later expressions: 10[f]=f[13]<<2; f[1]=20+10[f]+k; is replaced with f[1]=20+(10[f]=f[13]<<2)+k;
This technique is used in conjuction with the comma operator to further obscure where the data ends up. For example,
- -12[f]=4[++c]>>k; was incorporated into w[0]*=6[f]; to yield w[0]*=(12[f]=4[++c]>>k,6[f]);w[15]=w[k]=e[12[f]]; w[11]=w[10]=e[1]; becomes w[11]=(w[15]=w[k]=e[12[f]],w[10]=e[1]);A few other miscellaneous obfuscations have also been done:
- -while(++f[15]<12); is used instead of f[15]=12;for(s=14[f]=0;s<f[13];s++) is used instead of f[14]=0; for(s=0;s<f[13];s++)printf("Hello, world!"); is mostly commented out.![]() |
-© Copyright 1984-2019,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Joshua Karns
-Twitter: @jkarnss
make
-
-./prog < textfile_that_fits_on_the_screen
-
-
-make test
-
-./prog < hint.text
-
-
-If you typically get lost in mazes, watching this program run might – or might not, YMMV – -teach you how to find your way in a maze. The algorithm is well-known but the drawing is amazing!
- -Before running, make sure that your terminal can accommodate the whole file. Before running “make test”, -make it about 120x40 to be safe, ensuring that you see the @ sign as well as the exclamation mark.
- -…Oh, and the first M in YMMV stands for “mazing”.
- -A puzzle for the reader: Can you change the program to consider a diagonal movement as one step?
- -This program is pretty simple! It performs a breadth first search on the -specified graph. The graph can be any ascii text file that has an ‘at’ -character, which is going to be the starting location, and a ‘!’ character -which will be the destination.
- -The nodes on this graph that are spaces are connected with any directly -adjacent nodes that are also spaces. Nodes that aren’t spaces are not -connected with anything.
- -This program usually compiles under both GCC and clang. Build with:
- -$(CC) -std=c99 -o tbfs prog.c
-
-
-where $(CC) is cc, gcc, clang, or somet other c compiler.
- -You can then run it with: - cat | ./tbfs
- -Examples: - ./tbfs < maze - ./tbfs < prog.c
- -![]() |
-© Copyright 1984-2019,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Ben Lynn
-https://crypto.stanford.edu/~blynn/
-Twitter: @bmxlynn
make
-
-
-(./prog < fib.hs; cat prog.c) > fib.c
-cc fib.c -o fib
-./fib
-
-
-A fully functional compiler. The example prints out the 30th Fibonacci number.
- -A Haskell compiler. Supports a subset of Haskell more than large enough to -self-host. Like GHC with custom language extensions:
- -WeDontServeYourType: Compilation failing because of inscrutable type
-checking rules? Confused by the ever-growing mire of extensions to the type
-system? The solution is simple: no type checking. It also means no
-typeclasses. Just pass dictionaries explicitly.
ZeroPauseGarbageCollection: Instead of disruptive stop-the-world garbage
-collection, we only tidy up when the world stops of its own accord, that is,
-on program termination.
OneHundredPercentPure: Gone is the catch-all lawless IO monad. And no
-trace of those scary unsafeThisAndThat functions. All functions must be pure.
SyntaxForTheMasses: See below.
Build the compiler:
- -$ $(CC) -o prog prog.c
-
-
-Test the compiler on fib.hs:
$ (./prog < fib.hs ; cat prog.c) > fib.c
-
-
-Compiling the output produces a binary that prints the 30th Fibonacci number.
- -The file ghcfib.hs includes fib.hs with some glue code, and shows GHC
-also accepts our subset of Haskell:
$ ghc ghcfib.hs
-
-
-To avoid spoiling this entry by revealing the original Haskell source, we
-instead provide hint.hs, the output of a certain stage of the compiler when
-run on itself. This intermediate output is hopefully difficult to understand,
-yet is accepted by our compiler:
$ (./prog < hint.hs ; cat prog.c) > hint.c
-
-
-The output program behaves like the compiler itself.
- -Unlike the original source from which it is derived, GHC fails to compile
-hint.hs. This is because values have been replaced with their Scott encodings
-by this stage, which messes up type-checks; we’d need equirecursive types for
-it to work.
The file lol.hs contains an adaptation of Doug McIlroy’s elegant code from
-“Enumerating the strings of regular
-languages”. We exercise it by
-showing the first entries of the length-ordered list of all strings consisting
-of the characters a and b that contain an even number of a’s.
$ (./prog < lol.hs ; cat prog.c) > lol.c
-
-
-A GHC wrapper is provided:
- -$ ghc ghclol.hs
-
-
-See scc.hs (and its GHC wrapper ghcscc.hs) for an elegant way to print the
-strongly-connected components of a graph in reverse topological order.
$ (./prog < scc.hs ; cat prog.c) > scc.c
-
-
-It expects the input to be in a similar format as a previous entry -(2018 vokes). Indeed, obtain the 2018 winners, and run:
- -$ ./scc < 2018/vokes/example-1.txt
-$ ./scc < 2018/vokes/example-2.txt
-
-
-The output should agree, though our program omits line numbers and does not -sort entries within a line. (Also, our program only treats spaces as -whitespace, and supports any nonspace character in a vertex name.)
- -Some claim Haskell syntax is frightening because braces and semicolons are -optional. Some complain about a zoo of twisty little operators, all alike. Our -compiler addresses such concerns by making braces and semicolons compulsory, -disabling layout-based rules, making every operator left-associative with same -precedence, and only defining 6 primitive functions:
- -: + - * / <=
-
-
-The arithmetic operations behave as they do in C on unsigned ints, and (:) is
-Haskell’s cons function. Like Haskell and unlike C, (<=) returns a Bool
-(which are Church booleans behind the scenes) and not an Int.
No ifs, ands, or buts. Define them yourself. No tuples. Who needs them when -algebraic data types delivers a better product? There is no do. No where. No -list comprehensions. No unary operators.
- -Let expressions and operator sections are supported.
- -Within global scope or a let expression, each definition can only refer to -itself or previous definitions. This implies we can only achieve mutual -recursion by having one function pass itself to others.
- -The only primitive type is Int. In particular, they represent characters. To
-interoperate with GHC, our compiler treats any undefined functions as the
-identity function, so that we may freely use ord and chr (or fromEnum and
-toEnum) to make our code acceptable to both compilers.
The main function is the last function to successfully parse. It should have
-type [Int] -> [Int], and our compiler treats this like the function passed
-into Prelude.interact, that is, the entire standard input is passed to this
-function, and the result is printed to standard output.
Bool must be defined as:
- -data Bool = True | False;
-
-
-so that it matches the Scott-encoded booleans internally used by the primitive
-function (<=).
The alternatives in a case expressions must list every data constructor in -the order they are defined. For example, if we have:
- -data Foo a b = Bar a | Baz | Qux Int [b]
-
-
-then a case expression that examines a term of this type must have the form:
- -case x of
- { Bar a -> ...
- ; Baz -> ...
- ; Qux n bs -> ...
- }
-
-
-We stress braces and semicolons are required. Our fussy parser treats -semicolons as separators, not terminators.
- -The effect of erroneous input is undefined. It may be best to develop with GHC, -but even then, be mindful of changes needed because of issues caused by the -uniform operator precedence and the touchy format of case alternatives.
- -One-letter variable names abound in IOCCC entries, and for good reason. These -tiny pieces of confetti are hard to read, and leave room for more code. Then -why not go further and use zero-letter variable names? That is, tacit -programming or point-free style.
- -I had been playing with an algorithm devised by Oleg Kiselyov that effortlessly -and efficiently eliminates those pesky variables, leaving behind terms composed -from a small set of combinators. No need for lambda lifting or supercombinators.
- -By adding a handful of lines of mostly parsing code, we get a Haskell compiler, -or rather, a compiler that accepts a subset of Haskell sufficiently large to -self-host. You might say I wrote a tool for this contest, then ran it on itself -to make an entry for it.
- -Even with Kiselyov’s algorithm and some term rewriting, the compiler only fit -after compression, which naturally obfuscates the code. More tricks were needed -to fit within the size limits.
- -Y(BT)n; it works because
-Y(BT)ne = e(Y(BT)n).Other obfuscation techniques are better appreciated after decoding the
-compiler. See hint.hs.
undefined function compiles to the (.) function.(&&) with (||) and not using De Morgan’s law, which
-makes some comparisons less comprehensible.On my system, it compiles cleanly with -Wall with older standards, e.g.
--std=c89, but less cleanly if -pedantic is also supplied.
Compiling the compiler output with -Wall triggers a warning about a
-strange-looking comment.
My website reveals how this compiler -works.
- -![]() |
-© Copyright 1984-2019,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Christopher Mills
-Twitter: @MisterXopher
make
-
-make cpclean
-# Let this run for about about an hour and then kill it
-./prog Shakespeare.txt
-./prog < $(< ls -1tr cp* | tail -1) | head -100
-
-
-# If you are on a 64-bit system:
-
-make test-64bit
-
-less IOCCC-Rules-Guidelines.output.txt
-
-less IOCCC-hints.output.txt
-
-less Eugene_Onegin.output.txt
-
-# However, as the binary model files used to produce the output are in an implementation-specific format,
-# your mileage may vary.
-
-
-Can a machine learn?
- -Some say so.
- -But can a machine learn to write like Shakespeare,
- -or tweet like Trump?
- -Can it write rules and guidelines for the IOCCC?
- -You decide. :-)
- -OMLET is the Obfuscated Machine Learning Environment Toolkit, a -micro-framework for experimenting with recurrent neural networks. OMLET -lets you build, train and evaluate deep neural networks. Why invest -hours reading documentation and megabytes of disk space on a full-featured DNN -framework like TensorFlow or Torch when you can have full RNN -functionality in less than 4 KB!
- -OMLET has the following features:
- -OMLET is based on Andrej Karpathy’s character-level language model -as described in his blog post The Unreasonable Effectiveness of Recurrent -Neural Networks. I’ve included a small sample dataset to use for -training, but you can have even more fun by downloading some larger datasets:
- - - - -OMLET has three operating modes:
- -For your first OMLET experiment, we will try training a simple single-level -RNN to write some Shakespere plays. Start by typing
- -make
-
-
-After it builds, train it using
- -./prog shakespere.txt
-
-
-This will immediately start outputting gibberish to the output, e.g.
- -./prog shakespere.txt
- sins ohennAu
-T-teooclelp tiThoWy
-
-g
-nlakuafy
-e
-sselW usnsofueB Aoee pasfUsuslhe ooM ot Wou moy
-me neltAl -no IoyI mhuyakse inT-l chu ghenn ffo? fnsoe yhyye
-ue nnfrlass heUthole saounlcesyee pee
-t,
-T0:0% 3.210888
-o',,vU
- An ,hTf lnm Far rur:s moilt WoEgrv wonds mith Aog thernw
-Rni So
-co Nnd :
-For an bImy pgafoun:
-Wf'r hom wortiverita
-int fod mous Eheledet,
-Tho he theket nonS wnu-ang dorlaMSp
-nrocWiSe tflg 'o.
-T0:0% 2.995950
-d whecedhencrysesil yr bn,
-we hh y thiwt
-
-
-hut fithlot,
-Fmdy s he alt
-Vh th no dh foud bobt werw:s Aotnf Fhwi't whe, eusu
-
-lhh thele wewcond ary soupfy wind tDont couc ths:
-er fucwald oncli hen bos, f
-T0:1% 2.878945
-
-
-The gibberish is the networks attempt to write a play. So far, it’s not very -successful! Between the chunks of gibberish are training progress reports -that look like
- -T0:1% 2.878945
-
-
-This tells you that we are 1% through training epoch 0, and that the training -loss is about 2.88. As the training continues, the training loss will -reduce and the generated snippets will improve quickly:
- -ses, kuth
-LAs of the wish,
-As, I nos you,
-Yov not to nalll,
-Tr tot wonds.
-
-First Sondy, llt lrte, our, tw.
-
-First.
-
-BRUTUS:
-Helsting the kith gops of hoch Whay, fars surd what to,
-The cownens golt te.
-T0:12% 2.259114
-eplerrotrur tandans one wiok thy or thach and cullice ded yourssting
-And wours:
-Whed ur surt.
-
-SINENIUS:
-On we lain bith
-rerytund: tich lon hyivetetgor.
-
-VOLUONIA:
-He brich nom dove worthan then wise,
-T0:13% 2.254926
-
-
-It’s already started to figure out things about Shakespere plays – how to -spell short English words, how long lines tend to be, and that characters take -turns speaking with their names capitalized. The training loss has dropped to -2.25 and the improvement is noticeable.
- -Eventually, we will finish with the training data set and move on to a -validation cycle:
- -y fath onother,
-I sucess,
-For I me the west crare.
-
-TRANIO:
-Whow and'd have not to had you you one in my lapteny she very ame come me a gut and shourd aghir you as ignested; shend to make I strem
-To h
-T0:99% 1.924063
- notnce gaud and is nicked thou day, ha the dusing you disaid: in thim, you things in ere thee thus erile Iht that tare theme my hast thesp thou shay: thou not eaten-or-ho-bess resing: I the but had d
-T0:99% 1.923128
-V0:0% 1.678907
-V0:9% 1.700527
-V0:18% 1.733179
-V0:27% 1.714891
-V0:36% 1.716672
-V0:45% 1.782946
-V0:54% 1.835629
-V0:63% 1.876108
-V0:72% 1.906814
-V0:81% 1.924096
-V0:90% 1.954492
-V0:99% 1.969287
-serfs you'll alliencseard:
-We
-got you? before
-I say.
-
-Farstred dentlentecaly, sir, I it one bosticield
-All me the backnour mino,
-Whith capitaned mid! but stell the ifvemion
-Willerity.
-
-First Cumfol of
-T1:0% 1.885619
-
-
-Validation cycles are used to test the network to see if it has learned to -generalize – how well performs on data it hasn’t seen before (as opposed to -the training data that the network will see many times as it trains). Progress -on the validation set is also displayed with a validation progress report that -looks like
- -V0:36% 1.716672
-
-
-which means we are 36% of the way through the validation for epoch 0, and the -validation loss is about 1.72. Comparing the validation loss and the -training loss will give you an idea of how well the network is learning and -can let you know if the network is overfitting or underfitting.
- -As part of the training process, the data set (which for OMLET is the
-shakespere.txt file you gave on the command line) is divided into
-training and validation sets (by default, 95% of the data is used for
-training, but like most OMLET parameters, you can change this at compile-time).
At the end of the validation run, OMLET writes out a checkpoint file with a
-name like cp01_1.970. This saves the state of the run at the start of the
-epoch 1, after computing a validation loss of 1.970. The checkpoint is
-helpful if you need to stop and restart training. You can stop training by
-doing Control-C.
You can continue training from a previous checkpoint by providing the -checkpoint file name as the second parameter, for example:
- -./prog shakespere.txt cp01_1.970
-
-
-After the validation cycle finishes, OMLET begins the next epoch by restarting
-training at the beginning of the training set. Training continues forever,
-until you quit it with Control-C. You should monitor the checkpoints to
-see that the validation loss continues to drop. If it rises, the network has
-probably started to overfit on the training data.
Once you’ve trained the validation loss as low as it will go, you can use -OMLET to run the network in inference mode which uses the frozen checkpoint -parameters to generate data. Inference mode takes the checkpoint file as -standard input (not on the command line) and hence must be run with a -command like
- -./prog < cp55_1.807
-
-
-Running it produces an infinite amount of generated output, until you hit
-Control-C to stop it.
Note that if you decide to change networks or use a different input file, you -will want to delete all the checkpoint files because the format depends on -both the network and the input – using the wrong checkpoint is likely to -cause a crash.
- -The default network for OMLET (the one you get if you type make with the
-executable name prog) is the simplest recurrent neural network. It looks
-like
h = tanh(Wxh * x + Whh * h' + Bh)
-y = Why * h + By
-
-
-where
- -x is the input vectory is the output vectorh is the hidden state vectorh' is the previous value of hWxh, Whh, and Why are weight matricesBh and By are bias vectors.tanh is the hyperbolic tangent functionThe W’s and B’s are the trainable parameters of the network, and the
-process of training is optimizing the values of these parameters to minimize
-the loss of the network across the training set.
It is the presence of the hidden state vector that allows the RNN to -“remember” the past. We can see what would happen if we removed this hidden -state. If you type
- -make lin1
-
-
-OMLET will create an ADALINE network that does
- -y = Wxy * x + By
-
-
-This simple linear feed-forward network. You can run it with
- -./lin1 shakespeare.txt
-
-
-The linear network won’t be able to get past the gibberish stage, because it -lacks history:
- -./lin1 shakespeare.txt
-UERond w,
-
-
-Gir:
-KINof s, mesther s thouth.
-E:
-KINTret, at fu,
-GOMy t, as sth kesewit sooos atse ang k, ck,
-Sotheouserivesthecowhet been's, t he, h nre; t and, har wiread of pincer cedst sur has, ut:
-
-T14:67% 2.465115
-UKESpan,
-NGaromy soreate e m esewfoure pamitherarjulthengeoly tl.
-NG s at e! w.
-
-WAllinoully?
-Wamisw ofilem:
-I'delandinarrstath har aksubly s cath Whern t Is, weciss:
-
-GLat s; llde.
-Y aterit dsthence
-T14:67% 2.465404
-
-
-It is able to guess at what character is likely to follow the current one -(by doing a linear regression), but it lacks any history beyond that to -guide it.
- -You might be wondering about the role of the tanh function in the RNN.
-tanh acts as an activation function which adds nonlinearity
-to the network and allows it to solve complicated problems. Without
-nonlinearity, all of the linear functions would fold together into a single
-matrix-vector multiply and you’d effectively regress to the linear network
-above. Alas, even adding a nonlinearity to the feed-forward network
-(creating a perceptron) does not improve the performance because we
-still lack the history provided by the hidden state vector (although if you
-want to try it yourself, you can do so with make per1).
We can try to improve the RNN’s performance by stacking RNN modules atop each -other:
- -h1 = RNN(h1', x)
-h2 = RNN(h2', h1)
-y = Why * h2 + By
-
-
-with RNN(h, x) defined as above. Each RNN module has its own set of
-parameters and its own hidden state vector. This will improve the network’s
-performance, at the cost of a much larger parameter space
- -IMPORTANT NOTE: Since OMLET uses the system stack for network storage, -larger networks may cause OMLET to crash (typically with a message like -
Segmentation fault) unless the system stack size is first increased. -The exact command for doing so depends on your shell and your system’s -hard limits. Onsh/ksh/bashshells, you can view the hard limit -withulimit -Hsand set it withulimit -s 65532(replacing65532-with the actual hard limit). Oncsh/tcshshells, you can view -the hard limit withlimit -h stacksizeand set it with -limit stacksize 65532(replacing65532with the actual hard limit).
You can try the deeper network by doing
- -make rnn2
-
-
-(or even make rnn3 if you want a three-layer RNN) and train it with
./rnn2 shakespeare.txt
-
-
-The additional depth should allow the network to make better predictions (it -can represent more complicated history), but it may take a long time to train -– both because the network (being larger) now requires more time to train and -because of the vanishing and exploding gradient problem, which might -keep it from ever reaching its potential.
- -RNNs are particularly hard to train because the they are trained using -bankpropagation through time. The RNN is trained by effectively -converting it into a non-recurrent network by making many copies of it -and propagating the hidden state through the copies. During training, -the backpropagation through many clones of the network amplifies the -gradient, worsening the exploding and vanishing gradient problem.
- -Long Short Term Memory networks (also called LSTMs) were developed to -solve this problem. Christopher Olah gives a good description of them -at his blog posting. You can build a two-level LSTM by doing
- -make lstm2
-
-
-and train with it with
- -./lstm2 shakespeare.txt
-
-
-The LSTM is much easier to train because it explicitly decides how to update -its hidden state via “gates”. These gates are called
- -The basic LSTM equations are
- -f = sigmoid(Wxf * x + Whf * h' + Bf)
-i = sigmoid(Wxi * x + Whi * h' + Bi)
-o = sigmoid(Wxo * x + Who * h' + Bo)
-c = f * c' + i * tanh(Wxc * x + Whc * h' + Bc)
-h = o * tanh(c)
-
-
-Where
- -x is the input vectorh is the hidden state (and the output to the next layer)c is the cell state which represents the “memory” of the LSTMh' and c‘ are the previous values of h and c respectivelyf is the forget gate that tells the LSTM what portion of the hidden
-state to forgeti is the input gate that tells the LSTM what portion of the input
-vector to pay attention too is the output gate that tells the LSTM what portion of the cell
-state to use to generate the hidden stateWxf, Whf, Wxi, Whi, Wxo, Who, Wxc, and Whc are trainable
-parameter matricesBf, Bi, Bo, and Bc are trainable bias vectorstanh is the hyperbolic tangent functionsigmoid is the logistic functionThere are several LSTM variants (see C. Olah’s blog post for more -examples). One important one is the gated recurrent unit. GRUs are -simplified versions of an LSTM which combine the gates together, meaning they -require fewer learned parameters. This allows them to train faster than a -generic LSTM. You can build a two-layer GRU with
- -make gru2
-
-
-The OMLET Makefile comes with one-, two- and three-layer RNNs, LSTMs and
-GRUs, along with simpler feed-forward networks like multi-layer perceptrons and
-a linear network. This isn’t the limit of OMLET’s power – you can create your
-own networks by modifying the Makefile. Networks are passed in on the
-compiler’s command-line by using -D directives. The network is defined by
-a -DNW='...' command which consists of a series of comma-separated
-assignments. For example, the simple one-layer RNN could be defined like
-DNW=` x = I(n), hp = I(128), \
- h = C(hp, T(A(L(128, x), L(128, hp)))), \
- y = L(n, h)'
-
-
-The network declares x as an input vector (there must be a declaration for
-x). It is declared as I(n), which is an input vector of size n, which
-is the number of characters of the input alphabet (OMLET computes this from
-the input file at the start of training). OMLET will arrange to present the
-input character as a one-hot vector based on the current input
-character.
The second declaration, hp, declares the previous hidden state vector (what
-we called h' above). We declare this to be of size 128 – an arbitrary
-choice. A larger state vector can (theoretically) carry more state, but at
-a cost of larger parameter matrices and longer training time. You can
-experiment with increasing the hidden vector size and see.
The third line is the core of the RNN. It sets h, the hidden vector output
-to be the sum of two linear elements specified by L. The L function
-takes two parameters – the output vector size (which must match the size of
-h) and the input vector. L will compute y = W * x + B where each L
-has its own W (weight) and B (bias) training parameters. Both x and
-hp are sent through L and the result passed through the A function,
-which does vector addition. That result is passed through T which does
-element-wise tanh activation.
Next, we wrap the whole thing with the C function. C connects hp
-with h, causing the new value of h to be passed to the hp vector on
-the next iteration of the algorithm (allowing the RNN to retain state in h).
Finally, the whole result is passed through another instance of L, this time
-producing a vector of size n, which will have the negative log
-likelihood function. This is assigned to y, which is the output of
-the network (and hence must also be declared).
OMLET will take the y result and pass it through the softmax function,
-which converts the log probabilities into a probability distribution. In
-inference mode, this is used to select the next character to emit. In
-training mode, this is used to generate the loss which is backpropagated.
As an example of a more complicated network, we can look at a two-layer -GRU network:
- --DHS=128, \
--DNW=' x = I(n), \
- y = L(n, MD(MD(x)))' \
--DBK=' hp = I(HS), \
- z = S(A(L(HS, x), L(HS, hp))), \
- r = S(A(L(HS, x), L(HS, hp))), \
- c = T(A(L(HS, x), L(HS, hp))), \
- zc = OG(1, -1, z), \
- h = C(hp, A(M(zc, hp), M(z, c))), \
- y = h'
-
-
-We are using a few new tricks here – first, we are defining HS as the size
-of the hidden and cell vectors. There’s nothing special about this name, its
-just convenient to specify it so we don’t have a bunch of constants in the
-code. Second, the network itself is very simple – it declares x and has
-the matrix that converts the HS-sized hidden vector back to the n-sized
-alphabet vector… but it now calls MD, which is the user-definable
-module (here we are using it twice, to have two cascaded GRU blocks). The
-MD function performs the sub-network defined by the BK compile-time
-parameter (specified in the -DBK='...' setting). This sub-module again
-takes an x parameter and produces a y output. Inside it, we declare
-hp and h, the previous and current state vector, plus equations for the
-various GRU gates (these use S for the sigmoid activation function).
-One final new call is OG which does offset and gain, performing
-y = offset + gain * x where offset (the first parameter) and gain (the
-second) are constants. We are using this here to compute (1 - z) for the
-GRU’s linear interpolator.
The full set of available function blocks follows:
- -I(s): declares a vector (input or state) of size sL(s, x): learnable linear function y = W * x + B with an output vector
-size of sCM(x): learnable element-wise gain function y = W * xA(a, b): element-wise add: y = a + bM(a, b): element-wise multiply: y = a * bS(x): sigmoid activation function y = sigmoid(x)T(x): hyperbolic tangent activation function y = tanh(x)C(xp, x): copy x to xp in the next time step (propagate through
- time)OG(o, g, x): apply a constant offset and gain: y = o + g * xMD(x): apply the sub-network specified by BKNote: even if you don’t use MD in your network, you should still define
-BK by adding -DBK='y=x' to the command line, otherwise you will get a
-compile-time error.
OMLET has a large number of training and inference parameters which can be
-changed by the user. All of these are set by -D on the compile command line.
-The list of hyperparameters follows:
TP: Temperature parameter for use in inference mode. This divides the
-log probabilities before softmax. A low temperature makes the model choose
-safer but more boring choices. A high temperature takes more risks but
-makes more mistakes. Default is 1.0, which uses the computed
-probabilities.TR: The percentage of batches in the input data set that will be used
-for training. The default value of 0.95 sets this as 95%.LR: The initial learning rate, The default is 0.002.LE: The epoch where the learning rate will start decaying. Defaults to
-epoch 10.LD: Learning rate decay, per epoch (after LE epochs). The learning
-rate is scaled by this number. Default is 0.97WD: Weight-decay parameter, to promote regularizaiton. The default
-is 0.00008.RS: The random scale for weight initialization. Weight parameters will
-be initialized to be between -RS to +RS. The default is 0.15.CL: Clamp value for gradients. Gradients will be limited to the range
--CL to +CL. Default is 5.B1: Momentum mean parameter for Adam optimizer. Set to 0.9.B2: Momentum variance parameter for Adam optimizer, Set to 0.999.EP: Epsilon parameter for Adam, to provide numerical stability. Set to
-0.00000001.DI: How often to print a training or validation progress message and
-inference snippet. The default prints every 100 training batches.SL: The number of characters to print when doing an inference snippet.
-Default is 200.PF: Format string for the checkpoint filename. The default is
-"cp%02d_%.3f" which includes the epoch and validation loss. You may
-wish to add a subdirectory to the name to keep checkpoint files out of
-the current directory.![]() |
-© Copyright 1984-2019,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Timo Poikola
-https://ig.fi/other/ioccc
-Twitter: @timpoiko
make prog
-./prog 512 ./prog
-
-sleep 86400; make clobber prog
-./prog 512 ./prog
-
-sleep 86400; make clobber prog
-./prog 512 ./prog
-
-
-If you don't have a few days, try:
-
-TZ=UTC24 make clobber prog
-./prog 512 ./prog
-
-TZ=UTC48 make clobber prog
-./prog 512 ./prog
-
-
-Do you have the time to see what this program does? Think again, come back and try again.
- -Note that 2 can be said to be the least odd prime because it is the greatest even prime. -Moreover 2 can be also said to be the greatest odd prime because it is the least even prime.
- -The source code layout and some of the variable names honors the ski jumping accomplishments of -Matti Nykänen.
- -gcc -O0 -o prog prog.c
-
-
-or
- -clang -O[0123s] -o prog prog.c
-
-
-You can generate an A3 sized poster by make docs. This command creates a pdf file poikola.pdf.
- -An old wise man mumbled to me:
- -- -Implement a program, which can calculate SHA-3 checksum for a file
I think it is easy, but the wizard didn’t stop yet:
- -- -and primes and Fibonacci numbers.
Still easy. But the Gandalf the Grey impersonator is not ready:
- -- -But use only main(), and do not use math.h nor predefined stuff at all. But wait, there are some more rules: This -work should reflect the extraordinary mind of Matti Nykänen, -the all-time best ski jumper and -amateur philosopher, who passed away on fourth of -February 2019.
So, I followed the rules given by Gandalf the White and the Judges of IOCCC. Output of iocccsize,
-using the 2019 version of iocccsize, is carefully selected.
-For the sake of clarity, I used single letter variables in the code. I also avoided unnecessary use of functions.
-Like a tripundra, this program has three levels. In order to reveal all of them, you have to compile this program
-on three consecutive days.
As this is a contest for obfuscated code, the program does not perform unnecessary checks, but either fails or gets
-stuck if invoked erroneously. The program is invoked in this way: ./prog <integer> <file> in where <integer> is
-224, 256, 384, 512 or even 1024. Yes, I know 1024 is not a supported length of output, but as I said, the program does
-not validate its input in any way. These same parameters should be given in calculating a Fibonacci sequence or prime
-numbers. Please note that maximum file size is one gigabyte.
Matti Nykänen: Every time I jump, and I get that feeling of bon voyage, the feeling that I’ve been here -before.
- -Matti Nykänen: When you are about to jump, you are all alone and have to make your own decisions. Up there, -it’s all up yours.
- -This code has some jumping too. I used some gotos instead of longjmp(). Some Finnish ski jumping sites are
-used as labels, however, there is lahti instead of salpausselkä.
Tested against test vectors.
-Clang-4.0: For optimization levels [0123s], the program compiles and produces correct output for every tested vector using
-c11, c89, c90, c99, gnu11, gnu1x, gnu89, gnu90, gnu99, iso9899:1990, iso9899:199409, iso9899:1999 and
-iso9899:2011 as argument of -std=
Gcc-6: For optimization level 0, correct output using -c11, c99, gnu11, gnu1x, gnu89, gnu90, gnu99, iso9899:1999 and iso9899:2011
- -For obvious reason, the oddest prime is missing from output.
- -Gcc and clang are very fragile compilers. I spent numerous hours trying to achieve exactly the same output from -different optimization levels and compilers. Small change in code can produce really unexpected results, i.e. the compiler -can skip a few expressions or statements without obvious reason.
- -Please scroll down if you want to see spoilers.
- -It is commonly believed that Mike Keith’s algorithm published in Journal of
-Recreational Mathematics, Vol. 22, No. 4, 1990, p. 280, is the shortest way to calculate weekday for given date.
-Keith’s algorithm:
-(d+=m<3?y--:y-2,23*m/9+d+4+y/4-y/100+y/400)%7
-My algorithm: I noticed that
-(23*m/9+(m<3?y--:y-2)+d+4+y/4-y/100+y/400)%7
-is one character shorter. In my solution, m<3?y--:y-2 is used directly, instead of assign value for d.
Q is pronounced in Finnish exactly like “kuu”, a word for month or the Moon. So, Q = k is intended.
Last term of outputted Fibonacci sequence is the last one smaller than 264. It is plain coincidence (but a funny) -that value of ‘^’ is 94 in ASCII table.
- -For prime calculations: I recycled code from my high school C-programming course. Originally, I wrote it over 20 years -ago. My teacher said that it is (too) complicated to use bits stored in arrays, so I did it.
- -Cody: I really like that you enjoyed my previous entry. I hope that you will like this entry too.
-Because I did not want to give too many clues to Judges, I tried to write this entry in a different way
-than Most Stellar, but in this code there is at least one recycled thing from it. By the way,
-answers to questions: 1. 255. 2. Try to compare binary representations of those floats and binary representation
-of the string “25th IOCCC!”. 3. I don’t know. I used standard trigonometric functions from math.h for rotating the Big Dipper
-and later replaced those functions with my own implementations. But there was a bug in my code and the effect was more
-beautiful than intended. I did not even debug this bug and now it works as a feature. 4. It is not possible. If you
-change a single bit, the Fletcher 16 checksum does not match anymore and goto jumps to end of the code.
I see that Volker Diels-Grabsch’s winner is awarded in category Most self-aware. In last year, my entry incorporates
-the Fletcher 16 algorithm to ensure integrity of code. One of my first ideas for this year was to do the same thing,
-but with SHA-3. Using Fletcher 16, calculating a checksum which matches with sleeping time factor took about one minute.
-I realized that SHA-3 even with 224-bit output could take too much CPU time.
I would like to say thanks to PSP, because there were not too much interrupts during the coding phase.
- -![]() |
-© Copyright 1984-2019,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
Don Yang
-http://uguu.org/
make
-
-./prog sample_input.txt a b c d
-
-cat a
-
-cat b
-
-cat c
-
-cat d
-
-cat a b c d | ./prog
-
-
-./prog prog.c a b c d e
-
-cat a
-
-cat b
-
-cat c
-
-cat d
-
-cat e
-
-cat a b c d e | ./prog
-
-cat a b c d e | ./prog | diff - prog.c
-
-
-Do you understand how this program works? -You may have to go over and over the output again.
- -Scramble/unscramble to single file:
- -./prog original.txt > scrambled.txt
-
-./prog < scrambled.txt > unscrambled.txt
-
-
-Scramble/unscramble to multiple files:
- -./prog input.txt output1.txt output2.txt ...
-
-cat output1.txt output2.txt ... | ./prog > unscrambled.txt
-
-
-Re-scramble:
- -./prog original.txt | ./prog - > scrambled1.txt
-./prog original.txt | ./prog - | ./prog - > scrambled2.txt
-./prog original.txt | ./prog - | ./prog - | ... > scrambled3.txt
-
-
-Scramble slowly:
- -./prog input.txt | ruby prog.c
-
-
-Input must be in UTF-8 encoding.
- -This is a text scrambling utility. To scramble text, specify input -file name as the first argument:
- -./prog input.txt > output.txt
-
-
-If original input file was small enough to fit in your terminal, you
-can simply use cat to unscramble the output text.
cat output.txt
-
-
-It might seem like nothing was scrambled, but you can try passing the
-output through strings(1) and see that most of the original strings
-are gone. What happened is that the original text has been shuffled
-with ANSI cursor positioning codes inserted such that characters are
-printed in random order. This effect is more visible if there is a
-delay after each character is printed. For convenience, an utility is
-included in the source to output characters slowly:
./prog input.txt | ruby prog.c
-
-
-Scrambling order is deterministic, but you can reshuffle the output by
-piping it through the same utility again, by specifying - as the
-first argument:
./prog input.txt | ./prog - | ./prog - | ...
-
-
-You can also split the input to multiple files, each getting a subset -of the original input characters:
- -./prog input.txt output1.txt output2.txt ...
-cat output1.txt output2.txt ... > unscrambled.txt
-
-
-You can only unscramble files with cat if the input fits in a single
-terminal screen. If you don’t know what will be the terminal size of
-the recipient, note that prog.c will fit in a 80x25 terminal, so a
-good guideline is to pick files that have fewer rows and columns than
-prog.c.
For files that are larger than your terminal window, cat will not be
-sufficient for unscrambling because any scrolling causes the character
-positions to be misaligned. But fear not, this utility also includes
-unscrambling functionality. If no argument is specified, input will
-be read through stdin and unscrambled to stdout:
./prog < scrambled.txt > unscrambled.txt
-
-
-Where this is useful is that if you scramble the input to multiple -files and unscramble each output files individually, those output -files can be printed on transparencies and distributed separately.
- -./prog input.txt output1.txt output2.txt output3.txt
-./prog < output1.txt > layer1.txt
-./prog < output2.txt > layer2.txt
-./prog < output3.txt > layer3.txt
-
-
-In other words, this is a utility for facilitating -visual cryptography.
- -This utility can also be used just for removing trailing whitespaces -and expanding tabs to 8 spaces.
- -./prog input.txt | ./prog
-
-
-A simple text scrambling utility might not have required a screenful
-of code, but this particular one natively supports UTF-8.
-Specifically: individual UTF-8 byte sequences will not be split into
-broken ones, and the utility is aware of full-width versus half-width
-differences such that cursor is positioned correctly for most CJK
-input. sample_input.txt demonstrates this feature with a mix of
-Basic Latin and Japanese characters.
Output cursor positions will most definitely be wrong for inputs -containing combining characters and right-to-left text, but it should -be possible to unscramble those text back to the original using this -same utility, since the utility is self-consistent in how cursor -positions are handled.
- -If any file can not be opened for reading or writing, an error is -printed to stderr, and the utility will exit with nonzero status.
- -If there isn’t enough memory, the utility will likely crash.
- -If input contains CR-LF end of line sequences, those CRs are silently -dropped. In fact, most control codes are silently ignored except line -feeds (preserved) and tabs (expanded to 8 spaces).
- -Verified to work and compiles without warnings on these environments:
- -I tried really hard to make prog.c fit in a 80x25 terminal without
-wrapping. If I were not constrained by space, I would have made an
-ASCII art out of it. violet.c is that program, and also comes with
-the minor benefit of supporting lines longer than a million columns
-depending on sizeof(int).
Violet is named after “Violet Evergarden”, the character who is highly -skilled in writing letters.
- -![]() |
-© Copyright 1984-2019,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
- The International Obfuscated C Code Contest
-A 27th IOCCC Winner
-Dave Burton
-http://snox.net/ioccc
-Twitter: @lv2jmp
The code for this entry can be found in prog.c
- -make
-./prog
-
-
-./prog 128
-
-./prog_be 128
-
-./prog 170
-
-./prog 85
-
-
-This tiny one-liner is a bit-twiddlers delight! It does all of the work -without looping.
- -To understand how it works, a good place to start is to look at the hex -value that results when the two magic constants are XOR'ed.
- -Once you’ve figured out what happens with one set of constants, how can -choosing new constants, but using the same computation generate a reversed -result?
- -Invoke this with a single non-negative integer less than 256, and a useful transformation occurs.
- -Exporting the constants B,I,T,S to the makefile allows the code -to be compiled for either LE (little-endian) or BE (big-endian) machines(!!), -so they are truly configuration parameters, not logic.
- -One ping argument only. It will SEGV on zero arguments, and
-display strange results if more than one argument.
Small, non-negative integers only. Useful range is 0 .. 511, sorta, for LE; 0 .. 255 for BE. -Bonus points if you can explain why the limits work this way.
- -ASCII character set, 64-bit long longs are required.
- -v,a,r,i,a,b,l,e,s_NAME the operation.
- -No loops, no branches?!?
- -Compiles cleanly under clang -Wall -Weverything -pedantic,
-but you need to add --include stdio.h --include stdlib.h for the printf(3) and atoi(3).
On a little-endian machine:
- -clang -include stdio.h -include stdlib.h -Wall -Weverything -pedantic -DB=6945503773712347754LL -DI=5859838231191962459LL -DT=0 -DS=7 -o prog prog.c
-
-
-On a big-endian machine:
- -clang -include stdio.h -include stdlib.h -Wall -Weverything -pedantic -DB=7091606191627001958LL -DI=6006468689561538903LL -DT=1 -DS=0 -o prog.be prog.c
-
-
-You might be interested to compile it both ways on the same host, and try:
- -./prog 1; ./prog.be 1
-
-![]() |
-© Copyright 1984-2020,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
- The International Obfuscated C Code Contest
-A 27th IOCCC Winner
-Nicholas Carlini nicholas@carlini.com
-https://nicholas.carlini.com
The code for this entry can be found in prog.c
- -make
-./prog
-
-
-# Play with a friend, P1 and P2, squares are numbered 1..9
-./prog
-
-
-This program consists of a single print statement wrapped in a while loop. You -would not think that this would amount to much, but you would be very, very -wrong. A clue to what is happening and how this works is encoded in the -ASCII art of the program source.
- -HOW ABOUT A NICE GAME OF CHESSTIC-TAC-TOE?
cc -o prog prog.c
-./prog
-
-
-Alternates between P1 and P2. Enter a digit [1-9] to move:
- -1 | 2 | 3
----------
-4 | 5 | 6
----------
-7 | 8 | 9
-
-
-The game ends if:
- -Bad things may happen if the entered move is outside of the range [1..9]
- -While the game will stop if one player tries to overwrite another player’s move, -it will happily allow a player to move on top of themself. However, given that -this is an effective no-op and guarantees a loss to a competent opponent, if you -do this you probably deserve to lose.
- -Your terminal may beep at you every turn. We’ll call this a feature that … -the program … is hard at work processing your move! That is! Please be -patient.
- -After macro expansion the format string is roughly 100K. This makes some -compilers unhappy, and others slow. (For example, passing GCC the flags -Wall --Wextra -pedantic will result in a warning about oversized strings.)
- -Under some terminals the program may exit early. The following should always work:
- -echo "1 2 3 4 5 6 7" | ./prog
-
-
-The entirety of the program consists of a single iterated call to printf.
- -int main() {
- while(*d) printf(fmt, arg);
-}
-
-
-Here, fmt is a single string, and arg is a series of arguments to printf.
While its primary purpose is to serve as The One True Debugger, printf also happens -to be Turing complete. (See “Control-Flow Bending: On the Effectiveness of Control-Flow -Integrity” where we introduced this in an actual, published, academic paper. The -things you can get away with sometimes.)
- -We abuse this fact to implement the logic of tic-tac-toe entirely within
-this one printf call (and a call to scanf() to read user input).
Here’s (briefly) how it works.
- -This program uses three printf format specifiers.
-- %d takes an integer argument and prints it
-- %s takes a string argument and prints it
-- %n takes a pointer and writes (!!) the number of bytes printed so far.
Okay, everyone probably knows this. Let’s get a bit more advanced.
- -Format specifiers can take extra “arguments”.
-- "%hhn": store the number of bytes written mod 256 to the char pointer
-- "%2$d": print argument 2 to printf (and not the sequentially next argument)
-- "%8d": pad the printed integer to 8 characters
-- "%3$.*4$d": print argument 3 to printf with as many zeros as in argument 4.
For example, the following expression
- -printf("%1$.*2$d%3$hhn", 5, 10, &x)
-
-
-will have the same effect as if we had written
- -x = 10;
-
-
-because it will print out 0000000005 (5 padded to size 10) and then write the
-number of bytes written to x.
Alright, now we can get to the real fun.
- -We perform arbitrary computation with printf treating memory as a binary
-array—one bit per pair of bytes:
-- The zero bit is represented by the sequence 00 00
-- The one-bit is represented by the sequence xx 00 where xx is any non-zero byte.
We can use format strings to compute the OR/NOT of arbitrary “bits”.
- -We’ll start with the simplest, OR:
- -printf("%1$s%2$s%3$hhn", a, b, c)
-
-
-will compute
- -*c = strlen(a) + strlen(b)
-
-
-but given that strlen(x) is 1 for a 1-bit and 0 for a 0-bit, we have
*c = a | b
-
-
-Computing the NOT of a single value is also easy:
- -printf("%1$255d%1$s%hhn", a, b)
-
-
-will compute
- -*b = (strlen(a)+255)%256 = strlen(a)-1
-
-
-and again, because strlen(x) is either 1 or 0 we have
*c = !b
-
-
-From here we can compute any binary circuit. Doing something efficient, -though, still takes work.
- -The game itself is represented as a board of 18 bits, 9 bits per player, along -with a turn counter that alternates between player 1 and player 2.
- -To detect who has won, we implement the following logic. Let A, B, and C be -pointers to three squares in a row to test, and D be where to save if there is a -win or not.
- -"%A$s%B$s%C$s%1$253d%11$hhn" // r11 = !(*A & *B & *C)
-ZERO
-"%11$s%1$255d%11hhn" // r11 = !r11
-ZERO
-"%11$s%D$s%D$hhn" // *D = *D | r11
-
-
-That is, we set *D to 1 if there is a three-in-a-row. We repeat this for all
-possible three-in-a-row configurations, for both players.
The ZERO macro ensures that the number of bytes written out is 0 mod 256 with -the following expression
- -"%1$hhn%1$s" (repeated 256 times)
-
-
-where argument 1 is a pointer to a temporary variable followed by a null byte.
- -This works because if the current count is 0 mod 256, then “%1$hhn” will write -zero to argument 1 and then “%1$s” will never emit any text. If, on the other -hand, the count is not 0 mod 256, a length-1 string will be written to argument -1, and then “%1$s” will increment the count by one. By repeating this 256 -times we’re eventually going to reach 0 mod 256.
- -Checking if there has been an invalid move is achieved similarly.
- -In order to decide what to print out, we have to cast the “in-memory” array of -bits to Xs and Os to print out. This is actually rather straightforward. Given -in 1$ the pointer to player 1’s square, and 2$ the pointer to player 2’s, and -in 3$ the pointer to the board string, we can compute
- -"%1$s" (repeated 47 times) "%2$s" (repeated 56 times) %1$32d%3$hhn"
-
-
-which will, in effect, compute
- -*r3 = (*r1) * 47 + (*r2) * 56 + 32
-
-
-which will output ‘ ’ if neither are true, ‘X’ if r1 is, or ‘O’ if r2 is.
- -In order to be able to finally display the board, while still only using one -printf statement, we finish the statement with
- -"\n\033[2J\n%26$s"
-
-
-which is the escape sequence to clear the screen, and then prints argument 26. -Argument 26 is a pointer to a char* in memory, that initially is undefined, -but within the printf statement we will construct this string to look like a -tic-tac-toe board.
- -After the board, we need to print one of the following strings:
- -P1>_
-P2>_
-P1 WINS
-P2 WINS
-P1 TIES
-P2 TIES
-
-
-Depending on if it’s P1 or P2’s turn to move, the game is over and someone -won, or the game is over and it is a draw.
- -This turns out not to be as hard as it might look. Using the same trick as -before, we set byte four to be
- -*byte4 = is_win * 'W' + is_tie * 'T'
-
-
-The byte 'I' and 'S' can always be the same, and we do the same for 'E'/'N'.
We do this same on-the-fly creation of the scanf() format string, but for a
-different reason. We first want to run printf() to show the first board, and
-then alternate between runs to scanf() and printf() reading and then
-displaying moves. importantly, we do not want a final scanf when the game
-ends. It should just exit.
One option would be to implement the logic as
- -printf()
-while (*ok) {
- scanf();
- printf();
-}
-
-
-but this would DOUBLE the number of calls to printf we require. So instead we -implement it like this
- -while (*ok) {
- scanf();
- printf();
-}
-
-
-(In reality we actually pass scanf() as an argument to avoid the extra
-statement, but it has the same effect.)
Notice there is now no initial printf(). In order make sure the program doesn’t
-block before the first printf(), but we initialize the scanf() format to the null
-string so that it returns right away without blocking. The first time the printf()
-call runs, it writes out “%hhd” to create the scanf() format string.
![]() |
-© Copyright 1984-2020,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
- The International Obfuscated C Code Contest
-A 27th IOCCC Winner
-Yusuke Endoh
-Twitter: @mametter
The code for this entry can be found in prog.c
- -make
-./prog
-
-
-# Try resizing the terminal window before the first click.
-
-# Try resizing the terminal window after the first click.
-
-./prog ioccc.txt
-
-./prog unwinnable.txt
-
-
-When playing Minesweeper, a misclick might ruin a game, so why not leave the routine to the computer? -This program automatically uncovers mines according to several rules, and leaves guessing (and applying -the most straightforward of the rules – just for fun, perhaps?) to the user.
- -Try creating your own input files according to the author’s remarks. Did you encounter any problems?
- -The submission was in violation of the “2053” size rule by one character, likely a late typo. It was easy to fix.
- -Minesweeper is a game to sweep mines, as you know. The task consists of two parts:
- -A) choose a random cell based on your sixth sense -B) identify a non-mine cell based on logical inference
- -However, (B) is error-prone, and a waste of time. You must use a computer to do such a boring task!
- -This program is a semi-automatic minesweeper which does Part (B) automatically. -All you have to do is (A). You can test if you are lucky or not.
- -It uses ncurses:
- -$ gcc -o prog prog.c -lncurses
-$ ./prog
-
-
-You will see a terminal-wide field of a minesweeper. Probe a cell by mouse click. -If a cell turns out to have a mine (or not), the program determines whether its neighbors have a mine or not, and automatically probes (or flags) the cell.
- -R: new game (You can also click the smiley face at the top line.)Q: quitThe program uses four types of local inference:
- -If the number of a cell is equal to the count of the flagged neighbors, all the unprobed neighbors are probed.
- -Example:
- -
- ? ? ? . . .
- ? 3 ? => . 3 .
- ! ! ! ! ! !
-
Note that ? is a unprobed cell (it is unknown whether the cell has a mine or not); ! is a flagged cell (it is already known that the cell has a mine); and . is a probed cell (it is already known that the cell has no mine).
If the number of a cell is equal to the count of the unprobed or flagged neighbors, all the unprobed neighbors are flagged,
- -Example:
- -
- . ? ? . ! !
- . 4 ? => . 4 !
- . 2 ! . 2 !
-
Consider two number cells A and B. If A is equal to the difference of B and the count of B’s unprobed and flagged neighbors that are not A’s neighbors, all A’s unprobed neighbors that are not B’s neighbors are probed.
- -Example:
- -
- ? ? ? . . .
- ? 1 ? ? => . 1 ? ?
- ? ? 4 . . ? 4 .
- ? . ! ? . !
-
A and B are probed cells whose numbers are, respectively, 1 and 4. The count of B’s unprobed and flagged neighbors that are not A’s neighbors is three (one ! and two ?s). Since A (1) == B (4) - the count (3), the left and top unprobed cells are probed.
Consider two number cells A and B. If B is equal to the difference of A and the count of A’s unprobed and flagged neighbors that are not B’s neighbors, all A’s unprobed neighbors that are not B’s neighbors are flagged.
- -
- ? ? ? ? ! ? ? ?
- ? 3 1 2 => ! 3 1 2
- 2 2 . . 2 2 . .
-
A and B are probed cells whose numbers are, respectively, 3 and 1. The count of A’s unprobed and flagged neighbors that are not B’s neighbors is two (left ?s). Since B (1) == A (3) - the count (2), the left unprobed cells are flagged.
Interestingly, these complex rules can be integrated to one simple rule. Analyze the code.
- -You can also play with a prepared map.
- -$ ./prog ioccc.txt
-
-
-The format of the text is:
- -width height number-of-mines priorities-of-each-cell...
-
-
-There are mines in a cell whose “priorities-of-each-cell” is less than “number-of-mines”. -(But the mine in the first-clicked cell is removed.)
- -The judges pointed out a bug of the original version that I submitted (prog.orig.c). Because this program does not provide a feature to flag unprobed cells manually, we can do nothing if the number of unprobed cells are equal to the number of mines remaining; unwinnable.txt is an example for such a case. -Thus, I implemented an additional rule to flag all unprobed cells in such a case into the final version (prog.c).
- -Ilya Kurdyukov also pointed out a warning “ignoring return value of ‘fscanf’” only when “-O3” is used. So I changed the code a little to pretend to use the return value of fscanf.
- -Don Yang (omoikane) contributed another example map “megumin.txt” which is the Explosion Arch-Wizard.
-![]() |
-© Copyright 1984-2020,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
- The International Obfuscated C Code Contest
-A 27th IOCCC Winner
-Yusuke Endoh
-Twitter: @mametter
The code for this entry can be found in prog.c
- -make
-./prog
-
-
-./prog
-
-./prog hello.txt
-
-./prog yoda.txt
-
-./prog bear.txt
-
-
-Clever use of the C99 complex data type. The spoiler.zip file contains clues -as to how some winning authors create / edit programs into ASCII shapes.
- -With the source from the spoiler.zip file could you make the code render for a -larger terminal window? How about adding more glyphs?
- -No! Try not. Do, or do not. There is no try.
- -$ gcc -std=c99 prog.c
-$ a.out
-$ a.out hello.txt
-$ a.out yoda.txt
-$ a.out bear.txt
-
-
-See spoiler.zip for the source code. -The 16th most common password on the Internet in 2017 (according to Splash Data) the password is.
-![]() |
-© Copyright 1984-2020,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
- The International Obfuscated C Code Contest
-A 27th IOCCC Winner
-Yusuke Endoh
-Twitter: @mametter
The code for this entry can be found in prog.c
- -make
-./prog
-
-
-./run_clock
-# And watch closely for 15-20 seconds
-
-
-You may be tempted to use a mirror. Resist the temptation! Try figuring out how the clock hands are drawn. -Can you change the program to make it draw a familiar (non-mirrored) clock face? Can you add the second hand?
- -When using the run_clock shell script, your perception of time might depend on what time it is.
Prepare a mirror!
- -$ make clock
-
-
-Note: You need to recompile it each run.
- -prog.alt.c is an alternate version that uses Unicode letters, which was suggested by the judges.
-![]() |
-© Copyright 1984-2020,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
- The International Obfuscated C Code Contest
-A 27th IOCCC Winner
-Cody Boone Ferguson ioccc@xexyl.net
-https://ioccc.xexyl.net
-Twitter: @xexyl
The code for this entry can be found in prog.c
- -make
-WAIT=100 WALLS=0 CANNIBAL=0 ./prog
-# Start pressing some arrow keys
-
-
-make test
-
-WAIT=75 WALLS=1 CANNIBAL=1 ./prog
-
-./prog
-
-SIZE=-1 ./prog
-
-CANNIBAL=1 WALLS=1 WAIT=50 EVADE=200 ./prog
-
-WAIT=75 GROW=-1 SIZE=5 CANNIBAL=1 ./prog
-
-CANNIBAL=1 WALLS=1 WAIT=0 EVADE=1 MAXSIZE=10 ./prog
-
-
-As the Gadsden flag warns, beware of the snake! -This game has a number of configurable pitfalls including walls and snakes.
- -There is a good deal of useful documentation that is provided with this entry:
- -Documented game features!
- -Information about terminal capabilities, dimensions (setting and how to restore sanity if it causes any problems) as well as colours (limitations etc.).
- -Workaround for various game features
- -Bugs and things that might seem like bugs but are not.
- - - - -Because most of us could use some Double-layered Chocolate Fudge Cake!
- -Read ONLY if you really must give up trying to de-obfuscate!
- -Snake has two cheat modes (passable walls and self [cannibalism]), a drawing (or -practising) mode, can play by itself (and win!), is coloured (included -snake-colours.sh and play.sh scripts compile in player-selected -colours) and there are many other play modes (many more can be devised with the -imagination and the environmental variables; see gameplay.markdown / -gameplay.html for many examples) and options. You can pause and there’s -even a built-in test unit for some features! The following variables change the -game in the following ways (all can be combined):
- -The speed of the snake (how many milliseconds to WAIT for input before -moving; default 231 milliseconds and you can move faster by pressing a -direction key quicker or even holding it down).
If the bug (to eat) will move (EVADE) after user-specified number of snake -moves (default 300, 0 disables).
If the snake can go through WALLS (coming out at the opposite wall) -(default 1, yes).
If the snake can go through itself (CANNIBAL) (default 0, no).
The initial SIZE of the snake (default 5).
The size the snake must become in order to win the game (MAXSIZE, default 997).
How much to GROW each time a bug is eaten (default 5, can be negative).
How many moves (SHED, default 0, disabled) before ‘stretching’ (grow) -(SHEDS, default 5; can be negative). This is how snakes grow in the wild so is a -misnomer here because snakes don’t grow in the manner that the original -Snake game was designed.
- -A drawing/practising mode (WAIT < 0 makes timeout() set blocking read).
Computer plays the game (WAIT=0) EPILEPSY/STIMULATION OVERLOAD WARNING -included in the relevant section (this goes for a low EVADE value too).
Grow-Shrink mode (Positive and Negative Winning) mode (see -gameplay.markdown for more details).
The dimensions of the game (this is actually a terminal thing but I document -how to do this and its potential pitfalls) (LINES , COLUMNS).
There are no complicated command line invocations; it’s just a matter of passing -into the game descriptively named variables and I include a script that sets up -many different gameplay modes (gameplay.markdown and play.sh).
- -The gameplay.markdown (gameplay.html) file has all the information on -what the game looks like, how to play, the different types of modes (that I have -thought of so far) including all those in the above list. Along with the -play.sh and snake-colours.sh scripts it’s probably the most important -file for players.
- -The gameplay file is long but it includes game printouts as well as explaining -the many different gameplay modes. The play.sh script automates most (if -not all) of the gameplay modes described in the gameplay file (it also -allows you to change colours like snake-colours.sh) as well as the judges' -suggestions (that I don’t document so as to not spoil them). You can pass in -environmental variables to both scripts though obviously some will conflict with -different options in play.sh.
- -Probably just as important is chocolate-cake.html with an old but wonderful -recipe (because the judges love chocolate and who can blame them? - also it goes -with one of the IAQs I include later).
- -The troubleshooting.markdown (troubleshooting.html) file has some advice -on potential problems (and things that might appear to be problems at first -glance but are not) that I have thought of or encountered.
- -The terminals.markdown (terminals.html) has a variety of information -specific to terminals from input/directions, dimensions, sanity and colours: a -sort of troubleshooting guide for terminals with some additional information.
- -The spoilers.markdown has a variety of information including some of the -obfuscation techniques and a bit of how it works.
- -The bugs.markdown (bugs.html) has a list of known bugs and things that -look like bugs but aren’t as well as documenting a built-in test unit for some -features.
- -Because all IOCCC entries should have a man page I have included one (even -though much of it is what’s also above). To render try:
- - man ./snake.1
-
-
-The COMPILING file has a few portability notes and the HACKING file has -some information on how one might modify things, things that could be -implemented (and how to/how not to go about some of the things) as well as some -other information on the entry (some of which is deliberately not true - a -variation of misleading comments). These files are probably insignificant.
- -I will have more information about this entry at -https://ioccc.xexyl.net/2020/snake after the winning entries have been -published.
- -For the files I recommend looking at the html files with a browser; this -particularly goes for the gameplay.html, bugs.html, terminals.html -and troubleshooting.html - along with the most important one -chocolate-cake.html.
- - - -NAQs/IAQs (Never/Infrequently Asked Questions)
- -‘The screen keeps showing bugs!’ Well yes, that’s rather the point! Help out -by eating them. Keep eating them until you win! Then you will have the -satisfaction of getting rid of the non-bug bugs! :)
The Snake in the game doesn’t fly (yes there are flying snakes). For -other snake madness see the reports of ‘human snakes’.
Technically walls, snakeskin and the snake itself would not be an obstacle -in real life. The shed snakeskin is not an obstacle but walls can be and -so can the snake itself. Also snakes grow by moulting (technical term for -shedding) so when the snake leaves its snakeskin behind it really ought to -grow but instead it shrinks; this means negative shedding ought to have the -snake grow and positive shedding have the snake - what? It’s a misnomer: it -took fewer bytes and the negative shedding is a positive consequence of -unsigned arithmetic.
On a more serious note look at bugs.markdown (bugs.html).
- -There are two in particular. First is a long time mate of mine wrote a bash -implementation of Snake several years ago (uncoloured, no cheat modes, hardcoded -dimensions etc. - in fact everything was hardcoded).
- -Back then I had thought of making a curses implementation of it but I never got -round to it. When the judges announced that the 2020 IOCCC contest would be open -from late December 2019 through 15 March 2020 I started thinking again on what -might be a good entry. By chance I thought of the Snake game and so wrote it -finishing the implementation of everything on 8 November 2019. Did I say -everything? That’s an unintentional lie; I thought it was everything but I -implemented many new things after that. In fact I have numerous times thought I -was done only to have added yet another feature - or two or three or more!
- -Second is the old Atari game Surround. There were a few modes as I recall. -The object of the game was to surround your opponent so that they would run into -you, the wall or themselves. The opponent was either the computer or another -player.
- -In one mode you could go through walls (that’s where I got the idea to do
-likewise). There was also a drawing mode where you could just move round making
-different designs though that this is in my entry is a happy coincidence
-(because timeout() will block when it gets a negative value). It’s true that
-in my Snake it’s not quite the same but it’s close enough. Perhaps it can be
-made more like Surround if it grows every movement but then depending on the max
-size of the snake the game might be over fairly quickly (I don’t remember how
-it was done in Surround).
In Surround each move you made you would grow in size by one. This is what -inspired the shedding mode. Anyway I always loved the game and it’s similar to -Snake in several ways.
- -Yes. I thought it would be fun if there were other obstacles for the snake (in -my mind I was thinking of barriers like the walls but in the field).
- -I also thought it would be fun to have more than one bug at some point after say -the snake gets to be some size. One of the reasons I didn’t do this is because I -was trying to save iocccsize bytes. I never got round to this though and I feel -that the features I have implemented are far more interesting and fun.
- -Another idea is having portals or teleportation but there are a number of -problems with those that would have to be worked out too.
- -I would have loved for it to be practical to support diagonal movement but as I -describe elsewhere it’s not. That’s perhaps what I regret most. It would be -possible to choose letters instead of arrow keys but even if that fit in the -size restrictions how would I show the head? I looked at the extended ncurses -character set and I didn’t see any diagonal arrows. I suppose I could have it -not show the arrows but then that brings an old problem back.
- -Nevertheless I am quite happy with the features in the game and I hope everyone -who plays it enjoys it as much as I enjoyed writing/playing it.
- -I can think of at the least the following:
- -MAXSIZE=-1 should do it).And if you’re a show-off you can try:
- -But if that’s not enough I don’t know what to tell you other than suggest that -you make use of your talents for financial gain or at least a world record. -Either way I tip my proverbial snakeskin hat to you (animal cruelty but a pun is -a pun and every pun deserves to be shed).
- -They grow through a process called moulting - shedding their skin (other -creatures also moult). This takes place over some days and unlike humans snakes -never stop growing (though growth slows down as they mature). I chose the -variables SHED and SHEDS for simplicity and because the words are -shorter. I don’t like the words because it’s rather a misnomer but what I had -chosen before was longer - STRETCH and STRETCHES.
- -For the fascinating science behind snake slithering see Snake walk: The physics -of slithering. For the bizarre thought of snake human hybrids see human -snakes. The latter is hard to comprehend and there are some sad tails (tales) -in there too because I believe that people actually believe in this (how/why I -do not know) and they really do tell the truth as they see it (even if -impossible).
- -When Ilya Kurdyukov was playing with this he questioned why this is possible -when other implementations don’t have it this way. There are a few reasons.
- -First is that the friend’s implementation had it that way and it had been a long -time since I had played it (if I ever did? I don’t know now: I played so many -games over the years and the game most alike it that I played is Surround, as -below).
- -It also is the way it is in Surround.
- -It makes cannibalism mode very interesting.
- -And I happen to like it the way I have it. In the end a snake isn’t an obstacle -for itself but in the game it is and I went all the way instead of only halfway.
- -It also would take more bytes and that’s a problem with IOCCC rule 2b.
- -But if you have a problem with it you can always enable cannibalism and keep -walls passable and not worry about dying.
- -Why yes I do! So good in fact that even my late stepmum who didn’t even like -chocolate (except white chocolate) loved this cake. It’s a double-layered -chocolate fudge cake. See the file chocolate-cake.html for the recipe. -Note that it’s a complicated but it’s well worth it!
- -I included it in all my entries this year because if any of them won more people -can have this recipe; also it might help remind the judges that they really -should have their cook bake it so they can all - including the cook should they -also like chocolate - enjoy the cake whilst judging (and otherwise - it’s a big -cake and very rich). Sadly they didn’t get to enjoy it during their judging due -to the pandemic but maybe next time (or they can do on their own).
- -Do make sure to pay attention to all notes!
- -Please be advised that the note there that talks about the icing being difficult -in too warm room is rather significant; unfortunately with SARS-CoV-2 this might -be more of a problem depending on how long it lasts and where you reside. If -necessary use the refrigerator or else air conditioner to cool down the place.
- -I submitted three Snake versions; these are the other layouts for those few -(or more likely none) who are interested to see them.
- -The prog.2.c has more digraphs but I think no other significant differences.
- -The prog.3.c is in a more artistic layout (a backwards S), has at least one -additional obfuscation technique (see spoilers) but it also has more digraphs -and as the judges said they feel that digraphs are dated so that’s probably why -they chose the first layout. The prog.3-j.c version is prog.3.c with a shorter J -define.
- -The prog.alt.c version is the one that allows for customising the bug colour and
-it’s used in both snake-colours.sh and play.sh. It also calls erase()
-first, clearing the screen, which the play.sh and snake-colours.sh scripts also
-both do.
Once again I’m honoured to win along with some of the other veterans who I have -a huge amount of respect for; there’s Don Yang, Dave Burton, Yusuke Endoh and -Edward Giles all of whom are amazing programmers. I’m especially proud to win -besides Dave Burton and Yusuke Endoh but Don Yang and Edward Giles too.
- -But there are some others who I don’t remember like Ilya Kurdyukov (who’s -offered a lot of interesting thoughts on Snake and who plans to have his own -version after the entries are published), Nathan Otterness, Nicholas Carlini -(whose entry is an absolutely brilliant abuse of printf - and I totally agree -with the judges comments that your entry is so novel that it’ll be worth special -mention in the future Best of IOCCC list!) and tsoj too.
- -Well done and congratulations to all of you again! Thank you for submitting the -wonderful entries and I’m honoured to have my two entries beside yours!
- -To Dave Burton I thank you for your wonderful comments as well as pointing out -that even with prog.orig.c it probably would be better to make use of the alt -target instead of naming prog.c prog.orig.c. You’re quite right, I had thought -of it but you brought it up so I could correct it. Much appreciated mate.
- -I would like to dedicate this entry to my wonderful mum Dianne Ferguson whom I -love with all my heart and soul <3 Thank you for being the best mother -imaginable! You’ve been there for me in the darkest of my hours without question -without complaint and with all the love, compassion, empathy, sympathy and -devotion anyone could ever ask for. Bless you again and again and again dear -mother.
- -I also want to dedicate this to Vicky Wilmore who has given me a lot of -love the past few years and who was there for me in some very dark times. Thank -you Vicky sweetheart from the bottom of my heart and soul. Although we have -parted ways, whether for now or for ever, you will always always always have a -place in my heart and soul xxx
- -I would like to thank my dear friend Martijn Schoemaker for encouraging me in my -programming over the years and who I owe a great deal to. Thank you for -believing in me and my programming abilities (and other abilities) even when I -couldn’t believe in myself! Very much appreciated especially coming from an -amazing programmer who I have huge admiration for!
- -I want to thank Ilya Kurdyukov for his helpful comments, suggestions and -reporting the problem about half-width/full-width char spacing. He’s been -playing with some versions of his own and will have them on GitHub after the -2020 IOCCC winning entries have been published.
- -Finally I want to thank Leo Broukhis, Simon Cooper and Landon Curt Noll for -continuing to hold the contest after all these years - and for having selected -my entries. It’s a huge honour; thank you! I also happen to love your -comments as well as the award titles. And yes indeed ‘most of us could use -Double-layered Chocolate Fudge Cake!’
-![]() |
-© Copyright 1984-2020,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
- The International Obfuscated C Code Contest
-A 27th IOCCC Winner
-Cody Boone Ferguson ioccc@xexyl.net
-https://ioccc.xexyl.net
-Twitter: @xexyl
The code for this entry can be found in prog.c
- -make
-./prog
-
-
-# IOCCC obfuscated!
-echo IOCCC | ./prog
-
-# IOCCC obfuscated and de-obfuscated!
-echo IOCCC | ./prog | ./prog
-
-# more input fun
-./prog - < try.this.txt 2>/dev/null
-
-# more obfuscated fun
-echo testing test tests | ./recode
-echo testing test tests | ./recode | ./prog - 2>/dev/null
-echo testing test tests | ./recode | ./prog - 2>/dev/null | ./recode
-echo testing test tests | ./recode | ./prog - 2>/dev/null | ./recode | ./prog - 2>/dev/null
-
-
-This code is an enigma. Try to decode it!
- -There is a good deal of useful documentation that is provided with this entry:
- -A useful man page for this entry. To render, try:
- -man ./enigma.1
-
-
-Some useful information about recode.c
- - - - -Because most of us could use some Double-layered Chocolate Fudge Cake!
- -My remarks about my Heer ‘Army’ and Luftwaffe ‘Air Force’ Enigma simulator for -the 27th IOCCC.
- -I want to dedicate this entry in part to the millions of poor souls that were -lost during the tragedy that is the Second World War. There are so many people -who are unknown, unloved, unclaimed and even unidentified. And who knows what -they might have gone on to do if their lives weren’t - like it is with all other -wars - needlessly taken from them? When one considers it was all because the -most powerful man in the world at the time felt he should rule all others it -makes it somehow even more tragic: there wasn’t even a good reason for the war -(is there ever?).
- -If one were to write the name of every person who died in the conflict in a -book, it would take so many pages that the book would be so heavy, so long, so -expensive to print, and it wouldn’t bring anyone back to life nor would it -erase the suffering. Nothing will. It’s horrible.
- -There really are no words that can truly describe the tragedy but I wish to with -my Enigma simulator honour each and every soul who was lost, or suffered, or -suffered the loss of friends or loved ones, as well as the world itself, in and -from one of the greatest tragedies in the history of mankind.
- -I will have more information on this entry at -https://ioccc.xexyl.net/2020/enigma after the winning entries have been -published.
- - - -Bugs, limitations, differences from the real Enigma machines and general notes
Is there a better single word that could describe the code that is IOCCC? I’m -sure there are some other words that are equally as valid but I believe ‘Enigma’ -is a great word nonetheless.
- -However it’s curious that no winning entry has ever been a simulator of the -German Enigma machine. I’m actually quite surprised at that because it’s such a -brilliant piece of engineering of the time even though it had a critical flaw: -that no letter could be itself; this combined with cribs (known or suspected -plaintext) - which was down to carelessness, capturing an Enigma and sometimes -settings sheet, as well as known messages the Germans started out with - allowed -for cracking the code.
- -Combining this entry with two of the Morse code entries is particularly -interesting because that’s what the Germans did: the party sending the message -would first set up the machine, write down the letters and then transmit by -Morse code the encoded message. Then those picking up on the message would note -the Morse code, translate it to the alphabet and then input it into their Enigma -machine configured in the same way and thus have the original message.
- -The 1998 ASCII / Morse code translator entry (author Dorssel) prints the -Morse code of text; and the 2014 Morse audio transcoder (author Vik) can be -used to allow for the actual sound of it. With my entry we can complete the -loop!
- -The author (Nathan) of the 1992 Worst Abuse of the Rules had this to say:
- -This program is a hello world text encrypter/decrypter. It uses an
-enigma (I think) style encryption algorithm, where the encryption
-key character is modified by a value, determined from the previous
-character. Non-printable characters (those with ASCII values < ' '
-or > 0x7e) are passed unaltered, thus any kind of file may be
-successfully processed, but if the original is printable, the
-processed file will be too. The input is read from stdin, and the
-output presented to stdout. The key, a text string, is presented as
-a command argument. This is optional, and if omitted, the file is
-self-{de,en}crypted. To specify decryption, a "-" should be given
-before the key. (Actually encryption and decryption proper inverse
-operations, so you can use decrypt to scramble and encrypt to
-descramble, if you're perverse.)
-
-
-But the Enigma algorithm is more complex than that and my entry can encipher and -decipher text in the manner of the Enigma machines of the Army (Heer) and Air -Force (Luftwaffe); the Kriegsmarine ‘Navy’ was more complex (see section Adding -Kriegsmarine support for more information on that.
- -My entry should also work as a non-military grade Enigma as it by default has an -empty plugboard (they had none). I explain how to set up the simulator later.
- -Yusuke Endoh asked the judges and me if the real 1992 entry source was -available. Simon Cooper didn’t have access to it because it was before his time in -the IOCCC; but before the other judges could answer Ilya Kurdyukov sent a link to -the original 1992 code. However because I do not know the current status of the -regulation (though it seems unlikely that it still applies) I am only citing an -old version of the IOCCC website:
- - nathan - obfuscation by (trivial) encryption (source not exported)
-
- Brian Westley decided to just ``screw the (US) government'' and make the real nathan.c source available. We also note that Nathan Sidwell who lives outside the US made his own source available as well.
-
-
-Anyone who wants to find it I am sure can but I leave that to them.
- -If you run the program by itself it’ll use the default settings and prompt you -for input (end with EOF). At that point it’ll process the input string and print -the result (after finishing the enciphering).
- -If you run it like:
- - ./prog -
-
-
-It will prompt you for the settings of the machine (example below).
- -The first group is in the order of rotor (number), ring setting (letter) and -ring (starting) position (letter). It will do this for the first, second and -then third for each.
- -Then it will prompt you for the reflector (number). The first one is reflector B -and the second is reflector C.
- -Finally it’ll prompt you for the plugboard pairs.
- -After that you can input the string and it’ll go from there.
- -BTW: There’s a much more entertaining (and delicious) challenge or exercise in -recode.markdown (involves chocolate-cake.html). These however show -the general program as well as how to use the two winning entries of the Morse -code that I referred to earlier.
- - $ ./prog -
- Ring 1: 3
- Setting 1: I
- Position 1: O
- Ring 2: 1
- Setting 2: C
- Position 2: C
- Ring 3: 5
- Setting 3: C
- Position 3: Z
- Reflector: 2
- Plugboard pair 1: CO
- Plugboard pair 2: DE
- Plugboard pair 3: SN
- Plugboard pair 4: XY
- Plugboard pair 5: MS
- Plugboard pair 6: AT
- Plugboard pair 7: VF
- Plugboard pair 8: UR
- Plugboard pair 9: KL
- Plugboard pair 10: BJ
- IOCCC
- ^D
- CFDRG
-
-
-Notice that all output except the deciphered/enciphered text is sent to stdout.
- -If I didn’t specify the - by e.g. echo IOCCC | ./prog then it will use the
-default settings; as the judges suggest this invocation I will not show it here.
You can also type it out like this though:
- - $ ./prog
- IOCCC
- UUMMX
-
-
-The IOCCC comes from stdin; the UUMMX is stdout.
- -If I compile the 2014 entry and copy it to my local directory as
-vik I might do:
$ echo TEST|./prog |./vik | mplayer -demuxer rawaudio -
-
-
-And you would hear Morse code of the Enigma output of ‘TEST’ (i.e. KCWV). Or -perhaps not in this case. I’m not sure: I discovered a bug in that entry -(Fedora, CentOS and macOS all affected).
- -For example I can use the syntax provided in the winning remarks along with my -entry to write it to a file. Say:
- - $ echo TEST|./prog |./vik > test.raw
- $ ./vik e < test.raw | ./prog
- LEST
-
-
-Why did that happen? This shows more details:
- - $ ./vik e < test.raw
- SCWV
-
-
-However as can be seen the first char is wrong:
- - $ echo TEST|./prog
- KCWV
-
-
-And piping the original output to my entry itself you get the original input:
- - $ echo TEST | ./prog | ./prog
- TEST
-
-
-I’m not sure what causes that or if there’s a way to fix it but that’s the -idea anyway. Neither do I know if the original transcoding is correct.
- -What if I use the input string ‘LEST’ instead? In that case it worked fine:
- - $ echo LEST | ./prog | ./vik > lest.raw
- $ ./vik e < lest.raw | ./prog
- LEST
-
-
-But there’s one obvious question, right? Let’s try the most important one:
- - $ echo IOCCC | ./prog | ./vik > ioccc.raw
- $ ./vik e < ioccc.raw
- UUMMX
- $ ./vik e < ioccc.raw | ./prog
- IOCCC
-
-
-Phew! The program redeemed itself after the test failure! :)
- -(Technically above it didn’t print a newline after the output and this is how it -is with some of the things I pasted in the other file and maybe others here -too. Notice also how it showed the same output that my program gave it - UUMMX.)
- -What about the other Morse code entry?
- - $ echo IOCCC | ./prog | ./dorssel
- ..- ..- -- -- -..-
-
-
-I have included a supplementary program ‘recode’ (recode.c) that can -do a number of things which acts as a kind of wrapper and configurator to my -entry. By default it prompts you for the settings (rotors/rings, ring settings, -positions, reflector and plugboard pairs), validating input as you go.
- -After that it prompts for text that you can pass to the Enigma simulator; -alternatively you can specify a file to read in.
- -It has a randomise mode and it can save/read the settings to/from a file to -allow for duplicity (an archaic term for the state of being double but obviously -for Enigma it has to also mean deceitful).
- -I recommend using this in a pipeline instead of the simulator itself if you want -to change the configuration of the simulator because it offers a much richer -experience (and because you can reuse the configuration without having to type -it out again every time).
- -It does take the effort to try and prevent invalid input (as above) though maybe -I didn’t think of everything. My entry was meant to be a simulator only as far -as the ciphering goes but I thought this would make it much more interesting: -make it more flexible by a wrapper program.
- -For examples using it (and a delicious challenge) see recode.markdown. See -also recode.1 and enigma.1 man pages.
- -The parser is in a sense rather rudimentary but allows for both interactive and -automatic (e.g. via the recode program) input. This does mean that something -like the following can happen:
- - $ ./prog -
- Ring 1: 1AB
- Setting 1: Position 1: Ring 2: 2CD
- Setting 2: Position 2: Ring 3: 3
- Setting 3: A
- Position 3: B
- Reflector: 1A
- Plugboard pair 1: BC
- Plugboard pair 2: ..
- Plugboard pair 3: ..
- Plugboard pair 4: DE
- Plugboard pair 5: FG
- Plugboard pair 6: HI
- Plugboard pair 7: JK
- Plugboard pair 8: LM
- Plugboard pair 9: NO
- Plugboard pair 10: PQ
- IOCCC
- WD
- SIRDK
-
-
-First of all: what is that WD? I didn’t type that but it appeared it seems due -to too much input that triggers this (it happens when I hit ctrl-d to end -input).
- -If everything is input correctly it would show nothing except the actual Enigma -output (maybe at times ^D - I have noticed this at least when I don’t fill in -all plugboard pairs - which might or might not be possible with the Enigma -machines that had plugboards, I really do not know). I don’t view this as a bug -because the parsing of input is meant to be simple and in fact you can expect -the same output from the same input even if there are errors in the input.
- -Anyway as you can see the first ‘1AB’ was the first ring, setting and position. -After this it wants Ring 2 and I did similar; for ring 3 I did it each variable -by itself. However for the reflector I did 1A and it only expects 1 char! So will -that mean that the plugboard pairs are off? Yes it does seem to be so. This is -buffering at play I believe but it’s useful for allowing the recode program to -easily configure the Enigma machine. In the other markdown file I give a hint -as to how this could be fixed but the caveat is it would necessitate a need for -rewriting recode.c.
- -There’s another thing to be aware of and that’s the way the ranges are enforced. -There are five rotors which obviously are in C 0-4 but in ‘natural language’ -1-5 (they were labelled I, II, III, IV and V though).
- -There are two reflectors and the same applies: in C 0-1 but in human it’s -1-2 (technically these were reflectors B and C in the Enigma machine which I -display by name in recode.c just like with the rotors).
- -For more information see recode.markdown or recode.html.
- -BTW: If you need a reminder to go to the gym just do your Enigma ABCs and it -should help you remember (though not at this time in our world it might help you -later on?). This might become even more useful after the challenge is accepted, -accomplished and made use of! :)
- - $ echo ABC | ./prog
- GYM
- $ echo ABC | ./prog | ./prog
- ABC
-
-
-The layout of recode.c isn’t too significant (but see below) but I want to -mention prog.c especially:
- -I did think of a more artistic layout but reflecting on it I think that the -blankness of it can be another way of honouring all the many people who died -in - like all other wars - what was a useless conflict because - again like all -other wars - a powerful human being decided that they should rule others.
- -The blankness is a reflection of the millions of people who died unknown, uncared -for, unloved, without ever being acknowledged in their far too short lives, some -even unidentified; it’s the presence of absence.
- -I find it somehow fitting that the day I have finished this is 30 April 2020, -which was exactly 75 years from the day that the person responsible for the -Second World War, Adolf Hitler, ended his life. (I have since then made a bug -fix but I consider this inconsequential).
- -As for recode.c though I really love this:
- - /\
- / This is *not* what you think:
-
-
-…because it seems so wrong in C code at first glance.
- -It’s an Enigma simulator! Isn’t that proof that it’s obfuscated itself?! :) -Silliness aside obfuscation.txt has some of the ways I think this entry is -obfuscated. To decipher try:
- - ./recode -Robfuscation.key -fobfuscation.txt | ./prog - 2>/dev/null > obfuscation.markdown
-
-
-To encipher:
- - ./recode -Robfuscation.key -fobfuscation.markdown | ./prog - 2>/dev/null > obfuscation.txt
-
-
-The file obfuscation.key is the key to decipher/encipher -obfuscation.txt.
- -For the lazy obfuscation.markdown has the deciphered version. I am afraid -I’m not so inclined to do that for the cake recipe: the idea there is to make it -a fun exercise that when solved unlocks a wonderful double-layered chocolate -fudge cake recipe. But given that my ‘Don’t tread on me award’ entry also -has the recipe, not enciphered, one might just go there instead. Still it’s a -fun way to explore this entry.
- -As for the obfuscation.key file if you observe the contents you’ll find the -word OBFUSCATION:
- - 2OB5FU1SC2ATIONCDEFGHJKLMPQRYZ
- OB FU SC ATION
-
-
-Ways that my simulator differs from the real thing. Not all of these are bugs -and some could be considered features; others are just differences.
- -Does not check for using the same rotor more than once. The real Enigma
-machines this would not work because they had to choose from a set of rotors and
-there were no duplicates. This shouldn’t be a problem here however except that
-it won’t be a possible configuration of the real Enigma machine. The recode
-program however does validate this (except when reading in settings via the
--R option which I explain in the recode.markdown / recode.html file).
The way the plugboard - for the machines that had them - is if you connect A -to B then no other letters can connect to A or B. Earlier there wasn’t proper -detection and this caused invalid output.
- -Why only 10 pairs when the German alphabet has 26 letters? It’s - theoretically possible to have 13 but the Enigma typically had 10 pairs. - It’s easy enough to update my entry to do this once you de-obfuscate it but - I’m not helping there (and in fact I don’t think I could any more even if I - wanted to - at least not easily!).
It does not obviously have the clicking sound associated with the moving -parts of the real machine. I think it would be annoying to have this as it -processes each letter. However with the Morse code audio transcoder entry you -can at least have the output played in Morse code as the Germans did; I think -that is really cool (I think it’s really cool even if there’s a bug in it)! That -it pays homage to that (and another) entry is a bonus here.
The simulator doesn’t report errors but tries to gracefully deal with them: -if one chooses a value out of range it moves it into the range (if > the max -then the max, if < min then the min). If invalid chars are input for the -plugboard pairs then it’s not added to the plugboard etc.
The real Enigma machines had only letters: no digits, no punctuation. My
-entry prints !isalpha() chars untouched. The Germans had different systems for
-punctuations, numbers etc. (one of the documents I link to has these details).
My entry preserves case of letters. The real Enigma had only one case as it -was just a keyboard and they didn’t need case-sensitivity.
Later models introduced a fourth rotor. The Kriegsmarine procedures were -also far more complex than the Heer and Luftwaffe. I find this particularly -interesting because it was Hermann Goering who was the Supreme Commander of the -Luftwaffe and the intelligence agency Forschungsamt (FA) was his; it provided -Hitler with invaluable information so one would think the Luftwaffe system would -be more complex! See adding Kriegsmarine support for more -information.
I only include reflectors B and C. To have included more would have used too
-many bytes (each reflector and rotor is 26 characters!) and I could not include
-them for this reason; I include 5 rotors and 2 reflectors and that’s a total of
-(5 * 26 + 2 * 26 == 182 chars) but there are as you can see many other strings
-too. It is however feasible to update the rotor and reflector options and you
-could even make your own versions if you wanted to. Doing this is an exercise to
-the reader however (the idea of trying this makes me cringe because of how I
-obfuscated things)!
There’s one thing I’m unsure of in my implementation. Because of all the -possible settings I used some other simulators as a starting point and more -importantly to validate that my code worked right. These other simulators had -bugs though and so one thing looked odd and I don’t know if it is right or not. -An online simulator appears correct but I don’t see the option to change that -part.
- -If you notice in the Q() function where I set up specific pointers and other -data there is a call to the macro ‘q’ but I only refer to the first ring setting -(of which I no longer even know which element it is! Or was it position? I don’t -even know that now for certain). That’s because the Python code did that (though -very differently of course) but I also had to bug-fix the Python in another -part.
- -I do not know if this is correct but as I show somewhere my entry does match the -online simulator so I presume it is correct. It might be that the Germans tended -to have it at A but again I do not know.
- -I said that one could add the additional rotors used by the Kriegsmarine but -looking at this again it appears that it’s not as simple as adding the rotors to -the code and updating the references to the array etc.
- -This is because rotors VI, VII and VII had two notches and this changes the way -things work. The Kriegsmarine M4 also had an additional change which would -complicate matters more.
- -I looked into trying to do this for another version after winning but some of -the obfuscation techniques dramatically complicates even attempting this so I -haven’t even tried.
- -It is feasible that you could add your own rotors however but I leave this as an -exercise to the reader. I will say that the five rotors I, II, III, IV and V can -be found in the source code verbatim and you could confirm it by looking them -up; however much more would have to be done in order to get them to work, than -to just put the strings in. Again the way I set things up complicates this -greatly.
- -I have tested it under macOS, Fedora and CentOS Linux and all seems okay under -these platforms. When I was in the final stages of obfuscation I made an error -somehow (or else maybe the vim formatting caused a problem - I have seen this -before) and I had to go back and undo some of the obfuscation to figure out what -was going on (I had a hunch where and I noted it in the obfuscation I believe) -but this made me wonder on if I made any other mistakes since it appeared to be -working before that.
- -I don’t know if EBCDIC will work but I think it might because it appears that -the alphabet is a contiguous sequence. I don’t believe endianness matters but I -no longer remember what I’ve done in full and I’ve no way to test it.
- -If there are any inconsistencies in input/output one also has to be certain that -input was put in correctly because as soon as a letter differs the entire -sequence will be off.
- -The results of my test script (not included here but I will probably have it on -my website) are the same under Fedora, CentOS and macOS.
- -The Wehrmacht was the defence force in full which included the Heer (army), -Luftwaffe (air force) and Kriegsmarine (navy). As I said the Kriegsmarine -procedures were more complex: they had additional rotors and one of their models -had a different reflector system (thin instead of thick - some of the documents -below discuss this). The military intelligence agency, the Abwehr, had their own -system too. Non-military grade Enigma machines didn’t have the plugboard. And -so on.
- -However one of the documents below distinguishes the Kriegsmarine from the -Wehrmacht; when you see this you can read it as the Kriegsmarine versus the rest -of the Wehrmacht rather than the Wehrmacht and the Kriegsmarine.
- -Enigma Message Procedures: The Heer, Luftwaffe and Kriegsmarine Enigma -procedures.
- -Interactive Enigma Machine: Shows wiring of the Enigma machine based on the -settings and input (unfortunately uses Flash). This was what I used to verify -output (as best I could find). To set this up to use the default settings in my -simulator make sure to use Rotors I, II and III and the starting positions at B, -B and C respectively (as in left, centre, right). To do this click the button at -the top right that looks like:
- -o->
-<-o
-
-
-And then select the rotors. Next click the button again at the left of the -rotor selection ‘screen’. Then use the arrow buttons above each rotor to set -from left to right B, B and C. After this you can type your message in the input -field and watch the wiring of the rotors change and show the path it takes.
- -If I made use of the Enigma code in the recode.c program I would maybe consider -doing something like that but I intentionally do not use it there: as cool as it -might be it would give a better idea of how the algorithm works (unless I were -to make it just as obscure as I do in prog.c but that’s also a bit risky). I -don’t believe I could do it now anyway.
- -I’m uncertain how to change the rotor settings itself in this simulator to -determine if the ring settings being different from ABC would cause a problem -(this is the thing I mention I’m uncertain about in the bugs section).
- -Going back to the configuring the online simulator try inputting the text IOCCC -and you’ll see the resulting text being:
- -UUMMX
-
-
-Which is exactly as my entry shows! So at least for the starting position BBC -and an empty plugboard and the other defaults in my entry (which appear to be -consistent with the online simulator too) I can verify it works.
- -Tony Sale’s pages on The Enigma cipher machine: This is many pages on the -Enigma machine by the late Tony Sale who was the original curator of the -Bletchley Park Museum. There is a wealth of information in these pages on how -the Enigma worked and this includes some challenges to do to see how well you -understand the algorithm.
- -Fun fact: the abbreviation for the Signals Intelligence is that of our -wonderful SIGINT.
- -Technical Details of the Enigma Machine: ‘This page provides the technical -details of the Wehrmacht and Luftwaffe Enigma, and the Kriegsmarine Enigma M4.’ -It is quite a nice document with diagrams, pictures of actual Enigma rotors and -other parts and more.
- -The German Enigma Cipher Machine: The history of Enigma, its development, -use during the war and cryptanalysis.
- -How the Enigma was Set Up and Operated: This is the third page in a document -series on the Enigma that explains the initial set up of the Enigma machine for -each day. This is a good introduction to the set up. There is one thing that I -was not aware of (or if I was it did not register): the operator would after -setting the positions also put in three letters before the actual message (there -were several parts to each message but this was another layer of complexity). I -did not implement this in the recode program but what would it be anyway? If the -user here wants to they could add three letters to their message beginning. I -don’t think there need be any addition to the recode program - at least not -that.
- -Once again I’m honoured to win along with some of the other veterans who I have -a huge amount of respect for; there’s Don Yang, Dave Burton, Yusuke Endoh and -Edward Giles all of whom are amazing programmers. I’m especially proud to win -besides Dave Burton and Yusuke Endoh but Don Yang and Edward Giles too.
- -But there are some others who I don’t remember like Ilya Kurdyukov (who’s -offered a lot of interesting thoughts on Snake and who plans to have his own -version after the entries are published), Nathan Otterness, Nicholas Carlini -(whose entry is an absolutely brilliant abuse of printf - and I totally agree -with the judges comments that your entry is so novel that it’ll be worth special -mention in the future Best of IOCCC list!) and tsoj too.
- -Well done and congratulations to all of you again! Thank you for submitting the -wonderful entries and I’m honoured to have my two entries beside yours!
- -To Yusuke Endoh, Dave Burton and Nicholas Carlini I very much appreciate your -wonderful comments on this program. Your comments Yusuke on this entry specially -and also Dave’s comments on my double-win are both extremely special to me - it -truly takes my pride to another level!
- -I would like to dedicate this entry to my wonderful mum Dianne Ferguson whom I -love with all my heart and soul <3 Thank you for being the best mother -imaginable! You’ve been there for me in the darkest of my hours without question -without complaint and with all the love, compassion, empathy, sympathy and -devotion anyone could ever ask for. Bless you again and again and again dear -mother.
- -I also want to dedicate this to Vicky Wilmore who has given me a lot of -love the past few years and who was there for me in some very dark times. Thank -you Vicky sweetheart from the bottom of my heart and soul. Although we have -parted ways, whether for now or for ever, you will always always always have a -place in my heart and soul xxx
- -Once more besides those two I want to also dedicate this to all the many -millions of people whose lives were taken from them in what amounts to - like -all other wars - a horrible, pointless conflict and an utter waste of life, -something precious that is far too often taken for granted. As I noted before I -found it fitting that I finished this on 30 April 2020 - exactly 75 years after -Adolf Hitler, he who started the Second World War, ended his life. The blankness -of the layout is another way of honouring the poor souls who lost their lives, -many of whom we will never know even their name let alone what they might have -accomplished if it wasn’t for their tragic and pointless deaths. Always remember -that life is precious and never ever take it for granted! Believe in yourselves. -Everyone. Do not let anyone ruin that for you ever.
- -I would like to thank my dear friend Martijn Schoemaker for encouraging me in my -programming over the years and who I owe a great deal to. Thank you for -believing in me and my programming abilities (and other abilities) even when I -couldn’t believe in myself! Very much appreciated especially coming from an -amazing programmer who I have huge admiration for!
- -Finally I want to thank Leo Broukhis, Simon Cooper and Landon Curt Noll for -continuing to hold the contest after all these years - and for having selected -my entries. It’s a huge honour; thank you! I also happen to love your comments -as well as the award titles. And yes indeed ‘most of us could use -Double-layered Chocolate Fudge Cake!’
-![]() |
-© Copyright 1984-2020,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
- The International Obfuscated C Code Contest
-A 27th IOCCC Winner
-Edward Giles
-https://id523a.com/
The code for this entry can be found in prog.c
- -make
-./prog
-
-
-./prog < pi.wav
-
-# [https://en.wikipedia.org/wiki/867-5309/Jenny]
-./prog 867-5309 > jenny.wav
-
-# Use an audio player to play jenny.wav
-
-
-A cross platform utility for both encoding and decoding tones.
- -This program encodes and decodes dual-tone multiple frequency signals used in telephone systems, more commonly known as Touch-Tones.
- -If the program is executed with no arguments, it will read a WAV file from standard input, decode the touch-tones in the file, and output the corresponding digits to standard output. This program only supports WAV files that have exactly 16 bits per sample, but it allows any sample rate and any number of audio channels.
- -$ ./prog < pi.wav
-31415926
-
-
-If the program is executed with a command-line argument, it will generate the tones corresponding to the specified characters, writing them to standard output as a WAV file.
- -$ ./prog 867-5309 | aplay
-
-
-gcc -pedantic -Wall -Wextra there are no compiler warnings.libm.memcpy so there are no strict-aliasing violations.CHAR_BIT == 8int16_t, uint16_t, and uint32_t existint16_t is 2’s-complementdouble is an IEEE 754 binary64 floating-point typesizeof(double) == 8aa is both a variable and a macro for error handling,
-and memcpy is both a library function and a goto-label.f macro is used to unroll some of the loops.l. This array is usually accessed at index z plus a constant. Accesses of this type have been rewritten from, e.g. l[z+17] to 17[l+z]. [l+z] ends up occurring quite often, so I created the macro a as a shorthand.Each tone in a DTMF signal is a combination of two frequencies. The lower frequency determines which row the digit is in, and the higher frequency determines the column. There are 4 possible row frequencies and 4 possible column frequencies.
- -| - | 1209 Hz | -1336 Hz | -1477 Hz | -1633 Hz | -
|---|---|---|---|---|
| 697 Hz | -1 | -2 abc | -3 def | -A | -
| 770 Hz | -4 ghi | -5 jkl | -6 mno | -B | -
| 852 Hz | -7 pqrs | -8 tuv | -9 wxyz | -C | -
| 941 Hz | -* | -0 | -# | -D | -
This program determines which frequencies are present in the input by passing it through a set of 8 virtual resonators, each tuned to one of the frequencies used for DTMF. These can be implemented using only basic arithmetic, and they are able to ‘select’ a specific frequency from the input sound, blocking all other frequencies from reaching the output. The loudness of the sound output from each resonator can therefore be used as a measure of how much of a particular frequency was present in the input. The program then decides, over the course of one tone, which row frequency and which column frequency were most prominent.
- -Tones are generated using those same resonators by providing an impulse as input. An impulse can be thought of as consisting of sine-waves at all frequencies, and when it is put through one of the resonators, the result is a single pure sine wave.
-![]() |
-© Copyright 1984-2020,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
- The International Obfuscated C Code Contest
-The 27th IOCCC
-Copyright © 2020, Landon Curt Noll, Simon Cooper, and Leonid A. -Broukhis. All Rights Reserved. Permission for personal, educational -or non-profit use is granted provided this copyright and notice are -included in its entirety and remains unaltered. All other uses -must receive prior permission from the contest judges.
- -Use make to compile entries. It is possible that on non-Un*x / non-Linux -systems the makefile needs to be changed. See the Makefile for details.
- -Look at the source and try to figure out what the programs do, and run -them with various inputs. If you want to, look at the hints files for -spoilers - this year we included most of the information included -by the submitter.
- -Read over the makefile for compile/build issues. Your system may require -certain changes (add or remove a library, add or remove a #define).
- -Some C compilers are not quite as good as they should be. If yours is -lacking, you may need to compile using clang or gcc instead of your local -compiler.
- -This year’s Best of Show (carlini) is such a novel way of obfuscation that it would be -worth of a special mention in the (future) Best of IOCCC list!
- -For some reason, this year’s set of winners contains three nostalgic games, -Asteroids (tsoj), Minesweeper (endoh1), and Snake (ferguson1).
- -An entry (kurdyukov1) pays homage to a previous winner (2015/hou).
- -…We’ll stop spouting spoilers now. Have fun exploring all the entries!
- -As a rule, we try to compile the entries on a variety of platforms. -Quite a few entries this year could not be built or executed on some of them due to reliance on -library internals or the system runtime.
- -A few entries were violating the “2053 significant bytes” rule. If an entry could not be brought to -compliance within a few seconds of looking at the source, it was disqualified.
- -One entry tried to get around the size limit by putting the code into -makefile variables and using -D. This is already called out as discouraged -technique in the guidelines, but it is worth a reminder.
- -Several promising entries attempted to make use of the syscall function using literal syscall numbers.
-This is utterly non-portable.
A note to the authors: when submitting multiple entries, don’t let us easily correlate them by -coding style or documentation content, and definitely don’t submit nearly identical versions -of your program separately. As we try to judge the entries anonymously, the similarities will cause such -entries to compete against one another, making each less likely to win.
- -We hope the authors of non-winning entries will refine their entries and -perhaps re-submit them for the next IOCCC.
- -One more thing that feels dated is digraphs and trigraphs.
- -Please feel free to send us comments and suggestions about the -competition, this README or anything else that you would like to see in -future contests.
- -If you use, distribute or publish these entries in some way, please drop -us a line. We enjoy seeing who, where and how the contest is used.
- -If you have problems with any of the entries, AND YOU HAVE A FIX, please -send us the fix (patch file or the entire changed file).
- -![]() |
-© Copyright 1984-2020,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
- The International Obfuscated C Code Contest
-A 27th IOCCC Winner
-Ilya Kurdyukov
-https://github.com/ilyakurdyukov
-Twitter: @ilyakurdyukov
The code for this entry can be found in prog.c
- -make
-./prog
-
-
-# Obfuscated IOCCC
-echo IOCCC | ./prog
-
-./prog < prog.x86.asm
-
-./prog < prog.x86_64.asm
-
-
-This hash of a C code makes a hash out of input. -Do you understand how? -You should get a-round-to-it figuring it out!
- -Just a tiny MD5 checksum utility. Prints hash string of data from stdin.
-Work same as (openssl md5 | cut -d' ' -f2) command.
-Wall -Wextra -pedanticThe main difficulty of making MD5 code smaller is a 64x4 bytes long table with constants. Which will take more than 512 bytes in text hex encoding. This table is a results of a sine function, so can be generated dynamically, but merging floating-point arithmetics with precise integer calculations is not a great idea, because can make portability issues.
- -Attempts to satisfy CLANG -Weverything will ruin comma magic, that is so great for obfuscation, so I don’t want to care about that.
Probably, should work correctly on any machines, but I have nothing exotic (like BE or not 32/64) to try it.
- -Added a macro hack to make stdin work in binary mode under Windows (tested under mingw64), otherwise the hashes can be incorrect.
- -prog.extra.c the same with the sine function (so smaller), and in different shapes.
prog.x86_64.asm contains same program, but written on assembly for x86_64 Linux, for the sake of less executable size. Which is 500 bytes long (where 120 is for ELF headers) after compilation. Algorithm details is slightly differ (like constants packing), just to make smaller binary code. It’s interesting to compare density of binary code and obfuscated C.
prog.x86.asm and for x86, although the headers are smaller, but the binary code is larger due to fewer registers and lack of 64-bit multiply.
![]() |
-© Copyright 1984-2020,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
- The International Obfuscated C Code Contest
-A 27th IOCCC Winner
-Ilya Kurdyukov
-https://github.com/ilyakurdyukov
-Twitter: @ilyakurdyukov
The code for this entry can be found in prog.c
- -make prog prog_png prog_ppm
-./prog Nrect infile outfile
-
-
-# Take a selfie
-./prog 1000 selfie.jpg output.jpg
-# Admire your portrait in cubist style
-
-(echo P6 1024 1024 255; dd if=/dev/urandom bs=3M count=1) > random.ppm
-# Look at random.ppm. Do you see any patterns?
-./prog_ppm 1000 random.ppm output.ppm
-# See which patterns the program has found
-
-for i in 0001 0002 0004 0008 0016 0032 0064 0128 0256 0512 1024 2048 4096 8192 ; do ./prog $i sample.jpg out$i.jpg; done
-# Then flip through the out*.jpg pictures and see when you start recognizing the image.
-
-
-This entry has reminded us of a winning entry back in the early 90s. Can you guess which one?
- -For a given image, try graphing the execution time relative to the number of rectangles. -What is the complexity? Is it obvious from the source code?
- -This program divides the image into a specified number of rectangles. This process is content aware, so algorithm tries to match most of the information. However, it doesn’t finds the best theoretically possible layout.
- -./prog 1000 input.jpg output.jpg
-
-
-You can build three versions, depending on the image format.
- -Default is JPEG version, if you have the libjpeg development package installed in your system, then make without arguments should do the thing.
If you want to use libjpeg compiled from sources, then use LIBS define to specify the path to includes and the library.
make prog LIBJPEG="-Ijpeg-6b jpeg-6b/libjpeg.a"
-
-
-Use this command to build a PNG version (you need libpng):
- -make prog_png LIBPNG="-lpng"
-
-
-And the PPM version (no additional dependencies, can read raw/ASCII PPM, writes raw PPM):
- -make prog_ppm
-
-
-First, make sure you have the compiler tools installed e.g. by:
- -$ sudo xcode-select --install
-
-
-Make sure you install MacPorts. Then do:
- -$ sudo port install jpeg libpng ImageMagick
-
-
-The program itself doesn’t need ImageMagick, install it only if you plan to make gifs from the results using “makegif.sh”.
- -After that’s installed you need to run make with these options:
- -$ make LIBS="-I/opt/local/include -L/opt/local/lib"
-
-
-Made this thing while experimenting with the idea of representing an image with rectangles (lossy compression). It’s not very good in that sense, but the results look funny, like a kind of cubism pixelart.
- -Do not use values above 50000, it gonna be slow.
- -To understand how this works, just try running with 1,2,3,4… number of rectangles. At each iteration, the rectangle with the biggest difference from the picture data is split (halves may have different size) horizontally or vertically to get the minimum difference.
- -You can use this command to make a gif from output images (uses ImageMagick):
-convert -delay 10 -dither none -loop 0 $(ls out*.png | sort -V) $(ls out*.png | sort -rV) +map out.gif
-Also provided makegif.sh to aid with gif creation.
![]() |
-© Copyright 1984-2020,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
- The International Obfuscated C Code Contest
-A 27th IOCCC Winner
-Ilya Kurdyukov
-https://github.com/ilyakurdyukov
-Twitter: @ilyakurdyukov
The code for this entry can be found in prog.c
- -make
-./prog
-
-
-# first input to try
-echo first input to try | ./prog
-
-# try reading this output
-echo International Obfuscated C Code Contest | ./prog
-
-# try reading this other output
-./prog < input.txt
-
-
-It is interesting how well smeonoe can raed txet wtih lots of tyops in it. -How well can you raed porg.c, C prgoarm that is in the shpae of an SD card (or -is it a pnuch crad)?
- -Compile and try this:
- -cat some.input.txt | ./prog
- -The program can work with letters that are not represented in English, as long as these letters are encoded in the higher part of the single-byte character set (use iconv to convert from UTF-8 and back).
![]() |
-© Copyright 1984-2020,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
- The International Obfuscated C Code Contest
-A 27th IOCCC Winner
-Ilya Kurdyukov
-https://github.com/ilyakurdyukov
-Twitter: @ilyakurdyukov
The code for this entry can be found in prog.c
- -make
-./prog text_file output_length context_length random_seed
-
-
-./prog Shakespeare.txt 2000 10 1
-./prog Shakespeare.txt 2000 9 1
-./prog Shakespeare.txt 2000 8 1
-# ... Why does it get progressively slower when the context length decreases?
-
-./prog Eugene_Onegin.txt 2000 10 1
-# For those not knowing Russian, just to see how the UTF-8 characters are handled
-
-
-(Performance depends on the number of same hashes found. -Too many identical strings if the context length is small. author)
- -We were able to write our own program performing the same trick
-using the (still non-standard, for some reason) library function memmem,
-but that way it works too fast regardless of the context length, and it’s much less fun.
(Wow, amazing! Very fast, but there is a drawback to randomness. -If some string only appears after half the input, the first instance -of this string will have a 50% chance of occurrence. -Example:
- -echo "00000000000000000000 01 02 02 02 02 02 02" > test.txt
-./prog test.txt 1000 2 123
-# more twos in output
-./rand test.txt 1000 2 123
-# more ones in output
-
-
-But this will happen very rarely on real data. author)
- -Try using the same random seed and varying the context size.
- -cc prog.c -o prog
-
-
-This program generates random text from the provided dictionary using a Markov chain, outputs to stdout.
./prog input.txt 2000 10 12345
-
-
-Parameters are:
- -dictionary filename
-Need at least the size of the book, the more the better (1Mb), you can concatenate several books into one file. This should be a text file (not .doc/.pdf). You can feed with books in .fb2 format, metadata is filtered. Whitespace characters is also filtered. For languages other than English, it’s better to use ANSI encoding. You can use UTF, but you need to increase chain length (if one ANSI character is encoded as two UTF bytes, then multiply chain length by two).
bytes to generate (limited at 1Mb)
chain length -Randomness and performance depend inversely on this parameter and the size of the dictionary. If you feel that bytes are generated too slowly, then you need to increase the length of the chain. This length means that any part of the output of this size in bytes exists somewhere in the dictionary.
random seed
You can try this with the inputs provided with 2019/mills from the IOCCC winners.
$ ./prog shakespeare.txt 2001 10 12345
-r sons, wives for them, as the hope I had it. This is the way they be not too ra
-sh a trial of you only. Therefore will not out of door? Nurse: Marry, bachelor,
-Have other some, he is in Rome: but where is Warwick frowns at his. PRINCE EDWAR
-D: Where is the light: But I will watch thy waking, what work he makes Amongst y
-ou? Come, sirs, We shall write to you, fortune and The hazard of much blood. I w
-ould to heaven, respective lenity, And fire-eyed fury be my convoy in the senten
-ced; 'tis too horrible, so bloody on the banks If they were created, Would bring
- them to our presence? FLORIZEL: And those his golden crown, What is six winters
-? they are but Lewis and Warwick bids you come too late come from the king's fri
-end, and will do't; for, look you, sir, For still thy true servitor: I will rend
- an oak And peg thee in his knotty entrails till Thou hast hazel eyes: what eye
-but such an eye would spy out such a day to-morrow, or next day: He is within th
-e limit of the like, forsworn to love, Send her a story of more woe Than this is
- a merry ballad, but a very pretty one. MOPSA: Thou hast amazed me, My name is E
-lbow: I do lean upon, Now thou art: Thy tears are womanish; thy wild acts denote
- The unreasonably: come, you must: and there, I then do't to them? VOLUMNIA: Now
- the red pestilence hangs in our aim, which is yours. What is't your honour, as
-in war, since then, You have said before: My child is dead; or 'twere not 'long
-of him; but he, like you, lads; about your ears it is Menenius? Second Officer:
-Come, come, young wanton and effeminate boy, Takes on the hungry beach Fillip th
-e stars Shall bitterly begin his wooing that we have in hand are angry And frown
-ing brow to brow, ourselves, Still your own affections are devised, As blanks, b
-enevolences, and I thank thee for it. KING HENRY VI: Master lieutenant comes. Ma
-ster lieutenant comes. Master lieutenant, pray you,-- CORIOLANUS: What's that to
- him? CHRISTOPHER: At Pembroke, Sir James Blunt, And Rice ap Thomas with a virtu
-
-![]() |
-© Copyright 1984-2020,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
- The International Obfuscated C Code Contest
-A 27th IOCCC Winner
-Nathan Otterness
-https://github.com/yalue
The code for this entry can be found in prog.c
- -make
-./prog < input.mid > output.mid
-
-
-wget -O cvikl.mid 'http://www.kunstderfuge.com/-/midi.asp?file=beethoven/symphony_6_1_(c)cvikl.mid'
-./prog < cvikl.mid > output.mid
-
-# Play output.mid with your favorite player
-wget -O entertainer.mid https://www.midiworld.com/download/3857
-./prog < entertainer.mid > output2.mid
-# Play output.mid with your favorite player
-
-
-In an entry that boasts not using literals, one would expect to see straightforward ways to produce
-small integers like !(x^x)<<!(x^x), etc. but this entry is trickier than that. Deciphering what it does,
-apart from reading stdin and writing to stdout, would take a while.
While doing that, you can be audially entertained by a sample of its output.
- -This program seeks to automatically “improve” standard MIDI files (.mid) by -adding an extra track that provides a driving drum beat to bring some -excitement into boring video-game music rips or classical music sequences that -otherwise only see the light of day when modern musicians import them into FL -Studio to copy a few chords.
- -If you’re not using Windows Media Player or already familiar with MIDI files,
-you may need to install some additional software to be able to listen to them.
-For example, on Ubuntu, I was able to play them in VLC after installing
-vlc-plugin-fluidsynth and fluid-soundfont-gm.
You can obtain MIDIs in many places, but I mostly tested the program using
-files I found here.
-However, as discussed under the Limitations heading below, not all of them
-work correctly. I will admit to having used
-http://www.kunstderfuge.com/-/midi.asp?file=beethoven/symphony_6_1_(c)cvikl.mid
-for most of my testing.
Compile the program using the following command (I tested this using both
-clang and gcc):
-
-$CC -pedantic -Wall -Werror -Wextra -O3 -o prog prog.c
-
The program expects a MIDI on stdin, and writes a modified MIDI to stdout:
-
-./prog <input.mid >output.mid
-
If the program encounters an error, no output will generally be produced, and -it will exit with a specific status code. Meanings of the various status codes -are listed below, under the “Program error codes” heading. On success, the -program exits with a code of 0.
- -The program does not support MIDI files over 4 MB (specifically, it will -not take input files larger than 222 - 1 bytes). This is unlikely to be a -big limitation in practice, since even lengthy MIDIs are rarely over a -couple hundred KB.
Not all MIDIs set (or correctly set) their timing information, which will -lead to the tempo of the drum beat not matching the track. This will be -especially true for “live performance” .mid files.
There may be some types of MIDI messages that the program is unable to -correctly parse, but I have rarely seen this in practice. The largest -cause of program failures, in my experience, has been Limitation 2.
I had one primary goal when writing this program: include no C literals -whatsoever. The final C file includes no numerical, string, or character -literals. Instead, all literals have been replaced with a handful of global -variables, which are occasionally modified throughout the file to prevent -simple uses of find-and-replace.
- -So, in a sense, this obfuscation is simply an intentional use of global
-variables' classic problem: absolute spaghetti code. The absence of any sort
-of literals has the added benefit of forcing any would-be reader to trace the
-contents of many variables starting from main, since, without literals, very
-little of the code gives any inherent visual cues as to its purpose.
I already took the liberty of running prog.c through clang-format, since it
-still fits in the size limit and the formatting of the code was never intended
-to be an obfuscation technique here.
MIDI files are generally divided up into one or more “tracks” that play -concurrently. While it is easy to find the positions of each of these tracks -in the file, figuring out the amount of time each track is supposed to play is -more difficult, and requires parsing every track in its entirety. This means -that generating a drum beat that covers the entire piece of music requires -parsing every track (the entire file) in order to determine the longest track.
- -Once the program has determined the longest track in the file, it generates a -new track, containing the simple 4-note percussion sequence, to match the -length (in beats) of the longest-running track. It appends the new track onto -the end of the file, taking care to update the file header, as well.
- -If the program encounters an error, it will exit with a nonzero code. The error -codes can be interpreted as follows:
- -1: Encountered an invalid MIDI variable-length integer in the input.2: Attempted to write an invalid MIDI variable-length integer to output.
-(This would be an internal error).3: Encountered an unsupported MIDI event in the input.4: Encountered a bad MIDI track header in the input.5: The input MIDI file uses SMPTE time division, which isn’t supported.6: Failed allocating a temporary buffer to hold a single copy of our “beat”
-messages.7: Failed allocating a buffer to hold the new track data.8: Failed allocating a buffer to hold the input file.9: The input file was too large.10: The input file’s MIDI header was incorrect (but this isn’t checked
-very thoroughly).![]() |
-© Copyright 1984-2020,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
- The International Obfuscated C Code Contest
-A 27th IOCCC Winner
-tsoj tsoj.tsoj@gmx.de
-https://gitlab.com/tsoj
The code for this entry can be found in prog.c
- -make
-./prog
-
-
-# Make your terminal as large as possible, possibly reduce your font size
-# then...
-./prog
-
-
-This game does not use curses, but you may end up cursing.
- -The code is made more difficult to read using an innovative, right justified, -reverse indentation style.
- -w, a, s, dspaceqp, then use any other key to resume
- /\
- //\\
- / \
-/______\
- /\/\
-
-cc -std=c99 -O3 prog.c -o prog
-./prog
-
The only way I found to make it work is to use MSYS2. When using the MSYS2 shell you can install gcc via pacman.
-
-cc -std=c99 -O3 prog.c -o prog
-./prog.exe
-
-Wno-missing-prototypes-Wno-shorten-64-to-32-Wno-sign-conversion-Wno-implicit-int-float-conversion-Wno-missing-field-initializers-Wno-implicit-float-conversion-Wno-vla-Wno-float-conversion-Wno-comma-Wno-shadow-Wno-format-Wno-empty-body-Wno-misleading-indentation-Wno-maybe-uninitialized!= or ==![]() |
-© Copyright 1984-2020,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |
- The International Obfuscated C Code Contest
-A 27th IOCCC Winner
-Don Yang
-http://uguu.org/
The code for this entry can be found in prog.c
- -make
-./prog
-
-
-echo "International Obfuscated C Code Contest 2020" | ./prog 23209 > code.c
-
-# compile without a PIN
-cc code.c -o decode
-# yes, you must compile with -DPIN=<number>
-
-# compile with the wrong pin
-cc -DPIN=555 code.c -o wrongcoded # wait for it ...
-./wrongcoded | hexdump -C
-# Use the wrong PIN: You're gonna have a bad time.
-
-# compile with a PIN
-cc -DPIN=23209 code.c -o decoded # wait for it ...
-./decoded
-# weeeeeeeeeeeeee! You are having a good time!
-
-
-You might think of this entry as code obfuscater with a code. -If you use the wrong code, you’re gonna have a bad time. -What is compiling this entry about? -Having a good .. time!
- -This winning entry also comes with a JavaScript timelapse -spoiler that shows how this entry was written.
- -echo "Hello world" | ./mile 12345 > encoded.c
-
-gcc -DPIN=12345 encoded.c -o ./decoded && ./decoded
-
-
-Mile is a C code generator. Run without arguments for the help message below:
- -usage: [PIN] < input.txt > output.c
-
-where [PIN] is an integer in the range of 1..65535
-
-
-When run with an encoding PIN (first command line argument), Mile will -read bytes from stdin and generate C code on stdout. Example:
- -echo "Hello, world!" | ./mile 56789 > encoded.c
-
-
-This generated code will reproduce the same input bytes on stdout when -executed, if it was compiled with the same encoding PIN.
- -gcc -DPIN=56789 encode.c -o decoded
-
-
-The generated code reconstructs all data at compile time by seeding a -random number generator with the given PIN to reproduce the input bytes, -and simply does one fwrite() call at run time to print those bytes. Not -specifying a PIN is a compile time error. Specify the wrong PIN and -output code will still compile, but will likely produce garbage instead of -the input bytes. If the original input was empty then any PIN works, but -you might get a compile time warning complaining about empty arrays.
- -Because all data is reconstructed at compile time, expect the compile time -to be excruciatingly long if you try to encode too much data. Code -generated by encoding a haiku will probably compile in seconds, a limerick -may require tens of seconds, a sonnet will take minutes. Give Mile an -epic poem and you can probably write a faster preprocessor before GCC is -done (Clang probably already failed long before then).
- -I see that there is a lack of preprocessor abuse in recent years, probably -because programming in preprocessor is too tedious. Mile is meant to help -with that by producing C code filled with at least 98% preprocessor lines -for any input. Now you too can enjoy long compile times with minimal -effort.
- -Output is randomized using system clock, so if you wait a second between -runs, you should get a different generated code even for the same -encoding PIN.
Customized bytecode encoding of preprocessor boilerplates, mostly for -compression but should also make reverse engineering more fun.
CRC32 of the source code is embedded in the source code itself.
Code layout shaped to resemble “Mile” from “Didn’t I Say to Make My -Abilities Average in the Next Life?!”. Mile is known to be able to talk -to nanomachines directly, which is exactly what programming in -preprocessor feels like.
Mile has been verified to work in these environments (also, compiles -without warnings on all of these):
- -Output of Mile is a bit more taxing, and only works with a subset of the -above:
- -For people eager to encode large files, an extra utility has been packaged -with this entry to preprocess the generated output to make them more -acceptable to typical compilers. View the cppp.cc source and -then compile it with a c++ compiler of your choice.
-![]() |
-© Copyright 1984-2020,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |

-
-Please visit -www.ioccc.org -for the official IOCCC web. -
-Please do NOT bookmark nor link to this -experimental web site: -
-https://ioccc-src.github.io/temp-test-ioccc/ --
-When this experiment is finished, this site will go away! -
-This test web tree is part of the -temp-test-ioccc GitHub repo: -
-https://github.com/ioccc-src/temp-test-ioccc --
-This web site will be undergoing major changes, so expect many broken links, typos and other problems. -If you wish to recommend changes (understanding that things may be rapidly changing out from under your copy), -then consider making pull requests against the -temp-test-ioccc GitHub repo. -
[ The judges |
-IOCCC home page |
-How to enter |
-FAQ |
-Contacting the IOCCC
-
-IOCCC news |
-People who have won |
-Winning entries ]
The source winners of the 27th IOCCC have been released. Congratulations!
- -The IOCCC is currently CLOSED.
- -Right now, you CANNOT register as a contestant with the IOCCC,
-nor can you submit an entry because the IOCCC is yet NOT open.
-
-
Please see the watch the IOCCC news below for information on the next IOCCC. - -
You may also check on the status.json for the current status of the IOCCC. - - -
-
-We also added to the -status.json page, -a "latest_news" JSON member whose value is the date -of the most recent news item. -
-For example: -
-- "status_date" : "Mon Jan 30 02:28:44 PST 2023", - "latest_news" : "Mon Jan 30 02:28:44 PST 2023" -
-In addition to the IOCCC-style easter egg, you may count on -the JSON status page having a JSON member with name of "contest" -that will have a value of either "closed" or "open". -When a future IOCCC is announced or the IOCCC is currently open, -the JSON member with name of "contest" will change from -"closed" to "open". -
-Additional JSON members be added describing the contest such as -the IOCCC contest number, open date, close date, timezone, etc. -The details of such additional JSON members are TBD. -
-When an open IOCCC closes, we won't instantaneously update the -status.json page. -Instead you will have to rely on the additional JSON information -and/or read the IOCCC news, -and/or follow us on Mastodon via @ioccc@fosstodon.org. -
-Our Mastodon username is: @ioccc@fosstodon.org. -
-Please note: As of the date of this posting, our account was just setup, -so there isn't much to read there, yet. --
-In the future we plan to use Mastodon as our official announcement platform. -This will include announcing: -
-When registering for a new IOCCC, we will no longer ask for an optional twitter handle. -Instead, you will be asked if you wish to provide a Mastodon username when you submit your IOCCC entry. -Use of Mastodon is NOT required to enter the IOCCC, but nevertheless is encouraged. -Proving a Mastodon username will be entirely optional. -
-Non-mastodon users can follow the IOCCC postings via: -fosstodon.org/@ioccc. -
-If you do not yet have a Mastodon account, you may obtain a free mastodon account via: -joinmastodon.org. -
-If you do have / obtain a Mastodon account, please do us a favor and -follow the IOCCC at: -
-@ioccc@fosstodon.org --The IOCCC wishes to thank the good folk running the -fosstodon.org -Mastodon hub. -Their technology focused -Fosstodon Hub -is made possible by volunteers, -and those who voluntarily -support the cost of their server. -
-Stay tuned in Mastodon as we update you on our progress towards the next IOCCC! -
-We are working on a submit server that will allow a registered IOCCC contestant -to upload the above mentioned compressed tarball: when the contest is open of course. -
-Once we reach version 1.0, we plan to invite the public to test and comment. -
-We plan to hold in 2023, what we will call IOCCCMOCK, a trial IOCCC contest where the -judges will go through the motions (without judging the content) of an IOCCC: -testing the above mentioned tools and testing the submit server. -
-We are working on complete rebuild of this web site as well. -
-We plan to hold IOCCC28 in 2023. -Sorry for the delay, but we think you will appreciate the re-tooling -when it is completed. -Stay tuned! -
-For example, when we announce the winners, -we will do so by committing their code to the -Winning entries -of the IOCCC repo, so that people will be able immediately -view the winning source. -
-We plan to refactor and modernize the IOCCC web site. -We also plan to build a new and improved way to submit entries the next IOCCC. -As a result of all this work we need to do, -we plan to hold IOCCC28 in 2023 instead of 2021. -Sorry for the delay, but we think you will appreciate the re-tooling -when it is completed. -
-Stay tuned for how you may be able to help in the IOCCC redesign for IOCCC28! -
Older news has been archived, but is not currently available
- -![]() |
-© Copyright 1984-2020,
-Leo Broukhis, Simon Cooper, Landon Curt Noll
-- All rights reserved |
-- |