Merge pull request #713 from xexyl/2013-birken

This commit is contained in:
Landon Curt Noll authored and GitHub committed 2023-05-09 23:31:19 +09:30
commit 762804b29d
37 files changed
+1744 -708

No files matched your search

+4 -5
View File
@@ -16,11 +16,10 @@ make all
```
[Cody Boone Ferguson](/winners.html#Cody_Boone_Ferguson) fixed this to work
under macOS. The fix was to prototype `read()` prior to being defined and not
using `int, int, int` as the entry does. Instead the second arg is a `void *`.
In the `read()` function (which actually calls `write(2)`) the `i` (which is the
`void *`) has to be cast to an `int`. This solves the problem. Thank you Cody for
your assistance!
under macOS. The fix was to not use implicit `int`s in the `read()` function as
it once did. Instead the second arg is a `void *`. In the `read()` function
(which actually calls `write(2)`) the `i` (which is the `void *`) has to be cast
to an `int`. This solves the problem. Thank you Cody for your assistance!
## Judges' remarks:
+2 -2
View File
@@ -1,2 +1,2 @@
int read(int,void*,int);i;main(){for(;i["]<i;++i){--i;}"];read('-'-'-',i+++"hell\
o, world!\n",'/'/'/'));}read(int j,void *i,int p){write(j/p+p,i---j,(int)i/(int)i);}
i;main(){for(;i["]<i;++i){--i;}"];read('-'-'-',i+++"hell\
o, world!\n",'/'/'/'));}read(j,i,p)void*i;{write(j/p+p,i---j,(int)i/(int)i);}
+199 -1
View File
@@ -99,7 +99,14 @@ BTW: this remains my (Landon Curt Noll's) all time favorite entries!
These remarks, found at
[https://lainsystems.com/posts/exploring-mullender-dot-c/](https://lainsystems.com/posts/exploring-mullender-dot-c/),
were provided by Sjoerd Mullender years later. We thank the author of the
article for the quote!
article for the quote! For a more detailed analysis, taken from the Obfuscated C
and Other Mysteries, see below. We hope that this is okay with the author of the
book. Considering that the analysis is entirely the authors' comments we don't
think this will be a problem. Unfortunately the excerpt was PDF and it did not
copy paste well. [Cody Boone Ferguson](/winners.html#Cody_Boone_Ferguson) had to
go back and forth to type so it's possible he made a typo though he also fixed
some typos found in the extract. As for the other comments:
I have never known a lot about the VAX assembly, so we used the C compiler to
create the VAX code. We didn't write it ourselves from scratch as we did with
@@ -141,6 +148,197 @@ with that, but we didn't need that for this program. In fact, we made it as
beautifier which would re-indent your program to make the layout look better. Our
program is idempotent under `cb`.
### More detailed analysis
When this program is compiled, the compiler places the array somewhere in
memory, just like it places any compiled code somewhere in memory. Usually, the
C startup code (`crt0.o`) calls a routine named `main`. The loader fills in the address in
the startup code, but, at least on the old systems where this program
ran, it doesn't know that the `main` in this program isn't code but data!
When the program is run, the C startup code transfers control to the location
`main`. The contents of the array just happen to be machine instructions for
both a PDP-11 and a VAX.
On the VAX, the routine main is called with the `calls` instruction. This
instruction uses the first (2-byte) word of the called routine as a mask of
registers that are to be saved on the stack. In other words, on the VAX the
first word can be anything. On the PDP, the first word is a branch instruction
that branches over the VAX code. The PDP and VAX codes are thus completely
separate.
The PDP and VAX codes implement the same algorithm:
```c
for (;;) {
write(1, " :-)\b\b\b\b", 9);
delay();
}
```
The result is that the symbols `:-)` move over the screen. `delay` is
implemented differently on the PDP, where we used a nonexistent system call
(`sys 55`), and on the VAX where we used a delay loop.
My co-author, Robbert, and I had earlier written a similar program for an
assignment on the PDP-11. Along came the first Obfuscated C Code Contest, and
we decided that we should write a program like this, but make it run on two
different architectures.
We didn't think long about what the program should do, so it does something very simple.
We started with writing the PDP code in assembler. We both knew PDP-11
assembler, so that was no problem. The assembler code we came up with is as
follows:
```asm
pdp:
mov pc,r4
tst -(r4)
sub $9, r4
mov r4,0f
mov $1, r0
sys 4; 0:0; 9
mov $1000, r2
1:
sys 55
sob r2,1b
br pdp
```
This is not the code we originally wrote, but it is the code that we ultimately
used in the program. The string to be printed is shared by the VAX and the PDP
code and is located between the two sections.
First, the program deals with figuring out the address of the string. Then the
program counter is saved in a scratch register. Since the program counter points
at the second instruction, we subtract 2 from the scratch register in the second
instruction. Then we subtract the length of the string and store the result in
the location with label 0. This has to do with the calling sequence of system
calls on the PDP. Following the `sys` instruction is the system call number (4
for `write`), the address of the buffer (pointed to by label 0), and the length
of the buffer (9). The file descriptor is in register `r0`. The rest of the code
implements a delay loop. In each iteration, a non-existing system call (55)
slows things down.
We assembled this program and extracted the machine code from the resulting
object file. We used this code in the VAX part. Since neither of us was fluent
in VAX assembly, we wrote the VAX code in C and massaged the compiler output.
The VAX assembly program that we came up with is as follows:
```asm
vax: .word 0400 + (pdp - vax) / 2 - 1
1:
pushl $9
pushal str
pushl $1
calls $3, write
cvtwl $32767, r2
2:
decl r2
jneq 2b
jbr 1b
write: .word 0
chmk $4
ret
str: .ascii " :-)\b\b\b\b"
pdp: .word 4548, 3044, 58820, 9, 4407, 6, 5568, 1, 35076, 0, 9, 5570, 512, 35117, 32386, 496
```
The first word (after the label `vax`) is the PDP branch instruction. PDP branch
instructions are octal `400+` the distance divided by 2. The string that both
the PDP and VAX programs use is after the `str` label, and the PDP code is after
the pap label.
On the VAX, the program pushes 9 (the length of the string), the address of the
string and 1 (the file descriptor) on the stack and calls `write`. Since we
didn't know the exact calling sequence for system calls, we just copied the
source for the `write` system call stub into our program. After `write`
finishes, the program executes a delay loop, after which it jumps back to the
start of the program.
We assembled this program, and extracted the machine code from the object file.
After this we only had to convert the machine code to ASCII and write a little
bit of C to glue everything together. We wanted to use different formats for
each constant in the resulting array, and we wanted to choose the format
randomly. So we wrote a program to choose an appropriate format at random. The
program we wrote for that follows. This program actually also extracted the
machine code from the object file.
```c
#include <stdio.h>
#include <a.out.h>
main(argc, argv) char **argv;
{
register FILE *fp;
register short pos = 0, c, n;
register char *fmt;
if (argc != 2) {
fprintf (stderr, "Usage: %s file\n", argv[0]);
exit (1);
}
if ((fp = fopen(argv[1], "r")) == NULL) {
fprintf(stderr, "%s: can't open %s\n", argv[0], argv[1]);
exit(2);
}
fseek (fp, (long) sizeof (struct exec), 0);
printf("/* portable between VAX and PDP11 */\n\n");
printf ("short main[] = {\n");
for (;;) {
if (pos == 0)
printf("\t");
c=getc(fp) & 0377;
if (feof(fp)) break;
n = getc(fp) << 8|c;
switch (rand() % 5) {
case 0:
case 1:
fmt = "%d"; break;
case 2:
fmt = "%u"; break;
case 3:
fmt = "0%o"; break;
case 4:
fmt = "0x%x"; break;
}
if (32 <= n && n < 127 && (rand() % 4)) fmt = "'%c'";
printf(n < 8 ? "%d" : fmt, n);
printf(",");
if (pos++ == 8) {
printf("\n");
pos = 0;
}
else printf(" ");
printf("};\n");
}
}
```
As can be seen, there is a slight preference for decimal, and also a character
format is sometimes used, but only if the data is a printable ASCII character.
When we ran this program, we were almost completely satisfied with the result.
The only problem we had was that the program had chosen an octal representation
for the first word. Since everybody knows what a PDP-11 branch instruction looks
like (everyone knows that the traditional magic word for an executable, `0407`,
is a PDP-11 branch), we changed that to decimal. After checking the size of the
resulting program we saw that it was one byte too long. The limit was 512 bytes,
and our program was 513 bytes. So we changed the word `and` in the comment to
`&&`.
## Copyright and CC BY-SA 4.0 License:
This file is Copyright (c) 2023 by Landon Curt Noll. All Rights Reserved.
+1 -1
View File
@@ -85,7 +85,7 @@ CSILENCE= -Wno-implicit-function-declaration
#
ifeq ($(CC),clang)
#
CSILENCE+= -Wno-implicit-int-conversion -Wno-missing-variable-declarations
CSILENCE+= -Wno-implicit-int-conversion -Wno-missing-variable-declarations \
-Wno-pedantic -Wno-poison-system-directorie
#
CWARN+= -Weverything
+9 -3
View File
@@ -20,6 +20,7 @@ make all
./a.out 2>/dev/null
```
[Cody Boone Ferguson](/winners.html#Cody_Boone_Ferguson) fixed a segfault that
prevented this entry from working at all and made an alternate version
that works with `clang`. The alternate code, described below, is what is needed
@@ -31,12 +32,17 @@ memory as a `char *s`. It's now a `char s[]`.
Thank you Cody for your assistance!
NOTE: for `clang` you'll likely have to use the alternate code described below.
### INABIAF - it's not a bug it's a feature! :-)
Please note that if the BASIC file cannot be opened for reading or the output
file cannot be opened for writing then this program will crash. These crashes
are a mild nuisance but are considered a feature not a bug. We challenge you to
fix it for learning if you wish. See also [bugs.md](/bugs.md).
file cannot be opened for writing then this program will very likely crash or do
something funny.
These are a mild nuisance but are considered a feature not a bug. We challenge
you to fix it for learning if you wish. See also [bugs.md](/bugs.md).
## Try:
+1 -1
View File
@@ -14,7 +14,7 @@ make all
```
[Cody Boone Ferguson](/winners.html#Cody_Boone_Ferguson) fixed a segfault in
this program which prevented it from working. The problem was the read-only
this program which prevented it from working. The problem was that the read-only
char array `char *z[]` was being written to. The fix was to change it to `char
z[][100]` in two spots (see if you can determine why two places, not one!). Why
100 when the longest string is < 100? Because a shorter value caused strange
+1 -1
View File
@@ -18,7 +18,7 @@ make
```
[Cody Boone Ferguson](/winners.html#Cody_Boone_Ferguson) fixed a crash and a
display problem in this entry so that it would work in modern (64-bit) systems.
display problem in this entry so that it now works in modern (64-bit) systems.
The problem was that it relied on 32-bits so some `int`s were changed to
`long`s. At this time we don't have an easy way to test this theory but it might
be that using `-m32` would let this work in 32-bit systems. Thank you Cody for
+2 -2
View File
@@ -46,7 +46,7 @@ CWARN= -Wall -Wextra ${CSILENCE}
# Compiler standard
#
CSTD= -std=gnu11
CSTD= -std=gnu99
# Compiler bit architecture
#
@@ -65,7 +65,7 @@ CINCLUDE= -include stdlib.h -include string.h -include stdio.h -include ctype.h
# Optimization
#
OPT=
OPT=
# Default flags for ANSI C compilation
#
+37 -22
View File
@@ -15,49 +15,64 @@ make
./richards
```
[Cody Boone Ferguson](/winners.html#Cody_Boone_Ferguson) fixed a minor problem
that showed up in both linux and macOS. He notes however that as of this time
this entry does not work with macOS. See [bugs.md](/bugs.md) for more details.
Thank you Cody!
## Try:
```sh
echo '10 9 8 7 6 5 4 3 2 1*p*p*p*p*p*p*p*p*p' | ./richards
echo '64 256 128 p/p*p' | ./richards
```
NOTE: this entry does not work in macOS. See [bugs.md](/bugs.md) for more
details.
## Judges' remarks:
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?
Oh no, yet another
[dc](https://en.wikipedia.org/wiki/Dc_(computer_program))-style calculator? (see
[2000/dlowe](/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?
## Author's remarks:
This is an implementation of the classic UNIX dc command, the reverse-polish
This is an implementation of the classic UNIX
[dc](https://en.wikipedia.org/wiki/Dc_(computer_program)) command, the
[reverse Polish](https://en.wikipedia.org/wiki/Reverse_Polish_notation)
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.
OH! I forgot to mention! It's a
[JIT](https://en.wikipedia.org/wiki/Just-in-time_compilation).
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.
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](https://en.wikipedia.org/wiki/Just-in-time_compilation) 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:
* If your system requires the inclusion of alloca.h to use alloca, use the
compile flag `-DAH`.
* If your system cannot use mmap, use the compile flag `-DNM`.
* I don't include any headers I don't strictly need to, so you'll get warnings
about (at least) `memcpy()`, `isdigit()`, `atoi()`, `calloc()`, `malloc()`
and `alloca()` if you didn't use `-DAH`.
* GCC likes to complain about `while (a = b)` (assignments as a condition).
* I don't return from `main()`, even though it's declared to return int.
* If your system requires the inclusion of alloca.h to use alloca, use the
compile flag `-DAH`.
* If your system cannot use `mmap()`, use the compile flag `-DNM`.
* I don't include any headers I don't strictly need to, so you'll get warnings
about (at least) `memcpy()`, `isdigit()`, `atoi()`, `calloc()`, `malloc()`
and `alloca()` if you didn't use `-DAH`.
- NOTE from judges: we added these includes in 2023.
* GCC likes to complain about `while (a = b)` (assignments as a condition).
* I don't return from `main()`, even though it's declared to return int.
Platforms on which all known/tested optimization levels work with no additional
flags:
+16 -12
View File
@@ -3,7 +3,10 @@
#endif
#include<setjmp.h>
#include<stdio.h>
#if !NM
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#ifndef NM
#include<sys/mman.h>
#endif
#define vo volatile
@@ -24,11 +27,11 @@
#define H 9<<16
#define I case
#define J(i) calloc(i,1)
#define W(c) e=(o*)memmove(e,x[(u)c],y[(u)c])+y[(u)c];
#define W(c) e=memmove(e,x[(u)c],y[(u)c])+y[(u)c];
#define N break; I
q char k;
q void o;
q unsigned long u;
q int u;
q o(*f) (vo o *);
q struct {
u *a, **R, *m, h, c;
@@ -43,7 +46,7 @@ u sk[H];
k *w;
o *x[H];
u y[H];
f *j, *e;
f j, e;
u l=256;
o g(u v)
{
@@ -59,7 +62,8 @@ f K(k * p, dt d)
{
k c, n = 0;
f r = (f) e;
W(1) while ((c = *p)) {
W(1)
while ((c = *p)) {
switch (c) {
I '#':
while (*++p != 10);
@@ -123,9 +127,9 @@ o T()
o rd(u v)
{
o *a = 0, **b = &a, **c = b + 24;
o *a = 0, **b = &a, **c = b + 32;
x[v] = w;
for (; b < c && (*b < (o *)w || *b > (o *) T || *b == (long) v); b++);
for (; b < c && (*b < (o *)w || *b > (o *) T || *b == &v); b++);
if (b == c) {
jmp_buf *j = alloca(sizeof(*j));
setjmp(*j);
@@ -146,7 +150,7 @@ o re(vo k * rec)
} F(d) M--;
*M /= M[1];
} F(p) printf("%lu\n", *M);
} F(p) printf("%d\n", *M);
} F(x) u n = *M--;
if (!S j[n])
@@ -162,8 +166,8 @@ M++;
lx(d);
}
}
o *lib1[] = { T, T, T, T, T } ;
o *lib2[] = { T, ld, lp, lx, l1 } ;
f *lib1[] = { T, T, T, T, T } ;
f *lib2[] = { T, ld, lp, lx, l1 } ;
int main()
{
@@ -189,10 +193,10 @@ int main()
S l = (f *) lib2;
S r = (f) T;
j = e =
#if NM
#ifdef NM
malloc(H);
#else
mmap(NULL, H, -1, MAP_ANON | MAP_PRIVATE, -1, 0);
(f)mmap(NULL, H, -1, MAP_ANON | MAP_PRIVATE, -1, 0);
#endif
while (b = fgets(malloc(999), 999, stdin))
((f) K(b, d)) (d);
+48 -41
View File
@@ -27,25 +27,31 @@ gcc -o e e.c
./e > 271.c
```
...
## Try:
```sh
make pi
make e
make everything
./everything.sh
```
## Judges' remarks:
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?
A
[pi](https://en.wikipedia.org/wiki/Pi)/[e](https://en.wikipedia.org/wiki/E_(mathematical_constant))
printing quasi-[quine](https://en.wikipedia.org/wiki/Quine_(computing) in [ASCII
art](https://en.wikipedia.org/wiki/ASCII_art) with a compressed font in it; what
else to wish for in this program? [Virtual
machine](https://en.wikipedia.org/wiki/Virtual_machine) emulation?
## Author's remarks:
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.
program and [pi](https://en.wikipedia.org/wiki/Pi) or
[e](https://en.wikipedia.org/wiki/E_(mathematical_constant))) computation. I
know you're tired of them.
But have you ever seen **all-in-one**?
@@ -54,57 +60,58 @@ 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:
- computes 3 digits of pi and prints it as a ASCII-art program that:
- computes 4 digits of pi and prints it as a ASCII-art program that:
- computes 5 digits of pi and prints it as a ASCII-art program that:
- computes 6 digits of pi and prints it as a ASCII-art program that:
- etc.
- computes 3 digits of pi and prints it as an ASCII-art program that:
- computes 4 digits of pi and prints it as an ASCII-art program that:
- computes 5 digits of pi and prints it as an ASCII-art program that:
- computes 6 digits of pi and prints it as an ASCII-art program that:
- ...
One more thing... When you give a command line option "e" to the
first program, the generated one will compute Napier's constant
One more thing... When you give a command line argument `e` to the
first program, the generated one will compute [Napier's
constant](https://en.wikipedia.org/wiki/E_(mathematical_constant)))
rather than pi.
### Obfuscation
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`.
This program itself is in the shape of a
[spigot](https://en.wikipedia.org/wiki/Tap_(valve)). This is derived from
analogy with [spigot algorithm](https://en.wikipedia.org/wiki/Spigot_algorithm)
which infinitely computes the value of a mathematical constant such as
[pi](https://en.wikipedia.org/wiki/Pi) or
[e](https://en.wikipedia.org/wiki/E_(mathematical_constant)).
<http://en.wikipedia.org/wiki/Spigot_algorithm>
The two sets of programs, `314*.c` and `271*.c`, are almost the same
except their shape and constant computational part. I tailored the
common part to parse in both shapes (`3.14...` and `2.71...`), by
tweaking the computational order and adding meaningless code fragments.
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>
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,
[quines](https://en.wikipedia.org/wiki/Quine_(computing)) need 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
[Bézout's identity](https://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity) to
find the magic string, with the aid of a brute force. See `find-font-table.rb`
in detail.
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.
I'm sorry that many ASCII-art-style winning entries of
[IOCCC](https://www.ioccc.org/years.html) ignore [C preprocessor
directives](https://en.wikipedia.org/wiki/C_preprocessor). In my program,
`#include` is a part of ASCII-art with comments padded.
These design requirements made my program well-obfuscated
willy-nilly.
### Portability
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.
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 not requiring a 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
@@ -141,7 +148,7 @@ 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.
unless `-std=c99` option is given.
## Copyright and CC BY-SA 4.0 License:
+1 -1
View File
@@ -1,4 +1,4 @@
#include<stdio.h> /******** SpigotQuine -- usage: ./spigot [pi or e] ********/
#include<stdio.h> /******** SpigotQuine -- usage: ./endoh2 [pi or e] ********/
char*s="G1%%xJ{;Q7wunmuGuu%%uu#include<stdio.h>/*Spigot_Quine*/#include<stdli"
"b.h>/*_IOCCC2012_*/int*e," "i,j,k,n" ";char*q" ",*a,*d,*z,*p=%s%c;"
"int" "%cmain(){a=calloc(" "1,1e4+n*2);;for(*"
+33
View File
@@ -0,0 +1,33 @@
#!/usr/bin/env bash
make everything || exit 1
run()
{
local program="$1"
echo "" 1>&2
echo -n "$ ./${program}" 1>&2
sleep 2
"./${program}" | less -K -e
}
echo "running everything with $(type -P less): " 1>&2
echo 1>&2
run pi
run 314
run 3141
run 31415
run 314159
run 3141592
run 31415926
run 314159265
run 3141592653
run 31415926535
run e 271
run 2718
run 27182
run 271828
run 2718281
run 27182818
run 271828182
run 2718281828
run 27182818284
+56 -39
View File
@@ -1,13 +1,11 @@
# Most conspiratorial
Aaron Grothe
2205 South 51st Street
Omaha, NE 68106
US
<ajgrothe@yahoo.com>
Aaron Grothe
US
<ajgrothe@yahoo.com>
David Madore
<http://www.madore.org/~david/>
David Madore
<http://www.madore.org/~david/>
## To build:
@@ -17,13 +15,14 @@ make
## To run:
To create a shared secret shared among M people with N+1 needed to reconstruct:
To create a shared secret shared among `M` people with `N+1` needed to reconstruct:
```sh
./grothe -secret 1-/dev/urandom 2-/dev/urandom ... N-/dev/urandom 1+shared1 2+shared2 ... M+sharedM
./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
To reconstruct the original (an arbitrary combination of `N+1` or
more shared files with their proper numbers):
```sh
@@ -42,28 +41,27 @@ more shared files with their proper numbers):
## Judges' remarks:
Also known as Best abuse of the judging process.
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.
The IOCCC 2012 submission page didn't enforce the 2048 meaningful character
limit. This entry, as submitted, weighed in at 2222 chars but lucky for it, it
was 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.
It was clear to the judges that the extra size was an entry beautification step.
Had it not been, this entry would have been rejected in round 0.
The judges also took some liberty obfuscating this entry a litte more.
The judges also took some liberty obfuscating this entry a little more.
How does this entry work? The only place multiplication is used is
to perform the atoi conversion.
to perform the `atoi()` conversion.
## Author's remarks:
**Description**
### Description
This program implements a version of Shamir's Secret Sharing. Shamir's Secret
This program implements a version of [Shamir's Secret
Sharing](http://en.wikipedia.org/wiki/Shamir%27s_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.
@@ -72,18 +70,19 @@ Actually surprisingly useful for an IOCCC entry :-)
### Usage
To share a secret
To share a secret.
E.g.
file to be shared - cookie\_recipe.txt
File to be shared - [cookie_recipe.txt](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:
To split a secret into 4 pieces of which at least 3 will be needed to get it (in
this case a recipe) back:
```sh
./grothe \
@@ -92,7 +91,7 @@ To share secret into 4 pieces of which at least 3 will be needed to get back the
1+cookie_piece1.dat 2+cookie_piece2.dat 3+cookie_piece3.dat 4+cookie_piece4.dat
```
To put recipe back together using 1, 2 and 4th piece:
To put recipe back together using the first, second and fourth pieces:
```sh
./grothe \
@@ -102,25 +101,43 @@ To put recipe back together using 1, 2 and 4th piece:
### Limitations
* program is limited to 256 input and output files and will slow down dramatically when you get past 20-50 inputs and outputs
The program is limited to 256 input and output files and will slow down
dramatically when you get past 20-50 inputs and outputs.
### Obfuscations
* nothing is done consistently throughout the program E.g i+=1, i=i+1, i++ and ++i are all used in the program. The mark of true code buggery. - "A foolish consistency is the hobgoblin of little minds" - Ralph Waldo Emerson
* uses the most powerful obfuscation of all "Math". "Any sufficiently advanced cryptography is indistinguasble from magic" - Apologies to Arthur C. Clarke
* shadows variables by using brackets in main program to create local copies of variables that are the same as global scope variables. -Wshadow should probably be a part of -Wall in gcc
* uses array\_index[array\_name] instead of array\_name[array\_index] in several places. Still don't know why C continues to allow this
( error strings are encoded with offsets that are also used to select them in the case statement. All strings are located in one function for easy localization
* liberal use of octal numbers, hexadecimal numbers and regular decimal numbers throughout program
* nothing is done consistently throughout the program E.g `i+=1`, `i=i+1`, `i++`
and `++i` are all used in the program. The mark of true code buggery: "A
foolish consistency is the hobgoblin of little minds." - [Ralph Waldo
Emerson](https://en.wikipedia.org/wiki/Ralph_Waldo_Emerson)
* uses the most powerful obfuscation of all "Math". "Any sufficiently advanced
cryptography is indistinguishable from magic." - Apologies to [Arthur C.
Clarke](https://en.wikipedia.org/wiki/Arthur_C._Clarke)
* shadows variables by using brackets in main program to create local copies of
variables that are the same as global scope variables. `-Wshadow` should
probably be a part of `-Wall` in gcc.
* uses `array_index[array_name]` instead of `array_name[array_index]` in several
places. Still don't know why C continues to allow this (error strings are
encoded with offsets that are also used to select them in the case statement.
All strings are located in one function for easy localization).
* liberal use of octal numbers, hexadecimal numbers and regular decimal numbers
throughout program.
* variables and function names are semi-random and upper and lower case characters are used
* use of #defines from stdio.h, stdlib.h for values \_STDIO\_H and EXIT\_SUCCESS used to represent 1 and 0 respectively in the program
* arrays only need to be 256x256 most are set to greater values than they need to be so trying to figure it out can be a bit tough
* use of `#define`s from `stdio.h`, `stdlib.h` for values `_STDIO_H` and
`EXIT_SUCCESS` used to represent 1 and 0 respectively in the program.
* arrays only need to be 256x256 but most are set to greater values than they
need to be so trying to figure it out can be a bit tough.
### References
* Shamir's Secret Sharing - <a href="http://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing">http://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing</a>
* David Madore's implementation of Shamir's Secret Sharing - <a href="http://www.madore.org/~david/programs/programs-1.36.html">http://www.madore.org/~david/programs/programs-1.36.html</a>
* Steve's Recipe Database - source for the $25k Cookie Recipe - <a href="http://recipes.stevex.net/">http://recipes.stevex.net/</a>
* David Madore's implementation of Shamir's Secret Sharing - <http://www.madore.org/~david/programs/programs-1.36.html>
* Steve's Recipe Database - source for the $25k Cookie Recipe - <https://www.mealsteps.com>
## Copyright and CC BY-SA 4.0 License:
+21 -19
View File
@@ -1,7 +1,7 @@
# Most elementary use of C - Silver award
Tsukasa Hamano
<hamano@cuspy.org>
Tsukasa Hamano
<hamano@cuspy.org>
## To build:
@@ -21,7 +21,11 @@ make
./hamano < README.md > hint.pdf
```
You can read output.pdf with PDF reader acroread hint.pdf or evince hint.pdf.
You can read `hint.pdf` with a PDF reader like `acroread hint.pdf` or `evince
hint.pdf`. With macOS you can do `open hint.pdf` which by default will open
`Preview.app`. You may of course use your pdf view to open the file directly
instead.
To deobfuscate:
@@ -39,7 +43,7 @@ cc -Wno-implicit-function-declaration -xc hello.pdf -o hello2
./hello3
```
## Judges' remarks
## Judges' remarks:
This entry treads into a new territory for IOCCC - generating PDF files.
@@ -63,32 +67,30 @@ 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
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?
## Author's remarks
## Author's remarks:
This program obfuscate text file into PDF file with Dancing men
algorithm.
This program obfuscate text file into PDF file with [Dancing men
algorithm](http://en.wikipedia.org/wiki/The_Adventure_of_the_Dancing_Men).
<http://en.wikipedia.org/wiki/The_Adventure_of_the_Dancing_Men>
Probably, the output PDF file is compliant with PDF 1.3. And also
Probably, the output PDF file is compliant with PDF 1.3 and it's 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:
I've tested it with GCC 4.7 and Clang 3.0 with Linux, and the following
PDF Readers:
* Adobe Acrobat Reader
* Evince
* Ghostscript
* Xpdf
* Adobe Acrobat Reader
* Evince
* Ghostscript
* Xpdf
### Obfuscations
This program is obfuscated by using classical methods.
But can you find out the embedded font from fragmented glyph?
This program is obfuscated by using classical methods. But can you find the
embedded font in the fragmented glyph?
## Copyright and CC BY-SA 4.0 License:
+1
View File
@@ -1,3 +1,4 @@
hou
hou.html
remarks.htm
remarks.htm
+58 -19
View File
@@ -1,8 +1,8 @@
# Most useful obfuscation
Qiming Hou
<hqm03ster@gmail.com>
<http://www.houqiming.net>
Qiming Hou
<hqm03ster@gmail.com>
<http://www.houqiming.net>
## To build:
@@ -42,54 +42,93 @@ start hou.htm
## Judges' remarks:
What a versatile entry! It can be used to check the size of IOCCC entries *and* to publish them as HTML.
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?
For extra credit: what is the meaning of the number `2321237`?
## Author's remarks:
### Disclaimer
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 is 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 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 is 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 formatting constraints. The author did try to remove warnings under gcc and Visual Studio, though.
The code may throw a few warnings due to formatting 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 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.
### Syntax files
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 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 is supported:
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:
The regex engine is also algorithmically efficient. To illustrate the point,
[ansi.txt](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:
```sh
./hou ansi.txt ansi.txt
perl patho.pl < ansi.txt
```
### Limitations
Finally, there are a few limitations...
- The only escape sequence supported is \n and it doesn't work in [].
- The maximum file/rule size is a linear function of the hard-coded constant M.
- The only escape sequence supported is `\n` and it doesn't work in `[]`.
- The maximum file/rule size is a linear function of the hard-coded constant `M`.
- Single-character matches at the end of file may be missed.
- The operator | doesn't obey precedence rules and some extra ()s may be required.
- The operator `|` doesn't obey precedence rules and some extra `()`s may be required.
- Incorrect syntax files are not tolerated.
- The program relies on ASCII.
### Why obfuscated
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 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 formatting.
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 formatting.
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.
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.
### References
+12 -4
View File
@@ -1,7 +1,8 @@
# Best short program
Seonghoon Kang
<kang.seonghoon@mearie.org>
Seonghoon Kang
<kang.seonghoon@mearie.org>
<http://mearie.org>
## To build:
@@ -27,7 +28,8 @@ echo "shest'" | ./kang
[Cody Boone Ferguson](/winners.html#Cody_Boone_Ferguson) changed the code to
accept the proper German for four 'vier' where before it was spelt with the
sound of V (fier not vier). Thank you Cody!
sound of V (fier not vier). But was this a bug or a feature? He's on the fence
here but he went ahead and did it anyway as it seems useful. Thank you Cody!
## Judges' remarks:
@@ -73,7 +75,7 @@ It does *not* accept some spelt numbers, which I found mostly irrelevant:
This program is quite portable, only requiring the following:
* The signature `int main(int, int)` should be accepted by the linker. (Original
version only)
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.
* Both the compiler and execution environment should use an ASCII-compatible
@@ -120,17 +122,21 @@ Other obfuscations are more subtle:
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
@@ -151,6 +157,8 @@ 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.
More spoilers can be found at <https://gist.github.com/lifthrasiir/3909337>
### Acknowledgement
The cleaner (size-optimized) version of this program was originally published
+7 -7
View File
@@ -1,8 +1,8 @@
# Best one liner
Taketo Konno
Tokyo, Japan
<inaniwa3@gmail.com>
Taketo Konno
Japan
<inaniwa3@gmail.com>
## To build:
@@ -26,7 +26,7 @@ NOTE: N is an integer from 0 to 255.
### Alternate code
An alternate version of this entry, `konno_alt.c`, is provided.
An alternate version of this entry, [konno.alt.c](konno.alt.c), is provided.
This alternate code is an unobfuscated version of the winning code.
To compile this alternate version:
@@ -60,7 +60,7 @@ Try:
./konno 165
```
There are 256 (from 0 to 255) possible rules.
There are 256 (from 0 through 255) possible rules.
### Obfuscation
@@ -70,7 +70,7 @@ This program uses bit operations. I think
7&O<<!o>>!o+29
```
is an intersting operation. This isn't equal to
is an interesting operation. This isn't equal to
```c
7&O>>29
@@ -80,7 +80,7 @@ operation. What is the operation doing?
### Limitation
This program assumes that the size of int is 4.
This program assumes that the size of `int` is 4.
## Copyright and CC BY-SA 4.0 License:
+58 -48
View File
@@ -1,8 +1,8 @@
# Most surreptitious
Don Yang
<omoikane@uguu.org>
<http://uguu.org/>
Don Yang
<omoikane@uguu.org>
<http://uguu.org/>
## To build:
@@ -36,81 +36,90 @@ cc -o output output.c
## Judges' remarks:
The judges have nothing to add that has not already been written
about in the `spoiler.html`` file! :-)
The judges have nothing to add that has not already been written about in the
[spoiler.html](spoiler.html) (requires JavaScript) file! :-)
## Author's remarks:
### Usage
Nyaruko is a binary to text filter. Given some input on stdin,
Nyaruko will produce C code that reproduces this input on stdout:
`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
```sh
./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:
```sh
bash output.c > key.c
perl output.c > data.c
```
The key-less data.c still compiles, but produces a different message
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:
```sh
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:
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
```sh
./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
`/dev/urandom`, users should always specify this extra seed argument to
avoid deterministic keys.
### Features
Implementation details that makes Nyaruko more obfuscated than usual
Implementation details that make `Nyaruko` more obfuscated than usual
programs:
* Nyaruko recycles variables and buffers to reduce internal state.
The variable names are also carefully chosen for mixed-case
madness.
* Nyaruko employs some preprocessor magic to share much of the same
code and state between the encoder and decoder, and to increase
occurrences of smileys ;)
* `Nyaruko` recycles variables and buffers to reduce internal state.
The variable names are also carefully chosen for mixed-case
madness.
* `Nyaruko` employs some preprocessor magic to share much of the same
code and state between the encoder and decoder, and to increase
occurrences of smileys ;)
Output code has these features:
* Fits nicely under 80 columns, and does not contain any trigraphs.
* Uses a fairly efficient encoding scheme, better than uuencode for
files larger than ~13K, and better than base64 for files larger
than 20K.
* Encryption with ISAAC, a cryptographically secure pseudorandom
number generator.
* Trivial 3 language polyglot.
* Fits nicely under 80 columns, and does not contain any trigraphs.
* Uses a fairly efficient encoding scheme, better than `uuencode` for
files larger than ~13K, and better than `base64` for files larger
than 20K.
* Encryption with [ISAAC](https://en.wikipedia.org/wiki/ISAAC_(cipher)), a
cryptographically secure pseudorandom number generator.
* Trivial 3 language polyglot.
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.
Code layout is meant to resemble
[Nyaruko](https://en.wikipedia.org/wiki/Nyarlathotep), 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.
### Compatibility
Nyaruko has these environment dependencies:
`Nyaruko` has these environment dependencies:
* Requires ASCII character set.
* Assumes sizeof(unsigned int) == 4.
* Best viewed with tab stops set to 8 spaces.
* Requires ASCII character set.
* Assumes `sizeof(unsigned int) == 4`.
* Best viewed with tab stops set to 8 spaces.
Output code has the same dependencies, with the additional
requirement that the compiler must support arbitrarily long string
@@ -118,23 +127,24 @@ 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
`Nyaruko` has been to verified to work with these compiler/OS
combinations:
* gcc 4.4.5 on Linux (32bit and 64bit)
* clang 3.1 on Windows (Cygwin)
* gcc 4.5.3 on Windows (Cygwin)
* gcc 4.5.3 on Windows (MingW)
* gcc 4.3.5 on JSLinux
* tcc 0.9.25 on JSLinux
* gcc 4.4.5 on Linux (32bit and 64bit)
* clang 3.1 on Windows (Cygwin)
* gcc 4.5.3 on Windows (Cygwin)
* gcc 4.5.3 on Windows (MingW)
* gcc 4.3.5 on JSLinux
* tcc 0.9.25 on JSLinux
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.
default, this means `Nyaruko` may not faithfully encode files on MingW.
### Extra files
spoiler.html - Contains full recording of how the code went from
blank state to an obfuscated program, gzipped to fit under 1MB.
[spoiler.html](spoiler.html) - Contains full recording of how the code went from
blank state to an obfuscated program, gzipped to fit under 1MB. Requires
JavaScript.
## Copyright and CC BY-SA 4.0 License:
+303 -227
View File
@@ -1,31 +1,39 @@
# Most functional
John Tromp
<john.tromp@gmail.com>
<http://tromp.github.io/>
John Tromp
<john.tromp@gmail.com>
<http://tromp.github.io/>
## To build:
make all # On a 64-bit machine (default)
```sh
make all # On a 64-bit machine (default)
make tromp32 # On a 32-bit machine
make tromp32 # On a 32-bit machine
```
## To run:
./tromp [-b]
```sh
./tromp [-b]
```
NOTE: Substitute ./tromp32 for ./tromp everywhere below if on a 32-bit machine
Use `./tromp32` as you would `./tromp` if on a 32-bit machine.
## To run:
cat ascii-prog.blc data | ./tromp -b
cat binary-prog.Blc data | ./tromp
```sh
cat ascii-prog.blc data | ./tromp -b
cat binary-prog.Blc data | ./tromp
```
## Try:
(cat hilbert.Blc; echo -n 1234) | ./tromp
(cat oddindices.Blc; echo; cat primes.blc | ./tromp -b) | ./tromp
cat primes.blc | ./tromp -b | ./primes.pl
```sh
(cat hilbert.Blc; echo -n 1234) | ./tromp
(cat oddindices.Blc; echo; cat primes.blc | ./tromp -b) | ./tromp
cat primes.blc | ./tromp -b | ./primes.pl
```
### Selected Judges Remarks:
@@ -35,91 +43,116 @@ are more obfuscated than the entry itself.
## Author's remarks:
This program celebrates the close connection between obfuscation and conciseness,
by implementing the most concise language known, Binary Lambda Calculus (BLC).
by implementing the most concise language known, [Binary Lambda Calculus
(BLC)](https://tromp.github.io/cl/Binary_lambda_calculus.html).
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.
[BLC](https://tromp.github.io/cl/Binary_lambda_calculus.html) was developed to
make [Algorithmic Information
Theory](https://en.wikipedia.org/wiki/Algorithmic_information_theory), the
theory of smallest programs, more concrete. It starts with the simplest model of
computation, the [lambda
calculus](https://en.wikipedia.org/wiki/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.
More specifically, it defines a universal machine, which, from an input stream
of bits, parses the binary encoding of a [lambda
calculus](https://en.wikipedia.org/wiki/Lambda_calculus) term, applies that to
the remainder of input (translated to a lazy list of
[booleans](https://en.wikipedia.org/wiki/Boolean_algebra), 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!
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](https://en.wikipedia.org/wiki/De_Bruijn_notation)) as `1^{n}0`.
That's all there is to
[BLC](https://tromp.github.io/cl/Binary_lambda_calculus.html)!
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
For example the encoding of lambda term `S = \x \y \z (x z) (y z)`,
with [De Bruijn notation](https://en.wikipedia.org/wiki/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.
In the closely related
[BLC8](https://tromp.github.io/cl/Binary_lambda_calculus.html#BLC8:_byte_sized_I.2FO)
language, IO is byte oriented, translating between a stream of bytes and a list
of length-8 lists of [booleans](https://en.wikipedia.org/wiki/Boolean_algebra).
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.
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.
Without arguments, it runs in byte mode, using standard input 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.
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 size of the term space is fixed at compile time with `-DA`.
A half byte `cat'
=================
### A half byte `cat`
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:
The shortest (closed) lambda calculus term is `\x x (\ 1` in [De Bruijn
notation](https://en.wikipedia.org/wiki/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
```sh
$ 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.:
that is ignored by the program, any character from ASCII 32 (space) through 47
(`/`) will do, e.g.:
echo "*Hello, world" | ./tromp
Hello, world
```sh
$ echo "*Hello, world" | ./tromp
Hello, world
```
Bad programs
============
### Bad programs
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:
it will crash in some way. E.g. the following might dump core:
echo -n "U" | ./tromp
Segmentation fault
```sh
echo -n "U" | ./tromp
```
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:
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
```sh
echo ">Hello, world" | ./tromp
Since these properties can be checked when creating BLC programs,
```
will likely dump core.
Since these properties can be checked when creating
[BLC](https://tromp.github.io/cl/Binary_lambda_calculus.html) programs,
the interpreter doesn't bother checking for it.
A Self Interpreter
==================
### A Self Interpreter
The BLC universal machine may be small at 650 bytes of C
(952 bytes including layout), but written
The [BLC](https://tromp.github.io/cl/Binary_lambda_calculus.html) 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
@@ -140,9 +173,11 @@ as a self interpreter in BLC it is downright minuscule at 232 bits (29 bytes):
11110111 11001111
01110110 00011001
00011010 00011010
```
The byte oriented BLC8 version weighs in at 43 bytes (shown in hexadecimal).
```
19468
05580
05f00
@@ -156,14 +191,18 @@ The byte oriented BLC8 version weighs in at 43 bytes (shown in hexadecimal).
0b7fb 00cf6
7bb03 91a1a
(cat uni8.Blc; echo " Ni hao") | ./tromp
Ni hao
```
A prime number sieve
====================
```sh
$ (cat uni8.Blc; echo " Ni hao") | ./tromp
Ni hao
```
### A prime number sieve
Even shorter than the self-interpreter is this prime number sieve in 167 bits (under 21 bytes):
```
000100011001100101000110100
000000101100000100100010101
11110111 101001000
@@ -174,23 +213,30 @@ Even shorter than the self-interpreter is this prime number sieve in 167 bits (u
00010110
0000110110
The n'th bit in the output indicates whether n is prime:
```
cat primes.blc | ./tromp -b | head -c 70
0011010100010100010100010000010100000100010100010000010000010100000100
The `n`th bit in the output indicates whether n is prime:
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)
```sh
$ 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](https://en.wikipedia.org/wiki/Bit_numbering) = 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
```
$ (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
```
A Space filling program
=======================
### A Space filling program
Program hilbert.Blc, at 143 bytes, is a very twisty "one-liner" (shown in hexadecimal):
The 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
@@ -206,245 +252,275 @@ Program hilbert.Blc, at 143 bytes, is a very twisty "one-liner" (shown in hexade
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:
It expects `n` arbitrary characters of input, and draws a space filling [Hilbert
curve](https://en.wikipedia.org/wiki/Hilbert_curve) of order `n`:
(cat hilbert.Blc; echo -n "1") | ./tromp
_
| |
```sh
$ (cat hilbert.Blc; echo -n "1") | ./tromp
_
| |
(cat hilbert.Blc; echo -n "12") | ./tromp
_ _
| |_| |
|_ _|
_| |_
$ (cat hilbert.Blc; echo -n "12") | ./tromp
_ _
| |_| |
|_ _|
_| |_
(cat hilbert.Blc; echo -n "123") | ./tromp
_ _ _ _
| |_| | | |_| |
|_ _| |_ _|
_| |_____| |_
| ___ ___ |
|_| _| |_ |_|
_ |_ _| _
| |___| |___| |
$ (cat hilbert.Blc; echo -n "123") | ./tromp
_ _ _ _
| |_| | | |_| |
|_ _| |_ _|
_| |_____| |_
| ___ ___ |
|_| _| |_ |_|
_ |_ _| _
| |___| |___| |
(cat hilbert.Blc; echo -n "1234") | ./tromp
_ _ _ _ _ _ _ _
| |_| | | |_| | | |_| | | |_| |
|_ _| |_ _| |_ _| |_ _|
_| |_____| |_ _| |_____| |_
| ___ ___ | | ___ ___ |
|_| _| |_ |_| |_| _| |_ |_|
_ |_ _| _ _ |_ _| _
| |___| |___| |_| |___| |___| |
|_ ___ ___ ___ ___ _|
_| |_ |_| _| |_ |_| _| |_
| _ | _ |_ _| _ | _ |
|_| |_| | |___| |___| | |_| |_|
_ _ | ___ ___ | _ _
| |_| | |_| _| |_ |_| | |_| |
|_ _| _ |_ _| _ |_ _|
_| |___| |___| |___| |___| |_
$ (cat hilbert.Blc; echo -n "1234") | ./tromp
_ _ _ _ _ _ _ _
| |_| | | |_| | | |_| | | |_| |
|_ _| |_ _| |_ _| |_ _|
_| |_____| |_ _| |_____| |_
| ___ ___ | | ___ ___ |
|_| _| |_ |_| |_| _| |_ |_|
_ |_ _| _ _ |_ _| _
| |___| |___| |_| |___| |___| |
|_ ___ ___ ___ ___ _|
_| |_ |_| _| |_ |_| _| |_
| _ | _ |_ _| _ | _ |
|_| |_| | |___| |___| | |_| |_|
_ _ | ___ ___ | _ _
| |_| | |_| _| |_ |_| | |_| |
|_ _| _ |_ _| _ |_ _|
_| |___| |___| |___| |___| |_
A BrainFuck interpreter
=======================
```
The smallest known BF interpreter is written in... you guessed it, BLC,
### A [Brainfuck](https://en.wikipedia.org/wiki/Brainfuck) interpreter
The smallest known BF interpreter is written in... you guessed it,
[BLC](https://tromp.github.io/cl/Binary_lambda_calculus.html),
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
```
$ 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.
It expects its input to consist of a
[Brainfuck](https://en.wikipedia.org/wiki/Brainfuck) program
(looking only at bits `0`, `1` and `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!
```
$ more hw.bf
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.]
$ cat bf.Blc hw.bf | ./tromp
Hello World!
```
Curiously, the interpreter bf.Blc is the exact same size as hw.bf.
Curiously, the interpreter `bf.Blc` is the exact same size as `hw.bf`.
A BLC assembler
===============
### A BLC assembler
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
```sh
$ echo "\f\x f (f (f x))" > three
$ cat parse.Blc three | ./tromp
000001110011100111010
Converting between bits and bytes
=================================
```
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:
### Converting between bits and bytes
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
```sh
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
```
$ 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
```sh
$ cat rev.Blc - | ./tromp
Hello, world!
^D
!dlrow ,olleH
```
Symbolic Lambda Calculus reduction
==================================
### Symbolic Lambda Calculus reduction
BLC8 program symbolic.Blc shows individual reduction steps on symbolic lambda terms.
BLC8 program `symbolic.Blc` shows individual reduction steps on symbolic lambda terms.
Here it is used to show the calculation of 2^3 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)))))))
```sh
$ 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.
As expected, the resulting normal form is [Church
numeral](https://en.wikipedia.org/wiki/Church_encoding) 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:
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)
```sh
$ 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
```sh
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),
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
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
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
===========
### Performance
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
using so-called [Higher Order Abstract
Syntax](https://en.wikipedia.org/wiki/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
```sh
$ 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
===========
### Obfuscation
Obfuscation is due entirely to conciseness. Some questions to ponder:
Which of the term space codes 0,1,2,3 serves multiple purposes?
Which of the term space codes `0`, `1`, `2`, `3` serve multiple purposes?
Why is the environment pointer pointing into the term space?
What does the test u+m&1? do?
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?
And how do any of those BLC programs work?
Portability
===========
### Portability
The program freely (without casting) converts between int and int\*, causing
The program freely (without casting) converts between int and `int *`, causing
many warnings;
note: expected ‘int *’ but argument is of type ‘int’
```
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: 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.
It implicitly declares functions `read()`, `write()`, `exit()` and `calloc()`, the latter two incompatibly.
32 bit and 64 bit executables are separate [Makefile](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.
How the program works
=====================
### How the program works
See the file how13.
See the file [how.md](how.md).
Acknowledgements
================
### Acknowledgements
Christopher Hendrie, Bertram Felgenhauer, Alex Stangl, Seong-hoon Kang,
and Yusuke Endoh have contributed ideas and suggestions for improvement.
and [Yusuke Endoh](/winners.html#Yusuke_Endoh) have contributed ideas and
suggestions for improvement.
References
==========
### References
Binary Lambda Calculus
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>
<https://web.archive.org/web/20121125233450/https://www.cs.auckland.ac.nz/~chaitin/cup.html>
Jean-Louis Krivine. 2007.
A call-by-name lambda-calculus machine
+66
View File
@@ -0,0 +1,66 @@
# Spoiler
The program implements a so called [Krivine
machine](https://en.wikipedia.org/wiki/Krivine_machine), enhanced with a [basic
input/output system](https://en.wikipedia.org/wiki/BIOS) and a reference
counting [garbage collector](https://en.wikipedia.org/wiki/Waste_collector). The
Krivine machine is a stepwise transformer of a global state consisting of the
current term, the current environment (a list of closures), and a stack of
continuations (see the 3rd reference for details).
The term space holds [lambda
calculus](https://en.wikipedia.org/wiki/Lambda_calculus) terms in the following
format. 0 denotes some form of IO; the only four occurrences are at:
```
C=13: recognizes end of a byte
C=20: recognize output of 0 bit
C=21: recognize output of 1 bit
C=end: input list, expanded lazily
```
`1` denotes a variable, with next entry its de [Bruijn
index](https://en.wikipedia.org/wiki/De_Bruijn_index).
`2` denotes application with next entry the size of the term being applied.
`3` denotes lambda abstraction.
A closure consists of the following items:
0. pointer to the next closure (as part of an environment), or next record on
free list.
1. reference count
2. pointer to environment
3. lambda term (index in term space)
Here's what each variable do:
```
L Lambda term space
m mode: 0 for bits and 7 for bytes
b bits remaining unread in I, -1 on EOF
D Desirable temporary
c continuation context
a active environment pointer
C Current term index
U Ultimate term pointer
u utility entry
B Born to be free-list of closures
I Input character
O Output character
e entry of current term
```
Here's what each of the 6 auxiliary functions do:
```
s variable lookup in active environment with de Bruijn index u
S gets one bit of input, setting b to -1 on EOF or to remaining number of bits in current byte
k copy fragment from string literal holding lambda terms xor 46 into current end of term space
x expand input, adding 11 (resp. 99) entries to term space for bit (resp. byte) mode
p parses BLC-encoded lambda term using S(), stores results in term space and returns length
d decrease reference counter, add record to free list on reaching zero
```
-45
View File
@@ -1,45 +0,0 @@
Gur cebtenz vzcyrzragf n fb pnyyrq Xevivar znpuvar,
raunaprq jvgu n onfvp vachg/bhgchg flfgrz
naq n ersrerapr pbhagvat tneontr pbyyrpgbe.
Gur Xevivar znpuvar vf n fgrcjvfr genafsbezre bs n tybony fgngr pbafvfgvat bs
gur pheerag grez, gur pheerag raivebazrag (n yvfg bs pybfherf), naq n fgnpx bs pbagvahngvbaf
(Frr gur 3eq ersrerapr sbe qrgnvyf.)
Gur grez fcnpr ubyqf ynzoqn pnyphyhf grezf va gur sbyybjvat sbezng
0 qrabgrf fbzr sbez bs VB; gur bayl sbhe bpphenaprf ner ng
P=13: erpbtavmrf raq bs n olgr
P=20: erpbtavmr bhgchg bs 0 ovg
P=21: erpbtavmr bhgchg bs 1 ovg
P=raq: vachg yvfg, rkcnaqrq ynmvyl
1 qrabgrf n inevnoyr, jvgu arkg ragel vgf qr Oehvwa vaqrk
2 qrabgrf nccyvpngvba jvgu arkg ragel gur fvmr bs gur grez orvat nccyvrq
3 qrabgrf ynzoqn nofgenpgvba
N pybfher pbafvfgf bs gur sbyybjvat vgrzf
0 cbvagre gb gur arkg pybfher (nf cneg bs na raivebazrag), be arkg erpbeq ba serr yvfg
1 ersrerapr pbhag
2 cbvagre gb raivebazrag
3 ynzoqn grez (vaqrk va grez fcnpr)
Urer'f jung rnpu inevnoyr qbrf:
Y Ynzoqn grez fcnpr
z zbqr; 0 sbe ovgf naq 7 sbe olgrf
o ovgf erznvavat haernq va V, -1 ba RBS
Q Qrfvenoyr grzcbenel
p pbagvahngvba pbagrkg
n npgvir raivebazrag cbvagre
P Pheerag grez vaqrk
H Hygvzngr grez cbvagre
h hgvyvgl ragel
O Obea gb or serr-yvfg bs pybfherf
V Vachg punenpgre
B Bhgchg punenpgre
r ragel bs pheerag grez
Urer'f jung rnpu bs gur 6 nhkvyvnel shapgvbaf qbrf:
f: inevnoyr ybbxhc va npgvir raivebazrag jvgu qr Oehvwa vaqrk h
F: trgf bar ovg bs vachg, frggvat o gb -1 ba RBS be gb erznvavat ahzore bs ovgf va pheerag olgr
x: xbcl sentzrag sebz fgevat yvgreny ubyqvat ynzoqn grezf kbe 46 vagb pheerag raq bs grez fcnpr
k: kcnaq vachg, nqqvat 11 (erfc. 99) ragevrf gb grez fcnpr sbe ovg (erfc. olgr) zbqr
c: cnefrf oyp-rapbqrq ynzoqn grez hfvat F(), fgberf erfhygf va grez fcnpr naq ergheaf yratgu
q: qrpernfr ersrerapr pbhagre, nqq erpbeq gb serr yvfg ba ernpuvat mreb
+1
View File
@@ -5,3 +5,4 @@ restored-chocolate.png
restored-ioccc.png
restored.png
vik
vik.alt
+2 -2
View File
@@ -112,8 +112,8 @@ OBJ= ${PROG}.o
DATA= chocolate.png ioccc.png
TARGET= ${PROG}
#
ALT_OBJ=
ALT_TARGET=
ALT_OBJ= ${PROG}.alt.o
ALT_TARGET= ${PROG}.alt
#################
+78 -46
View File
@@ -1,8 +1,8 @@
# Best use of cocoa - Bronze award
Daniel Vik
<daniel@vik.cc>
<http://danielvik.com/>
Daniel Vik
<daniel@vik.cc>
<http://danielvik.com/>
## To build:
@@ -10,7 +10,8 @@
make
```
This entry requires [Zlib](http://www.zlib.net/).
This entry requires [Zlib](https://www.zlib.net).
## To run:
@@ -44,6 +45,16 @@ To extract the embedded PNG:
./vik d encodedimg.png > restored.png
```
There is an alternate version which might work for Windows. See Alternate code
section below.
### INABIAF - it's not a bug it's a feature! :-)
The author stated that the program will crash if no argument is passed to the
program or if invalid arguments or images of mismatching sizes or unsupported
pixel formats though we note that your computer might also [halt and catch
fire](https://en.wikipedia.org/wiki/Halt_and_Catch_Fire_(computing)) :-)
## Try:
```sh
@@ -53,45 +64,65 @@ To extract the embedded PNG:
./vik d ioccc-in-chocolate.png > restored-ioccc.png
```
### Alternate code:
Based on the author's description it should be able to get this entry to work
for Windows. With his instructions [Cody Boone
Ferguson](/winners.html#Cody_Boone_Ferguson) added the alternate version that
does this for the few who might use Windows. To compile:
```sh
make alt
```
Use `vik.alt` as you would `vik` above.
We're not sure whether we want to thank Cody or not for this :-) and he's not
sure if he wants to be thanked either :-) but we appreciate it nonetheless.
## Judges' remarks:
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`?
Can you discern hidden pieces of chocolate in
[chocolate-in-ioccc.png](chocolate-in-ioccc.png)?
![chocolate in ioccc](chocolate-in-ioccc.png "Chocolate in IOCCC")
## Author's remarks:
### Introduction
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.
This program is a [steganography](https://en.wikipedia.org/wiki/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
The program supports any 8 bit true color PNG images (RGB, RGBA, greyscale,
and greyscale+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
The program only updates the `IDAT` and `IHDR` chunks of the source image. Any
additional chunks are copied into the resulting image.
### Bonus Extractor:
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:
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$#@$](https://en.wikipedia.org/wiki/Brainfuck) 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:
```sh
./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
It is of course also possible to embed a
[brain$#@$](https://en.wikipedia.org/wiki/Brainfuck) program as a text file
(as explained above) and decode it, e.g.:
```sh
@@ -101,26 +132,25 @@ It is of course also possible to embed a brain$#@$ program as a text file
### Obfuscation
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.
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 have 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 ternary (`?:`) operator,
but this is really there to keep the program as simple as possible.
### Portability
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.
The program is portable to most platforms that have [zlib](https://www.zlib.net)
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
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
the variable declarations in the main declaration in order to run
correctly:
```c
@@ -129,31 +159,33 @@ _setmode(_fileno(stdout), 0x8000);
### Limitations
The program doesn’t have many error checks so passing in invalid arguments
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.
### Extendability
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
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$#@$](https://en.wikipedia.org/wiki/Brainfuck) 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
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
And to be honest, the chocolate image did not have a
[brain$#@$](https://en.wikipedia.org/wiki/Brainfuck) 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,
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
All these features were quite easy to add, much thanks to the (actually
pretty good) design of the code.
## Copyright and CC BY-SA 4.0 License:
+86
View File
@@ -0,0 +1,86 @@
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <io.h>
#include "zlib.h"
int
i,j,k,l
,m,n,Q,W,H,
B,Z,Y,X,O=1<<24
; char*A[999],x[
1<<24],z[1<<24],
s[1<<24],t[2<<24
],w[2<<24],*E;
uLong N; FILE
*f ; int main(
int c,char**v){
unsigned char**V
=(unsigned char
**)v;_setmode(
_fileno(stdout),
0x8000); for(m=0;
c==-11&&m<H
; m++, (*v)
+=m%3==0&&
(B&4) ,V[4]
++) n=m%W,
l=n?l:*(*V
)++,*V[4]=
!(B&2)&&
n%3?V[4
][-1]:
(i=
n<3?0:
V[4][-3],j
=m/W?V[4][-W
]:0,Z=k=!(m/W)
||n<3?0:V[4][-3
-W],*(*V)+++(l?l
-1?l-2?l-3?(X=j-
Z,X=X>0?X:-X,Y=i-
Z,Y=Y>0?Y:-Y,Z=i+j
-Z-Z,Z=Z>0?Z:-Z,X>Y
||X>Z?Y >Z?k:j:i):
(i+j) /2:j:i:0));
for( E=t+O; *v-1[v]
&&c== -16; ++*v)n=**v,n
-62? n-60?n -91?n-93||!
m|| !*E?* v:(*v=A[--m+9
]): (A[9+ m++]=*v-1):--E
:++ E ,n-43?n-44?n-45?
n- 46 ?0:putchar(*E):--*E
:(* E= getchar()):++*E; for(;
7< -c &&11>-c&&*v!=5[v]; ++*v)
**V =c +8?c+9?*V[1]++<<6|56:**V|~3
&*V [1] ++:**V>>6; for(; m<n*2; m+=2)c
+18? c+19 ?0:(V[1][m/8]+=(*V[0] ++-56)>>m
%8) :(* V[1]++=V[0][m/8]<<m%8 ); return !
c?c: c>0 ?n=main(-7,(Q=**++v,N=0x49444154,*A
=s+4, main (-128 ,A),A[1]=*++v,A [4]=z,*A=x,A))
,c=A[ 6] -x- 12,Q-101?main(-19,(main(-10,(A[5]=
t+n, *A= t, A[1]=z,A)),*A=t,A [1]=w,A)):main(-9,(
main( -8 ,((n=main(-7,(A[1] =*++v,A[4]=t,*A=s+4,
A)))<0 ? main (-18,(n= -n,*A=s,A[1]=t,A)):0,A[
5]=t+n ,*A= t,A) ),*A=t, A[1]=z,A)),98-Q?E=memcmp(
w,s,4 )? n+= main(-22 ,(*A=z,A[1 ]=t,A[2]=t+n
,A)), N=n= main (-23,(*A=t, A[1]=z,A[2 ]=z+n,A)),
memmove (x+ c+n+12 ,x+c,12),memcpy(x+c+8,t, n),main(-128
,(*A= x+c +4,A)) ,N=crc32( 0,memcpy(x +c+4,s,4),n
+4), main (-128, (*A=x+c+ n+12,A)),n +=c+24,x:(n=
strlen (w +4),w+4),fwrite(E ,1,n,stdout): main(-16,(*A=w,
A[1]=w +H, A)) :-c>31?main(c+=32 ,(*--*v=N,N>>=8,v)):-++c<4?(-c)
[*V]+256*main(c,v ):c+23?c+22?c+21?c+6?c+5?c+4?0:(N=O,uncompress(*v=s+4,&N
,v[3],v[2]-v[3] ),main(c-7,v),H):(n-=l=main(-4,v)+12,5[*v]-68?(v[6]=(*v+=
l)):(memcpy(v[2],*v+8,l-12),v[2]+=l-12,memmove(*v,*v+l,n)),main(c-(n>8),v))
:(n= main(-24,v),main(-4,v)-0x89504e47?-H:main(c,(*v+=16,W=main(-4,v)*3,*v
+= 4,H=main(-4,v)*W,B=(*v)[5],(*v)[5]=2,N=crc32(0,*v- 8,17),*v+=
13 ,main(-128,v),v[3]=v[2]=w+O,*v-=21,v))):(* *v=0,memcpy
(++*v ,v[1],W),*v+=W,v[1]+=W, 1+main((v[1]
!=v[2]) *--c,v)):(N=O
,compress(*v,&N, v[1],v[2]-v[1]),N):(f=
fopen(v[1],"rb"))?fclose((n=fread(*v,1,O,f),f)),
n[*v]=0,n:(strcpy(*v,v[1]),0); }
+36 -33
View File
@@ -15,8 +15,8 @@ make
./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.
where `file.c` is the file to be checked for nesting errors. For example, you may
try [incorrect.c](incorrect.c) and the program itself.
## Try:
@@ -25,10 +25,13 @@ try incorrect.c and the program itself.
./zeitak < incorrect.c
```
NOTE: it prints an error and exits on the first nesting error so it will not
detect multiple issues!
### Alternate code
An alternate version of this entry, `zeitak.alt.c`, is provided.
The file `zeitak.alt.c` provides a version that has been slightly
An alternate version of this entry, [zeitak.alt.c](zeitak.alt.c), is provided.
The file [zeitak.alt.c](zeitak.alt.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.
@@ -40,13 +43,14 @@ make alt
Use `zeitak.alt` as you would `zeitak` above.
## Judges' remarks
## Judges' remarks:
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](https://twitter.com/ioccc/status/252162898800033792)
[18
minutes](https://web.archive.org/web/20130925190722/https://twitter.com/ioccc/status/252162898800033792)
just to understand 18 key characters of this code.
## Author's remarks
@@ -58,8 +62,8 @@ just to understand 18 key characters of this code.
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.
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
@@ -74,51 +78,50 @@ around it's position.
printf(")");
* Doesn't get confused by the 1984/anonymous entry!
* Doesn't get confused by the [1984/anonymous](/1984/anonymous/anonymous.c) entry!
#### Mis-Features
* Escapes (e.g. `\"`) are ignored, so the following line will produce
an error:
* Escapes (e.g. `\"`) are ignored, so the following line will produce
an error:
printf("\"");
#### Obfuscation
IOCCC winners already contain entries without digits, control-flow
[IOCCC winners](/years.html) already contain entries without digits, control-flow
keywords and certain operators in their source. This entry has an
even more limited source, that is:
* Without any digits.
* Without any character constants.
* Without using functions from headers other than stdio.
* Without any control-flow keywords (not even the ?: operator).
* Without any arithmetic or logic operators!
* Without any digits.
* Without any character constants.
* Without using functions from headers other than stdio.
* Without any control-flow keywords (not even the `?:` operator).
* Without any arithmetic or logic operators!
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:
##### Additional obfuscations include:
* Extensive reuse of identifiers: Macros share names with variables, inner
curly braces scopes contain variables with names identical to those in the
outer scopes and some of the variables have different uses in different
parts of the program. Even the large array has more than one use.
* A complicated data structure with "unused" fields.
* Mostly one-letter identifiers.
* Complex recursion: A function might call itself once, twice, or not at all.
* Extensive reuse of identifiers: Macros share names with variables, inner
curly braces scopes contain variables with names identical to those in the
outer scopes and some of the variables have different uses in different
parts of the program. Even the large array has more than one use.
* A complicated data structure with "unused" fields.
* Mostly one-letter identifiers.
* Complex recursion: A function might call itself once, twice, or not at all.
#### Compilation/Running Notes
#### Compilation/Portability/Running Notes
* The program requires `char` to be one byte and pointers to be
at least two bytes long.
* 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
* 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 and CC BY-SA 4.0 License:
+1
View File
@@ -1 +1,2 @@
birken
birken.alt
+5 -3
View File
@@ -57,7 +57,7 @@ ARCH=
# Defines that are needed to compile
#
CDEFINE=
CDEFINE= -DZ=15000
# Include files that are needed to compile
#
@@ -120,8 +120,8 @@ DATA= belmont.txt bloober.txt bomberman.txt boo.txt bub.txt cheepcheep.txt \
toad.txt triple0.gif triple1.gif
TARGET= ${PROG}
#
ALT_OBJ=
ALT_TARGET=
ALT_OBJ= ${PROG}.alt.o
ALT_TARGET= ${PROG}.alt
#################
@@ -138,6 +138,8 @@ all: data ${TARGET}
${PROG}: ${PROG}.c
${CC} ${CFLAGS} $< -o $@ ${LIBS}
${PROG}.alt: ${PROG}.alt.c
${CC} ${CFLAGS} $< -o $@ ${LIBS}
# alternative executable
#
alt: data ${ALT_TARGET}
+337 -78
View File
@@ -1,8 +1,8 @@
# Best painting tool
Michael Birken
<o__1@hotmail.com>
<http://www.meatfighter.com/>
Michael Birken
<o__1@hotmail.com>
<http://www.meatfighter.com/>
## To build:
@@ -10,46 +10,109 @@
make
```
An alternate version which allows one to more easily see what is going on is
available. See Alternate code section below for more details.
WARNING: if you have a problem with flashing colours please consider whether you
should try this entry or not. This problem can also occur with the alternate
version but to a lesser degree depending on how it's configured.
## To run:
```sh
./birken < 17_columns_wide_paint_by_numbers_file
```
## Try:
```sh
./birken < ioccc.txt
perl -e 'map{map{print int(rand()*8);}(0..16);print chr(10);}(0..30);' | tr '[0-4]' ' '| ./birken
./demo.sh
BIRKEN=birken.alt ./demo.sh
```
### Alternate code:
Along with the [demo.sh](demo.sh), based on the author's recommendations,
[Cody Boone Ferguson](/winners.html#Cody_Boone_Ferguson) added an alternate
version for this entry which allows one to control how fast the painting is
done. To compile:
```sh
make clobber alt
```
Finding the 'right' default value was a fine line; the default, 15000
microseconds (0.015 seconds), will take quite a while to finish but it allows
one to more easily see what is going on. Even easier to see would be 25000 but
these values make it quite slow and one could easily lose interest. Like some
other entries where Cody made this type of alternate version he made it
configurable at compile time. If you wish to speed it up by 100% you can instead
do:
```sh
make clobber CDEFINE=-DZ=7500 alt
```
That will speed it up a fair amount but of course it will still take a while to
finish. If you wish to speed it up 200% you can use instead `3750`. Doing this
you might find the right value; use ctrl-c to terminate the program early.
Given that the [original](birken.c) version is easy to see without a delay this
slower value shouldn't be a problem.
Use `birken.alt` as you would `birken` above.
Thank you Cody!
## Judges' remarks:
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
absolute best: it is possible to achieve 0 by writing:
```c
/* *\
/....
```
The game of Tetris had been used in many endeavors, from studying [algorithmic complexity](http://arxiv.org/abs/cs/0210020) to [treating PTSD](http://www.livescience.com/19894-tetris-treat-ptsd-flashbacks.html).
The game of Tetris had been used in many endeavors, from studying [algorithmic
complexity](http://arxiv.org/abs/cs/0210020) to [treating
PTSD](http://www.livescience.com/19894-tetris-treat-ptsd-flashbacks.html) and
it's even been [put on MIT's Green
Building](http://hacks.mit.edu/Hacks/by_year/2012/tetris/).
Using it for painting by numbers looks like a novel idea.
## Author's remarks:
### About This Document
This document is best viewed as an HTML file in a browser that supports animated gifs.
This document is best viewed as an HTML file in a browser that supports animated
[GIF](https://en.wikipedia.org/wiki/GIF)s.
See the files: `*.txt`, `*.png` and `*.gif`.
### Abstract
By rotating, positioning and dropping a predetermined sequence of pieces, this program exploits the mechanics of Tetris to generate arbitrary images.
By rotating, positioning and dropping a predetermined sequence of pieces, this
program exploits the mechanics of Tetris to generate arbitrary images.
### Algorithm Overview
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.
The algorithm converts pixels from a source image into squares in the
[Tetris](https://en.wikipedia.org/wiki/Tetris) play-field, 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.
![](pen0.gif)
@@ -57,41 +120,89 @@ The algorithm converts pixels from a source image into squares in the Tetris pla
![](pen2.gif)
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.
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 play-field. 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.
![](platform0.gif)
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.
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.
![](platform1.gif)
### Single Square Emitters
For reference, the names of the 7 Tetriminos (the game pieces) appear in the table below.
For reference, the names of the 7
[tetriminos](https://en.wikipedia.org/wiki/Tetromino) (the game pieces or
actually a kind of geometric shape used in
[Tetris](https://en.wikipedia.org/wiki/Tetris)) appear in the table below.
![](names.png)
This algorithm was tailored specifically to render sprites from early video games. Those games packed graphics into 8&times;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&times;16 or 16&times;32 pixels.
This algorithm was tailored specifically to render sprites from early video
games. Those games packed graphics into 8x8 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 16x16 or 16x32 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.
The animation below depicts all the patterns used to emit single squares. `J`,
`T` and `L` [tetriminos](https://en.wikipedia.org/wiki/Tetromino) 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.
![](pen4.gif)
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.
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](https://en.wikipedia.org/wiki/Tetromino). As a result, the minimal
width of a play-field 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.
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](https://en.wikipedia.org/wiki/Tetromino), are unsupported.
![](pen5.gif)
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.
With 2 rows, the only means of spanning the full play-field width in a way that
remains supported is to use `S` and `Z`
[tetriminos](https://en.wikipedia.org/wiki/Tetromino). But, that will always
leave holes in the upper row.
![](pen6.gif)
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 &times; 3 + 1 = 61, which is not divisible by 4 and hence not constructible out of Tetriminos. However, a width of 21 yields 21 &times; 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 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](https://en.wikipedia.org/wiki/Tetromino). 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&times;20 squares, a 1:2 ratio. The program maintains that ratio by using a playfield of 21&times;42 squares.
The original [Tetris](https://en.wikipedia.org/wiki/Tetris) play-field is 10 x
20 squares, a 1:2 ratio. The program maintains that ratio by using a play-field
of 21 x 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 &#8722; 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 &times; 7 + 1 = 148, requiring 37 Tetriminos. As the images below show, those patterns do exist.
Since `J`, `T` and `L` [tetriminos](https://en.wikipedia.org/wiki/Tetromino) 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.
![](pen7.gif)
@@ -99,45 +210,83 @@ Since J, T and L Tetriminos are used interchangeably to produce the emitted squa
### Platforms
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.
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](https://en.wikipedia.org/wiki/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.
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](https://en.wikipedia.org/wiki/Tetromino) 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.
![](platform2.gif)
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.
In the middle of platform construction, the bottom row gets completed and
cleared, leaving 3 rows above it. The final `J` or `L`
[tetrimino](https://en.wikipedia.org/wiki/Tetromino) 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.
Also, of the 19 possible ways to start constructing a platform on top of a `T`
[tetrimino](https://en.wikipedia.org/wiki/Tetromino), only the 10 patterns shown
above exist.
### Program Input
The input sprite is represented textually. Digit characters `0` to `7` correspond to pixels with colors from the palette below.
The input sprite is represented textually. Digit characters `0` to `7`
correspond to pixels with colors from the palette below.
![ANSI color palette](palette.png)
As discussed above, sprites are limited to a maximum of 3 colors from this palette.
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.
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 `*.txt` files contain different sprites in this textual format that can be
fed into standard input. Several examples take advantage of the
[Tetris](https://en.wikipedia.org/wiki/Tetris) play-field background color.
Instead of using character `0`, internal regions marked as transparent are
effectively rendered as black.
###Program Output
### Program Output
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 program conceptually uses [Tetris](https://en.wikipedia.org/wiki/Tetris) as
an output device similar to a [line
printer](https://en.wikipedia.org/wiki/Line_printer). It restricts itself to
those operations that can be performed on the Tetris play-field: spawning,
rotating, positioning and dropping
[tetriminos](https://en.wikipedia.org/wiki/Tetromino). This process is visually
represented using ANSI escape sequences.
### ANSImation
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.
The rate at which the program plays
[Tetris](https://en.wikipedia.org/wiki/Tetris) is completely determined by the
rate in which the terminal application receives and displays the [ANSI
escape](https://en.wikipedia.org/wiki/ANSI_escape_code) sequences.
To slowdown the output programmatically, introduce a delay immediately after the call to `fflush`.
To slow down the output programmatically, introduce a delay immediately after the
call to `fflush()` (N.B: see [birken.alt.c](birken.alt.c)).
### IOCCC Size Tool Bug
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.
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*_ = "'""/*";
@@ -148,58 +297,118 @@ $ ./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.
When that line is deleted from this program, the tool properly reports the
secondary size limit of the program as 2048.
```sh
$ ./iocccsize -i < prog.c
$ ./iocccsize -i < birken.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.
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.
###Obfuscations
### Obfuscations
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.
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.
Variables are named and ordered to spell out, `"Tetris"`, `"ELORG"`, `"DVK"` and
the aforementioned `"Tea"`.
[ELORG](https://en.wikipedia.org/wiki/Elektronorgtechnica) 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](https://en.wikipedia.org/wiki/Alexey_Pajitnov)'s original 1984
[Tetris](https://en.wikipedia.org/wiki/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:
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
```c
[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.
The source is formatted to resemble the
[Tetris](https://en.wikipedia.org/wiki/Tetris) play-field mid-game. It is also
an homage to all the [past IOCCC entries](/years.html) 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&times;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 first string stores the coordinates of the squares of the 19 distinct
rotations of [tetriminos](https://en.wikipedia.org/wiki/Tetromino) (see below).
Since a tetrimino is a chain of 4 squares, all tetriminos fit within a 4x4
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.
![](rotations.png)
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 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](https://en.wikipedia.org/wiki/Tetromino)
index. Another 5 bits is required for the drop x-coordinate since there are 21
columns in the play-field. 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 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.
### Obfuscations
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 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`.
* 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.
* 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.
* 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 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.
* The file size of [birken.c](birken.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.
### Beyond Obfuscation
Due to the contest code size constraint, some optimizations reluctantly had to be omitted. For example, multi-square emitters are possible:
Due to the contest code size constraint, some optimizations reluctantly had to
be omitted. For example, multi-square emitters are possible:
![](multi2.gif)
@@ -209,7 +418,8 @@ Due to the contest code size constraint, some optimizations reluctantly had to b
![](multi5.gif)
In fact, using dynamic programming and creative heuristics, real-time search is possible, enabling patterns like this:
In fact, using dynamic programming and creative heuristics, real-time search is
possible, enabling patterns like this:
![](triple0.gif)
@@ -217,7 +427,11 @@ And, even this:
![](triple1.gif)
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.
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](https://en.wikipedia.org/wiki/Tetromino) to erode them down to a
single emitted square.
The details of these enhancements are left as an exercise to the reader.
@@ -225,36 +439,81 @@ 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 program
* `helloworld.txt` - Hello World, Tetris-style
* `hilbert.txt` - A graphic based on the Hilbert curve
* `ioccc.txt` - IOCCC
* `landon.txt` - Portrait of a man with glasses
* `leo.txt` - Portrait of a man without glasses
* `rhino.txt` - A purple rhinoceros
* `simon.txt` - Portrait of a man without hair
* [format.txt](format.txt) - The layout of the program
* [helloworld.txt](helloworld.txt) - Hello World, Tetris-style
* [hilbert.txt](hilbert.txt) - A graphic based on the Hilbert curve
* [ioccc.txt](ioccc.txt) - IOCCC
* [landon.txt](landon.txt) - Portrait of a man with glasses
* [leo.txt](leo.txt) - Portrait of a man without glasses
* [rhino.txt](rhino.txt) - A purple rhinoceros
* [simon.txt](simon.txt) - Portrait of a man without hair
The 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).
The 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, 1986
* `bloober.txt` - Bloober, Super Mario Brothers, Nintendo, 1985
* `bomberman.txt` - Bomberman, Bomberman, Hudson, 1983
* `boo.txt` - Boo, Super Mario Brothers 3, Nintendo, 1988
* `bub.txt` - Bub, Bubble Bobble, Taito, 1986
* `cheepcheep.txt` - Cheep Cheep, Super Mario Brothers, Nintendo, 1985
* `gurin.txt` - Gurin, Binary Land, Hudson, 1983
* `koopaparatroopa.txt` - Koopa Paratroopa, Super Mario Brothers, Nintendo, 1985
* `lakitu.txt` - Lakitu, Super Mario Brothers, Nintendo, 1985
* `mario.txt` - Fire Mario, Super Mario Brothers, Nintendo, 1985
* `mspacman.txt` - Ms. Pac-Man and Ghost, Ms. Pac-Man, Midway, 1982
* `paranaplant.txt` - Piranha Plant, Super Mario Brothers, Nintendo, 1985
* `samus.txt` - Samus Aran, Metroid, Nintendo/Intelligent Systems, 1986
* `toad.txt` - Toad, Super Mario Brothers 2, Nintendo, 1987
* [belmont.txt](belmont.txt) - [Simon
Belmont](https://en.wikipedia.org/wiki/Simon_Belmont),
[Castlevania](https://en.wikipedia.org/wiki/Castlevania_(1986_video_game)),
[Konami](https://en.wikipedia.org/wiki/Konami), 1986
* [bloober.txt](bloober.txt) - Bloober, [Super Mario
Brothers](https://www.mariowiki.com/Super_Mario_Bros.),
[Nintendo](https://en.wikipedia.org/wiki/Nintendo), 1985
* [bomberman.txt](bomberman.txt) -
[Bomberman](https://en.wikipedia.org/wiki/Bomberman), Bomberman,
[Hudson](https://en.wikipedia.org/wiki/Hudson_Soft), 1983
* [boo.txt](boo.txt) - [Boo](https://www.mariowiki.com/Boo), [Super Mario
Brothers 3](https://www.mariowiki.com/Super_Mario_Bros._3), Nintendo, 1988
* [bub.txt](bub.txt) - [Bub](https://bubblebobble.fandom.com/wiki/Bub), [Bubble
Bobble](https://en.wikipedia.org/wiki/Bubble_Bobble), Taito, 1986
* [cheepcheep.txt](cheepcheep.txt) - [Cheep
Cheep](https://www.mariowiki.com/Cheep_Cheep), Super Mario Brothers, Nintendo, 1985
* [gurin.txt](gurin.txt) - Gurin, [Binary
Land](https://en.wikipedia.org/wiki/Binary_Land), Hudson, 1983
* [koopaparatroopa.txt](koopaparatroopa.txt) - [Koopa
Paratroopa](https://www.mariowiki.com/Koopa_Paratroopa), Super Mario Brothers,
Nintendo, 1985
* [lakitu.txt](lakitu.txt) - [Lakitu](https://www.mariowiki.com/Lakitu), Super
Mario Brothers, Nintendo, 1985
* [mario.txt](mario.txt) - [Fire Mario](https://www.mariowiki.com/Fire_Mario),
Super Mario Brothers, Nintendo, 1985
* [mspacman.txt](mspacman.txt) - [Ms.
Pac-Man](https://pacman.fandom.com/wiki/Ms._Pac-Man) and Ghost, Ms. Pac-Man,
[Midway](https://en.wikipedia.org/wiki/Midway_Games), 1982
* [paranaplant.txt](paranaplant.txt) - [Piranha
Plant](https://www.mariowiki.com/Piranha_Plant), Super Mario Brothers, Nintendo,
1985
* [samus.txt](samus.txt) - [Samus
Aran](https://metroid.fandom.com/wiki/Samus_Aran),
[Metroid](https://metroid.fandom.com/wiki/Metroid_(game)), Nintendo/[Intelligent
Systems](https://en.wikipedia.org/wiki/Intelligent_Systems), 1986
* [toad.txt](toad.txt) - [Toad](https://www.mariowiki.com/Toad), Super Mario
Brothers 2, Nintendo, 1987
The origin of the remaining files are described below:
* `happyface.txt` - Based on a smiley; rights unknown
* `snoo.txt` - 8-bit version of Snoo, Reddit's alien mascot
* [happyface.txt](happyface.txt) - Based on a
[smiley](https://en.wikipedia.org/wiki/Smiley); original trademark of smiley
[Smiley Company](https://en.wikipedia.org/wiki/The_Smiley_Company)
* [snoo.txt](snoo.txt) - 8-bit version of [Snoo](https://www.reddit.com/r/Snoo/),
[Reddit](https://www.reddit.com)'s alien mascot
## Copyright and CC BY-SA 4.0 License:
+50
View File
@@ -0,0 +1,50 @@
char*_ = "'""/*";
#include <stdio.h>
#include <unistd.h>
#define m 21
#define o(l, k) for(l=0; l<k; l++)
#define n(k) o(T, k)
int E,L,O,R,G[42][m],h[2][42][m],g[3][8],c
[42][42][2],f[42]; char d[42]; void v( int
b,int a,int j){ printf("\33[%d;%df\33[4%d"
"m ",a,b,j); } void u(){ int T,e; n(42)o(
e,m)if(h[0][T][e]-h[1][T][e]){ v(e+4+e,T+2
,h[0][T][e]+1?h[0][T][e]:0); h[1][T][e]=h[
0][T][e];}fflush(stdout);usleep(Z);}void q(int l
,int k,int p){
int T,e,a; L=0
; O=1; while(O
){ n(4&&L){ e=
k+c[l] [T][0];
h[0][L-1+c[l][
T][1]][p?20-e:
e]=-1; } n(4){ e=k+c[l][T][0]; a=L+c[l][T][
1]+1; if(a==42 || h[0][a][p?20-e:e]+1){ O=0
; } } n(4){ e= k+c[l][T][0]; h[0][L + c[l][
T][1]][p?20-e: e]=g[1][f[p?19+l:l]]; } L++;
u(); } n(42) { o(e,m)if(h[0][T][e]<0)break;
o(a, m&&e==m){ for(L=T; L; L--) { h[0][L][a
]=h[0][L-1] [a ]; } h[0][0][a]=-1; } } u();
}int main(){ int T,e,t,r,i,s ,D,V,K; printf("\33[2J\33[?25l"); n(8)g[i=
1][T]=7-T; R--; n(42) o(e,m) G[T][e]--; while(fgets(d,42,stdin)) { r=++
R; n(17){ e=d[T]-48; d[T]=0; if ((e&7)==e) { g[0][e] ++; G[R][T+2]=e; }
} } n(8)if(g[0][7-T]){ t=g[i ][O]; g[i][O++]=g[i][T]; g[i][T]=t; } n(8)
g[2][g[i][T]]=T; n(R+i)o(e,m )if(G[T][e]+i) G[T][e]=g[2][G[T][e]]; n(19
)o(t,2){ f[T+t+T]=(T["+%#,4" "5>GP9$5-,#C?NX"]-35)>>t*3&7; o(e,4){ c[T]
[e][t]=("5'<$=$8)Ih$=h9i8'9" "t=)83)l4(99(g9>##>4(" [T+t+T]-35)>>e*2&3;
} } n(15) { s=T>9?m:(T&3)-3?15:36;o(e,s)o(t,2)c[T+19][e][t]="6*6,8*6.608.6264826668\
865::(+;0(6+6-6/8,61638065678469.;88))()3(6,8*6.608.6264826668865:+;4)-*6-6/616365,\
-6715690.5;,89,81+,(023096/:40(8-7751)2)65;695(855(+*8)+;4**+4(((6.608.626482666886\
5:+;4+4)0(8)6/61638065678469.;88)-4,4*8+4(((60(/6264826668865:+;4-616365676993-9:54\
+-14).;./347.+18*):1;-*0-975/)936.+:4*,80987(887(0(*)4.*""/4,4*8+4(((6264826668865:\
+;4/4-4+8-4)0(8)6365678469.;88)1/(6*6,6.60626466686:8)8-8*818.8582/9863(+;/""*6,6.6\
0626466686:4(8)8-8*818.8582/9863(+;/,6.60626466686:8-818.8582/9864*4+4(0())+;/.6062\
6466686:8/8380/7844,4-4*4+4(0())69+;/0626466686:818582/9864.4/4,4-4*4+4(0())+;" [e+E
+e+t]-40; E+=s+s; } n(45){ if(T>i) { v(2,T,7); v(46,T,7); } v(2+T,44,7); } T=0; o(e,
42)o(t,m)h[T][e][t]--; while(R+i) { s = D=0; if (r-R) { n(19) if (G[R+i][T]+i) V=T/2
; else if(G[R][T]+i) s++; if(s) { if(V>4){ V=9-V; D++; } V+=29; n(20) q(c[V][T][0],c
[V][T][i],D); } } n(19) if((L=G[R][T])+i) { O=T-L; e=O>9; t=e?18-O :O; o(K,((t&3)-3?
16:37)){ if(K){ L=c[t+19][K-i][0]; O=c[t+19][K-i][i] ; } q(L,O,K && e); } } if(s) q(
c[V][20][0], c[V][20][i], D); R--; } printf("\33[47;1f\33[?25h\33[40m"); return 0; }
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/env bash
make clobber everything 2>/dev/null
if [[ -z "$BIRKEN" ]]; then
BIRKEN="birken"
fi
trap "clear; exit" SIGINT
for i in *.txt; do
NAME="$(echo "$i" | awk '{ print toupper(substr($1,1,1)) substr($1,2)}'|sed -e 's/\.txt//g' \
-e 's/Ioccc/IOCCC/g' -e 's/Mspacman/Ms Pac-Man/g' -e 's/Helloworld/Hello World/g' \
-e 's/Cheepcheep/Cheep Cheep/g' -e 's/Happyface/Happy Face/g' -e 's/Paranaplant/Piranha Plant/g' \
-e 's/Koopaparatroopa/Koopa Paratroopa/g')"
read -r -n1 -p "Press any key to try $NAME: "
./"${BIRKEN}" < "$i"
echo
done
clear
+2 -2
View File
@@ -54,7 +54,7 @@ Can you find a pattern here?
What happens if you specify different numbers?
This tiny one-liner is a bit-twiddlers delight! It does all of the work
This tiny one-liner is a bit-twiddler's 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
@@ -91,7 +91,7 @@ Small, non-negative integers only. Useful range is `0 .. 511`, sorta, for LE; `
ASCII character set, 64-bit long longs are required.
v,a,r,i,a,b,l,e,s_NAME the operation.
v,a,r,i,a,b,l,e,s\_NAME the operation.
No loops, no branches?!?
+186 -41
View File
@@ -647,8 +647,9 @@ This will be fixed in time but it's noted here for now.
## STATUS: INABIAF - please **DO NOT** fix
If the BASIC file cannot be opened for reading or the output file cannot be
opened for writing the program will crash. This is not a bug but a feature.
Please do not fix this except for the challenge.
opened for writing the program will very likely crash or do something funny.
This is not a bug but a feature. Please do not fix this except for the
challenge to yourself.
Please also note that for `clang` you have to use [dds.alt](1991/dds/dds.alt.c) not
[dds.c](1991/dds/dds.c).
@@ -1903,45 +1904,126 @@ tends to result in empty output.
## [2011/richards](2011/richards/richards.c) ([README.md](2011/richards/README.md))
## STATUS: doesn't work with some platforms - please help us fix
This does not appear to work with macOS, resulting in a segfault. We're not
sure if this is to do with the Apple silicon chip or not but it seems unlikely.
At first glance it appeared to be that it might be the function pointers. These
were changed a bit and it might have helped a bit but this is not certain
either. What was noticed is that there is an overflow according to `asan`:
This does not appear to work with macOS, resulting in a segfault (and sometimes
a bus error).
We're not
sure if this is to do with the Apple silicon chip or not but it seems like it
_might_ (see Apple resources below) be but it could also be a wider problem with macOS. It appears that
Apple does not allow certain combinations of memory protections with the arm64
processor.
[Cody Boone Ferguson](/winners.html#Cody_Boone_Ferguson) tried some of the
workarounds but at this time he could not get it to work. He offers some earlier
debugging sessions below as well as a resource from the author as well as some
resources on Apple's website should anyone wish to take a crack at it. He might
address it later.
### Debugging
At first glance it appeared to be that it might be the function pointers or the
fact it is trying to execute code in memory (as noted above). The function
pointers were changed a bit but this has not helped solve the problem with
macOS. A few things that were noticed depending on `asan` sanitisers specified.
With `address` in linux:
```
==32361==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x00016d368d08 at pc 0x000102b1dcb0 bp 0x00016d368b90 sp 0x00016d368b88
READ of size 8 at 0x00016d368d08 thread T0
#0 0x102b1dcac in rd richards.c:128
#1 0x102b1e1f4 in re richards.c:145
#2 0x102a7e7e0 in t richards.c:104
#3 0x102b1f7cc in main richards.c:185
#4 0x19498ff24 (<unknown module>)
richards.c:101:9: runtime error: null pointer passed as argument 2, which is declared to never be null
```
Address 0x00016d368d08 is located in stack of thread T0 at offset 40 in frame
#0 0x102b1dae8 in rd richards.c:125
but it actually works. This code is:
This frame has 1 object(s):
[32, 40) 'a' (line 126) <== Memory access at offset 40 overflows this variable
```c
} else
p++;
W(c)} /* LINE 101 */
}
```
Okay but what about argument 2? Well `W` is defined as:
```c
#define W(c) e=memmove(e,x[(u)c], y[(u)c])+y[(u)c];
```
so it would appear that
```c
x[(u)c]
```
(at least in my tired head?) is NULL. But why does it work then?
NOTE: `u` is `int`.
Under macOS (with the arm64 chip) we get:
```
UndefinedBehaviorSanitizer:DEADLYSIGNAL
==10834==ERROR: UndefinedBehaviorSanitizer: SEGV on unknown address 0xffffffffffffffff (pc 0x00019f446748 bp 0x00016f353100 sp 0x00016f352b90 T139066)
==10834==The signal is caused by a WRITE memory access.
#0 0x19f446748 in _platform_memmove+0xa8 (libsystem_platform.dylib:arm64e+0x3748) (BuildId: 756cd10d62a032839e57cbaa810c95ac32000000200000000100000000030d00)
#1 0x100c33c2c in main richards.c:202
#2 0x19f0bff24 (<unknown module>)
==10834==Register values:
x[0] = 0xffffffffffffffff x[1] = 0x0000000100ab18c1 x[2] = 0x00000000000000cf x[3] = 0x0000000000000000
x[4] = 0x0000000100ab18a1 x[5] = 0x0000000000000001 x[6] = 0x000000000000000a x[7] = 0x0000000000000000
x[8] = 0x00000001015972b8 x[9] = 0xffffffffffffffff x[10] = 0x0000000000000001 x[11] = 0x00000000000001f0
x[12] = 0x0000000000000001 x[13] = 0x00000000000003e0 x[14] = 0x0000000000000001 x[15] = 0x0000000000000084
x[16] = 0x000000019f4466a0 x[17] = 0x00000001ff3ad908 x[18] = 0x0000000000000000 x[19] = 0x0000000100c32a80
x[20] = 0x00000001017e0000 x[21] = 0x00000001017e1910 x[22] = 0x000000016f353530 x[23] = 0x000000019f13a366
x[24] = 0x000000016f3534b0 x[25] = 0x0000000000000001 x[26] = 0x0000000000000000 x[27] = 0x0000000000000000
x[28] = 0x0000000000000000 fp = 0x000000016f353100 lr = 0x0000000100aaf880 sp = 0x000000016f352b90
UndefinedBehaviorSanitizer can not provide additional info.
SUMMARY: UndefinedBehaviorSanitizer: SEGV (libsystem_platform.dylib:arm64e+0x3748) (BuildId: 756cd10d62a032839e57cbaa810c95ac32000000200000000100000000030d00) in _platform_memmove+0xa8
==10834==ABORTING
```
and naturally it does not work.
Adding the proper `PROT_WRITE` constant to the `mmap()` call does not seem to
help. Of course with the address this is not surprising so why is a different
address allocated in macOS? Or is it?
Now with `address` sanitiser both linux and macOS crash at:
```
=================================================================
==10983==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x00016f8d5e78 at pc 0x0001005dd910 bp 0x00016f8d5cd0 sp 0x00016f8d5cc8
READ of size 8 at 0x00016f8d5e78 thread T0
#0 0x1005dd90c in rd richards.c:132
#1 0x1005ddf8c in re richards.c:149
#2 0x1005110a0 in t richards.c:108
#3 0x1005df72c in main richards.c:189
#4 0x19f0bff24 (<unknown module>)
Address 0x00016f8d5e78 is located in stack of thread T0 at offset 56 in frame
#0 0x1005dd678 in rd richards.c:129
This frame has 2 object(s):
[32, 36) 'v.addr'
[48, 56) 'a' (line 130) <== Memory access at offset 56 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow richards.c:128 in rd
SUMMARY: AddressSanitizer: stack-buffer-overflow richards.c:132 in rd
Shadow bytes around the buggy address:
0x00702da8d150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00702da8d160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00702da8d170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00702da8d180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00702da8d190: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1
=>0x00702da8d1a0: 00[f3]f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
0x00702da8d1b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00702da8d1c0: f1 f1 f1 f1 00 f3 f3 f3 00 00 00 00 00 00 00 00
0x00702da8d1d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00702da8d1e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00702da8d1f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00702df3ab70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00702df3ab80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00702df3ab90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00702df3aba0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00702df3abb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x00702df3abc0: 00 00 00 00 00 00 00 00 f1 f1 f1 f1 04 f2 00[f3]
0x00702df3abd0: f3 f3 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
0x00702df3abe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00702df3abf0: 00 00 00 00 f1 f1 f1 f1 00 f3 f3 f3 00 00 00 00
0x00702df3ac00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00702df3ac10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
@@ -1958,35 +2040,98 @@ Shadow byte legend (one shadow byte represents 8 application bytes):
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==32361==ABORTING
==10983==ABORTING
/bin/bash: line 1: 10983 Abort trap: 6 ./richards
```
This was reported in both linux as 32-bit and 64-bit and macOS as 64-bit except
that the sizes were different in 32-bit (as expected). The code it is having a
problem with is:
which corresponds to the code:
```c
o *a = 0, **b = &a, **c = b + 24;
o rd(u v)
{
o *a = 0, **b = &a, **c = b + 32;
x[v] = w;
for (; b < c && (*b < (o *)w || *b > (o *) T || *b == (long) v); b++);
for (; b < c && (*b < (o *)w || *b > (o *) T || *b == &v); b++); /* LINE 132 */
```
where `o` is a `void`.
but this seems to not necessarily be relevant since without it it works in
linux.
A warning of interest when compiling is:
```
richards.c:169:15: warning: incompatible pointer types initializing 'f *' (aka 'void (**)(volatile void *)') with an expression of type 'o ()' (aka 'void ()') [-Wincompatible-pointer-types]
f *lib1[] = { T, T, T, T, T } ;
...
richards.c:170:15: warning: incompatible pointer types initializing 'f *' (aka 'void (**)(volatile void *)') with an expression of type 'o ()' (aka 'void ()') [-Wincompatible-pointer-types]
f *lib2[] = { T, ld, lp, lx, l1 } ;
^
richards.c:170:18: warning: incompatible pointer types initializing 'f *' (aka 'void (**)(volatile void *)') with an expression of type 'void (volatile dt)' (aka 'void (struct (unnamed at richards.c:36:3) *volatile)') [-Wincompatible-pointer-types]
f *lib2[] = { T, ld, lp, lx, l1 } ;
^~
richards.c:170:22: warning: incompatible pointer types initializing 'f *' (aka 'void (**)(volatile void *)') with an expression of type 'void (volatile dt)' (aka 'void (struct (unnamed at richards.c:36:3) *volatile)') [-Wincompatible-pointer-types]
f *lib2[] = { T, ld, lp, lx, l1 } ;
^~
richards.c:170:26: warning: incompatible pointer types initializing 'f *' (aka 'void (**)(volatile void *)') with an expression of type 'void (volatile dt)' (aka 'void (struct (unnamed at richards.c:36:3) *volatile)') [-Wincompatible-pointer-types]
f *lib2[] = { T, ld, lp, lx, l1 } ;
^~
richards.c:170:30: warning: incompatible pointer types initializing 'f *' (aka 'void (**)(volatile void *)') with an expression of type 'void (volatile dt)' (aka 'void (struct (unnamed at richards.c:36:3) *volatile)') [-Wincompatible-pointer-types]
f *lib2[] = { T, ld, lp, lx, l1 } ;
^~
```
This can be fixed easily enough however but it doesn't appear to matter in this
case.
### Resources
#### More from the author
The author has more about the entry at
<https://github.com/GregorR/ioccc2011>.
#### Apple resources
[Porting Just-In-Time Compilers to Apple
Silicon](https://developer.apple.com/documentation/apple-silicon/porting-just-in-time-compilers-to-apple-silicon?language=objc)
[Allow Execution of JIT-compiled Code
Entitlement](https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_cs_allow-jit?language=objc)
Looking at
<https://github.com/apple/darwin-xnu/blob/5394bb038891708cd4ba748da79b90a33b19f82e/bsd/kern/kern_mman.c>
Cody noticed a curious thing in the `mprotect()` function: `#if
CONFIG_DYNAMIC_CODE_SIGNING` and the protection variable has the
`VM_PROT_TRUSTED` set it might allow overriding the problem but this is
unconfirmed and it's not known when `CONFIG_DYNAMIC_CODE_SIGNING` would be
defined.
Do you have a fix? We welcome it!
## [2011/vik](2012/vik/vik.c) ([README.md](2012/vik/README.md))
## [2011/vik](2011/vik/vik.c) ([README.md](2011/vik/README.md))
## STATUS: INABIAF - please **DO NOT** fix
The author stated that the program will crash if no argument is passed tot he
The author stated that the program will crash if no argument is passed to the
program though we note that your computer might also [halt and catch
fire](https://en.wikipedia.org/wiki/Halt_and_Catch_Fire_(computing)) :-)
# 2012
## [2012/vik](2012/vik/vik.c) ([README.md](2012/vik/README.md))
## STATUS: INABIAF - please **DO NOT** fix
The author stated that the program will crash if no argument is passed to the
program or if invalid arguments or images of mismatching sizes or unsupported
pixel formats though we note that your computer might also [halt and catch
fire](https://en.wikipedia.org/wiki/Halt_and_Catch_Fire_(computing)) :-)
# 2013
+2 -2
View File
@@ -99,7 +99,7 @@ Jens Schweikhardt,Jens_Schweikhardt,http://www.schweikhardt.net,null,schweikh@sc
Jetro Lauha,Jetro_Lauha,http://jet.ro,null,null,FI,null,null
Jim Hague,Jim_Hague,http://www.oxinet.co.uk/jim,null,jim.hague@acm.org,UK,null,null
John Dalbec,John_Dalbec,https://jpdalbec.people.ysu.edu,null,jdalbec@cboss.com,null,null,null
John Tromp,John_Tromp,http://tromp.github.io/,null,john.tromp@gmail.com,null,null,null
John Tromp,John_Tromp,http://tromp.github.io/,john.tromp@gmail.com,null,null,null
John Williams,John_Williams,null,null,williams@morinda.com,null,null,null
Jon Thingvold,Jon_Thingvold,null,null,jon.thingvold@usit.uio.no,null,null,null
Jonathan Hoyle,Jonathan_Hoyle,http://www.jonhoyle.com,null,jonhoyle@mac.com,null,null,null
@@ -164,7 +164,7 @@ Sean Barrett,Sean_Barrett,http://world.std.com/~buzzard,null,buzzard@world.std.c
Sean Dorward,Sean_Dorward,null,null,null,null,null,null
Sebastian Deorowicz,Sebastian_Deorowicz,http://sun.aei.polsl.pl/~sdeor/,null,sdeorowicz@gmail.com,null,null,null
Selene Makarios,Selene_Makarios,http://www.bungalow.com/,null,null,null,null,null
Seonghoon Kang,Seonghoon_Kang,null,null,kang.seonghoon@mearie.org,null,null,null
Seonghoon Kang,Seonghoon_Kang,null,http://mearie.org,kang.seonghoon@mearie.org,null,null,null
Shinichiro Hamaji,Shinichiro_Hamaji,null,shinichiro.hamaji@gmail.com,null,null,null
Sjoerd Mullender,Sjoerd_Mullender,http://www.cwi.nl/~sjoerd/,null,Sjoerd.Mullender@cwi.nl,null,null,null
Someone Anonymous,Anonymous_2015,null,null,hirekokeshi@gmail.com,null,@hirekoke,null
Can't render this file because it contains an unexpected character in line 23 and column 6.
+2 -1
View File
@@ -685,7 +685,8 @@ Contest </I></FONT></CENTER><BR>
<!-- K K K K K K K K K K K K K K K K K K K K K K K - -->
<UL>
<LI TYPE=none><A NAME="Seonghoon_Kang"></A><B><a href="ma&#105;&#x6C;&#116;o:&#107;&#x61;&#x6E;&#x67;&#46;&#115;&#x65;&#111;n&#x67;&#104;&#111;&#x6F;&#110;&#x40;&#x6D;&#101;&#x61;&#x72;&#x69;&#101;.&#111;&#x72;&#103;">Seonghoon Kang</a></B>
<LI TYPE=none><A NAME="Seonghoon_Kang"></A><B><a
href="ma&#105;&#x6C;&#116;o:&#107;&#x61;&#x6E;&#x67;&#46;&#115;&#x65;&#111;n&#x67;&#104;&#111;&#x6F;&#110;&#x40;&#x6D;&#101;&#x61;&#x72;&#x69;&#101;.&#111;&#x72;&#103;">Seonghoon Kang</a></B> -- <A HREF="http://mearie.org">http://mearie.org</a>
<UL>
<LI TYPE=square>Best short program (<A HREF="years.html#2012_kang">2012 kang</A>)
</UL><BR>