Add preview of 1984-2019

The 2020 winners are hinted it, but the source code is not there,
nor are the hints. Someone could look into the HTML and
see what was commented out, but that is not a problem because
WHO won is known and the name of their AWARD is known already.
Moreover a number of the winners have talked about what their
entirs do, so the commented out spoiler text is not a bit problem.

One will find HTML commented out with:

    <!-- XXX remove when 2020 is ready
    2020 links here
    XXX remove when 2020 is ready -->

The "XXX remove when 2020 is ready" string is found at the
start and end comment blocks.  Again, soneone could read
what was commented out, but that is OK since most of that
information is known or can be known.  The following files
have such HTML comment blocks in them.

    ./winners.html
    ./years-spoiler.html
    ./years.html

In addition, ./all/summary.txt was modified to not
include the 2020 entries for the momemt.

The 2020 winner code AND write-ups are NOT part of this set.

p.s. The all/all.tar.bz2 does not contain the 2020 source code (yet?).
This commit is contained in:
Landon Curt Noll committed 2020-12-30 16:57:03 -08:00
1 parent 28efc67f5d
commit c0663537cb
1683 files changed
+220064

No files matched your search

BIN
View File
Binary file not shown.
+197
View File
@@ -0,0 +1,197 @@
#!/bin/make
# 2001 makefile
#
# Copyright (C) Simon Cooper, Landon Curt Noll, Peter Seebach, 2001.
# All Rights Reserved. Permission for personal, educational or non-profit
# use is granted provided this this copyright and notice are included in its
# entirety and remains unaltered. All other uses must receive prior permission
# from the contest judges.
SHELL= /bin/sh
CAT= cat
RM= rm
SED= sed
TRUE= true
# optimization
#
# Most compiles will safely use -O2. Some can use only -O.
# A few compilers have broken optimizers and thus you may
# not want anything.
#
#OPT=
#OPT= -O
OPT= -O2
# flags for ANSI compiles
#
# NOTE: Some ANSI compilers make use of -Xa to turn on ANSI mode,
# others such as gcc may want -ansi, others (Compaq Tru64 Unix)
# want -std1, and others may want nothing at all.
# Adjust the CFLAGS line as needed.
#
# NOTE: Some compilers cannot optimize, or optimize some entries
# incorrectly. You might want to turn on -O to see if your
# compiler can handle them.
#
#
#CFLAGS= -Xa ${OPT}
#CFLAGS= -std1 $(OPT)
CFLAGS= -ansi ${OPT}
# NOTE: On some systems, the library path does not include the location
# of the X11 libraries. You might need to use a -L/path/to/X11/lib/dir
# in order to compile with these libs.
#
X11CCFLAGS= -I/usr/X11R6/include -I/usr/X11R6/include/X11 -I/usr/include/X11
#X11CCFLAGS=
X11LDFLAGS= -L/usr/X11R6/lib -Wl,-R/usr/X11R6/lib
#X11LDFLAGS=
# ANSI compiler
#
# Set CC to the name of your ANSI compiler.
#
# Some entries seem to need gcc. If you have gcc, set
# both CC and MAY_NEED_GCC to gcc.
#
# If you do not have gcc, set CC to the name of your ANSI compiler, and
# set MAY_NEED_GCC to either ${CC} (and hope for the best) or to just :
# to disable such programs.
#
CC= cc
MAY_NEED_GCC= gcc
# winners that compile under ANSI C
#
WINNERS= anonymous bellard bellard.otccex cheong coupard \
ctk dgbeards herrmann1 herrmann2 jason kev ollinger rosten \
schweikh westley williams
ALT_NAMES= westley.orig
DATA_FILES= anonymous_files bellard_files herrmann1_files herrmann2_files
all: ${WINNERS}
# Most likely to amaze
#
anonymous: anonymous.c
magic='${MAY_NEED_GCC} -O1'; \
X='-DA(X)=#X'; \
warning='-pedantic -Dprocessor'; \
$$magic $$warning -Dmagic= $$X "-DX=A($$magic \"$$X\")" \
-o anonymous anonymous.c
anonymous_files: anonymous.ten.c
# Best abuse of the rules
#
bellard: bellard.c
${CC} -rdynamic ${CFLAGS} bellard.c -o bellard -ldl
bellard_files: bellard.otccex.c
# Best short program
#
cheong: cheong.c
${CC} ${CFLAGS} cheong.c -o cheong
# Most obfuscated sound
#
coupard: coupard.c
${CC} ${CFLAGS} -o coupard coupard.c
# Worst Driver
#
ctk: ctk.c
${CC} ${CFLAGS} -o ctk ctk.c
# Worst AI
#
dgbeards: dgbeards.c
${CC} ${CFLAGS} -DE=break -DF=char -DK=case -DP=int -DR=return \
-DI=0xFFFF dgbeards.c -o dgbeards
# Best abuse of the C preprocessor
#
herrmann1: herrmann1.c herrmann1.sh
@echo "NOTE: $@ must be built/run using the script $@.sh"
${SHELL} ./herrmann1.sh
herrmann1_files: herrmann1.gcd herrmann1.sh herrmann1.times2
# Most eye-crossing
#
# This entry requires the GCC -include feature.
#
herrmann2: herrmann2.c
${MAY_NEED_GCC} ${CFLAGS} herrmann2.c -o herrmann2 \
-include /usr/include/stdlib.h -include /usr/include/stdio.h \
-include /usr/include/time.h -include /usr/include/unistd.h
herrmann2_files: herrmann2.cup herrmann2.ioccc
# Best Of Show
#
jason: jason.c
${CC} ${CFLAGS} -o jason jason.c
# Best Curses Game
#
kev: kev.c
${CC} ${CFLAGS} -DPORT=5455 -DSPEED=50 -o kev kev.c \
-lcurses -ltermcap \
-Dl_="socket(il.sin_family=AF_INET,SOCK_STREAM,0)"
# Best primal ASCII graphics
#
ollinger: ollinger.c
${CC} ${CFLAGS} ollinger.c -o ollinger
# Best abuse of the user
#
rosten: rosten.c
${CC} ${CFLAGS} rosten.c ${X11CCFLAGS} ${X11LDFLAGS} -pedantic -lX11 \
-o rosten
# Best one-liner
#
schweikh: schweikh.c
${CC} ${CFLAGS} schweikh.c -o schweikh
# Best position-independant code
#
westley: westley.c
${CC} ${CFLAGS} westley.c -o westley
westley.orig: westley.orig.c
${CC} ${CFLAGS} westley.orig.c -o westley.orig
# Best position-independant code
#
williams: williams.c
${CC} williams.c ${X11CCFLAGS} ${X11LDFLAGS} -lX11 -o williams
everything: ${WINNERS} ${ALT_NAMES} ${DATA_FILES}
love:
@echo 'not war?'
haste:
${MAKE} waste
waste:
@echo 'waste'
clean:
${RM} -f *.o a.out core ${WINNERS}
clobber: clean
${RM} -f ${WINNERS}
${RM} -f ${ALT_NAMES}
nuke: clobber
@${TRUE}
install: all
${CAT} ${WINNERS} ${ALT_NAMES} > /dev/null
+97
View File
@@ -0,0 +1,97 @@
2001 marked the "The Sixteenth International Obfuscated C Code Contest"
Copyright (C) Landon Curt Noll, Simon Cooper, Peter Seebach
and Leonid A. Broukhis, 2001-2002.
All Rights Reserved. Permission for personal, educational or non-profit
use is granted provided this copyright and notice are included in its
entirety and remains unaltered. All other uses must receive prior permission
from the contest judges.
Standard IOCCC stuff
--------------------
The IOCCC has a web site and now has a number of international mirrors. The
primary site can be found at,
http://www.ioccc.org
Use make to compile entries. It is possible that on non-Un*x / non-Linux
systems the makefile needs to be changed. See the Makefile for details.
Look at the source and try to figure out what the programs do, and run
them with various inputs. If you want to, look at the hints files for
spoilers - this year we included most of the information included
by the submitters.
Read over the makefile for compile/build issues. Your system may
require certain changes (add or remove a library, add or remove a
#define).
Some ANSI C compilers are not quite as good as they should be. If
yours is lacking, you may need to compile using gcc instead of your
local compiler.
Remarks on some of the entries
------------------------------
There were some outstanding entries that did not win. Unfortunately
some very good entries lost because they:
+ depended too much on non-portable side effects in expressions;
+ depended too much on a particular byte order;
+ required the use of a special script, data file or pseudo-machine
language that was not supplied with the entry.
We hope the authors of some of those entries will fix and re-submit
them for the next IOCCC.
We believe you will be impressed with this year's winners. The Best of Show
is a fine example of obfuscation. But don't ignore the other winners!
There are games, programs that speak, ones that compile code and one that
might run binaries you already have!
The Worst Abuse of the Rules is technically allowed by the rules. This year
we awarded it again, but don't assume you can get away with using the same
technique next time ... :-)
This year there were several repeat winners. This is understating the
achievement a little - one person has won 8 times before! (Please note that
judging is done completely anonymously).
Why has it taken so long to post the winning source?
----------------------------------------------------
This is somewhat my (Simon Cooper) fault. I do apologize to the IOCCC
community for this! Judging does take quite a lot of time, and I
over-committed myself several times this year. Without divulging too much,
we do look at and work out what every entry does.
Final Comments
--------------
Please send us comments and suggestions what we have expressed above.
Also include anything else that you would like to see in future contests.
Send such email to:
questions@ioccc.org
If you use, distribute or publish these entries in some way, please drop
us a line. We enjoy seeing who, where and how the contest is used.
You must include the words ``ioccc question'' in the subject of your EMail
message when sending EMail to the judges.
If you have problems with any of the entries, AND YOU HAVE A FIX, please
EMail the fix (patch file or the entire changed file) to the above address.
Watch:
http://www.ioccc.org/
for news of the next contest.
=-=
+39
View File
@@ -0,0 +1,39 @@
#define processor x86
#include <stdio.h>
#include <sys/stat.h>
#define l int*
#define F char
struct stat t;
#define c return
#define I (P+=4,*L(P-4,0))
#define G (signed F)E(*L(P++,0))
#define C(O,D)E (D[B+V(010)/4+O*10])
#define U R[4]=E(V(17)-4),*(l)V(021)=
F M [99],Q[99],b[9999],*ss,*d=b,*z;
#define O =(n=*(l)V(021),R[4]=E(V(17)+4),n)
#define p(a,b,c) system((sprintf(a,b,k[1]),c)),z
#define g (y/010&7)
#define R (B+13)
#define x86 (F*)index\
(ss+V(i ),0100)
#define D(y,n,a,m,i,c )d+=sprintf( d,y,n,a,m,i,c ),(F*\
) P
l B,i,n,a,r,y ,
P ;
#define Tr(an,sl,at,or) l an##i(d,sl){ c at? an##i(d,r):or; } \
l an(d, sl){ c \
r=V(014 )&63,an##i(d,sl); }
#define add(Ev,Gv) Ev(){ i=((a-=16)+C(r,4))/4,(\
Gv?Ev() :0) ; } Ev##n(){ a=C(r,5),Ev(); }
Tr(L,r, C(r,3)&&C(r,3)<=d?(l)(((int)B)+d+C(r,4)-C(r,3)):(((int)B)^d)>>24&&--\
r,(l)d) Tr(Run,a,(ss=strcmp((F*)B+C((V(12)>>16),4)+C(--r,0),A(.strtab))?ss:(F\
*)B+C(r ,4),C(r,1)-2),0) add(Sca ,V(-~i)-P+2) add(ru,strcmp(ss+V(i),A(main)))
E(DX) { c *z? DX:DX <<030|(DX&65280)<<010|DX>>8&65280|DX>>24&0377; } l K(k){
c L(E(k [(l)V(17)]),0); } V(v){ c E(B[v]); }
main (char *ck, char **k) {
exit(E((ck?main((z?(stat(M,&t)?P+=a+'{'?0:3:execv(M,k),a=G,i=P,y=G&255,sprintf(Q,y/'@'-3?A(*L(V(%d+%d)+%d,0)):A(R[%d]),(y&7),'\r',y/0100-1?0:G),(a+127&&a+'}'&&a+1?(a+61&&a+24&&a+025?(P=a+'H'&&a%061<=0?P:i,D(a>0?" R[%d]=E(~-E(R[%d])),\0 U R[%d],\0 R[%d] O,\0 U %d,\0R[%d]=0,"+(a&'8')*3:a <- 'c'?" %d, %c%s = R[%d], \0 %d, *R=%c%s==R[%d], \0 R[%d]=(int)%c%s,"-a%'w'%'j'*5:"%d,%d,%s=%d,",a>0?a-'h'?a-49?a&7:g:I:g,a>0?a&7:"& "[a%3%2+1],a+72?Q:A(*R),a>0|a<-99?g:I,0)):(P=i,i=a+61?a+21?E(I):G:0,D(a%' '+29+"P O,\0 U %d,P=%d,",P,P+i,0,0,0),p(d,"A'",b))):(n=g-4?g%5-1?a+127?G:I:0:(Scan(),*( x86?processor :d)=0,(int)(ss+V(i))),g%5<2?D(g%5?" %s=E(~-E(%s)), \0 U %s,"+4*g:"%s=E(E(%s)%c%d),",Q,Q,"+ - "[g],n,0):(a=G-'u'?'!':'=',D(g-4?"P=%d%c=%s?%d:%d,":"*R=E(((int(*)(l,l,l))%s)(K(1),K(2),K(3))),P O,",n,a,Q,P,P+G),p(d,"A'",b))))):(Run((z=(F*)&ck,stat(k[1],&t),B=(l)mmap(0,i=t.st_size,3,1,open(k[1],2),0))),magic((R[4]=E(B+i/4),run(),P=V(-~i),U 0)),sprintf(M,A(.%s%d),k[1],P),D("%s %s '-DX=A(%s)' -o %s '-Dmagic=",X,__FILE__,X,M,fflush(0)))),k):p(M,A(rm -f .%s*),M),*R)));
}
+136
View File
@@ -0,0 +1,136 @@
Most likely to amaze:
The author wishes to remain anonymous
Great Britain
Judges' Comments:
To build:
make anonymous
Try:
./anonymous anonymous.ten
Is emulation the sincerest form of flattery? This small program does
quite a lot of bit twiddling.
Selected Author's Comments:
This program is an optimizing dynamic binary translator, allowing you to
run x86 programs on any machine (x86 or otherwise).
I have included a simple "10 green bottles" program, already compiled
for the x86. The program 'ten', and its source (dull) are given as info
files. Warning: note that the translator screws around with the binary
you run on it, *will* corrupt the binary to some extent, and may leave
any program you run on it unusable.
The build script should give an example command to run.
Features
Basic Block Cache: Rather than translating each instruction individually
the dynamic binary translator generates a translation for an entire
basic block of subject code. Having translated a block once, the target
code generated will be stored for the duration that the program is
running, so as a program runs its performance will improve, as it hits
cached blocks. This can be clearly observed in the example program,
'ten'.
Target Library Linking:
The program runs dynamically linked elf binaries, and when the subject
program attempts to make a call to a standard library, the translator
attempts to make an appropriate call to the native system libraries on
the target machine. This involves mangling between different calling
conventions, etc.
Automatic Endian Detection/Reversal:
There are various problems raised when attempting to run little endian
x86 code on a big endian chip, such as a PPC. These problems are dealt
with in a manner that is entirely transparent to the user.
Configuration
Warnings:
By default the build script should compile the program with a set of
switches such that while compiling the program it generates one error
(which I feel is useful advice). The program should generate no further
compiler errors while it is running (yes, the program can generate
compiler errors while it is running). If you do not wish to see this
error, or if the program generates any further error when compiled using
your C compiler please remove the "warning=..." line from the build
script.
Optimization:
The build script contains a "-O1" switch for the compiler. Increasing
the optimization level will make the program run *slower*, while
compiling the program without any optimization will allow it to run
*faster*.
Obfuscation
The most obvious part of the obfuscation is probably the mess of defines
at the top. This may seem a somewhat tired old obfuscation - however
since many of these macros are (sometimes only) used by the program once
it has dynamically recompiled itself, they are only referenced within
the source code from within strings - and therefore the macros cannot be
expanded. Furthermore, some of these strings of code are not given as
strings, but instead are wrapped up in macros that use the "#"
preprocessor operator to turn them into strings. In the hope throwing a
few C beautifiers the macro to generate the strings is not contained
within the source code but instead is passed in on the command line.
Buried under all this, and the fact that the entire program is just a
call to exit, there are some nice subtle little obfuscations. For
example, you may notice that there are a couple of macros that use the
"##" preprocessor operator to build pairs of functions. One of these
macros is used to build to pairs of functions of which only one has
local variables which shadow global variables; so one modifies the
global state, and the other doesn't.
There is also quite a nice trick where I wave a magic wand, and a chunk
of code which should only be run when the program is run for the first
time (setting the PC to point at main, etc) gets turned into a
frog^M^M^M^Mstring. The C compiler sees a string by itself in the code,
thinks "yup, thats a valid C expression", and quietly moves on to the
next line of code.
Limitations
Due to space limitations only a handful of instructions are supported,
those instructions which are supported may supported in somewhat
non-conventional ways, chunks of the architecture (e.g. flags) are just
ignored, the elf loader does not really load the elf binary, the target
library linking can only pass up to 3 parameters to the target library
function, etc, etc, etc.
In short, please consider this a full disclaimer for any bug that may
turn up - yes the program is unsafe, but it's pretty cool anyway.
Despite all this, the translator is not exclusively limited to running
the 'ten' program. Other trivial x86 programs may run on the translator
- and I have successfully run a wide range of HelloWorld programs,
including one of last years IOCCC winners, 'tomx'.
Complete Program
The fact that the program makes calls to system and execv may imply that
it is not a complete program in its own right, as it relies on other
programs. The call to system is a call to ask gcc to recompile the
translator with a new set of switches, and the call to execv asks for
the newly compiled program to be executed. I would point out that
almost every other entry to this competition also require a C compiler
(well, the published winners at any rate, and I recognize that a few
don't). There is little real difference between this program and one
like last years entry 'dhyang'; both are just C programs that generate C
code as their output.
Enjoy, thanks!
+19
View File
@@ -0,0 +1,19 @@
#define PLURAL(bottles) bottles==1?"bottle":"bottles"
void sing(int bottles) {
printf("%d green %s, standing on the wall.\n", bottles, PLURAL(bottles));
}
int main() {
int bottles = 10;
while(bottles) {
sing(bottles);
sing(bottles);
printf("And if one green bottle should accidently fall,\nThere'd be ");
sing(--bottles);
printf("\n");
}
return 0;
}
+446
View File
@@ -0,0 +1,446 @@
#include <stdio.h>
#define k *(int*)
#define a if(
#define c ad()
#define i else
#define p while(
#define x *(char*)
#define b ==
#define V =calloc(1,99999)
#define f ()
#define J return
#define l ae(
#define n e)
#define u d!=
#define F int
#define y (j)
#define r m=
#define t +4
F d,z,C,h,P,K,ac,q,G,v,Q,R,D,L,W,M;
E(n{
x D++=e;
}
o f{
a L){
h=x L++;
a h b 2){
L=0;
h=W;
}
}
i h=fgetc(Q);
}
X f{
J isalnum(h)|h b 95;
}
Y f{
a h b 92){
o f;
a h b 110)h=10;
}
}
c{
F e,j,m;
p isspace(h)|h b 35){
a h b 35){
o f;
c;
a d b 536){
c;
E(32);
k d=1;
k(d t)=D;
}
p h!=10){
E(h);
o f;
}
E(h);
E(2);
}
o f;
}
C=0;
d=h;
a X f){
E(32);
M=D;
p X f){
E(h);
o f;
}
a isdigit(d)){
z=strtol(M,0,0);
d=2;
}
i{
x D=32;
d=strstr(R,M-1)-R;
x D=0;
d=d*8+256;
a d>536){
d=P+d;
a k d b 1){
L=k(d t);
W=h;
o f;
c;
}
}
}
}
i{
o f;
a d b 39){
d=2;
Y f;
z=h;
o f;
o f;
}
i a d b 47&h b 42){
o f;
p h){
p h!=42)o f;
o f;
a h b 47)h=0;
}
o f;
c;
}
i{
e="++#m--%am*@R<^1c/@%[_[H3c%@%[_[H3c+@.B#d-@%:_^BKd<<Z/03e>>`/03e<=0f>=/f<@.f>@1f==&g!='g&&k||#l&@.BCh^@.BSi|@.B+j~@/%Yd!@&d*@b";
p j=x e++){
r x e++;
z=0;
p(C=x e++-98)<0)z=z*64+C+64;
a j b d&(m b h|m b 64)){
a m b h){
o f;
d=1;
}
break;
}
}
}
}
}
l g){
p g&&g!=-1){
x q++=g;
g=g>>8;
}
}
A(n{
F g;
p n{
g=k e;
k e=q-e-4;
e=g;
}
}
s(g,n{
l g);
k q=e;
e=q;
q=q t;
J e;
}
H(n{
s(184,n;
}
B(n{
J s(233,n;
}
S(j,n{
l 1032325);
J s(132+j,n;
}
Z(n{
l 49465);
H(0);
l 15);
l e+144);
l 192);
}
N(j,n{
l j+131);
s((e<512)<<7|5,n;
}
T y{
F g,e,m,aa;
g=1;
a d b 34){
H(v);
p h!=34){
Y f;
x v++=h;
o f;
}
x v=0;
v=v t&-4;
o f;
c;
}
i{
aa=C;
r z;
e=d;
c;
a e b 2){
H(m);
}
i a aa b 2){
T(0);
s(185,0);
a e b 33)Z(m);
i l m);
}
i a e b 40){
w f;
c;
}
i a e b 42){
c;
e=d;
c;
c;
a d b 42){
c;
c;
c;
c;
e=0;
}
c;
T(0);
a d b 61){
c;
l 80);
w f;
l 89);
l 392+(e b 256));
}
i a n{
a e b 256)l 139);
i l 48655);
q++;
}
}
i a e b 38){
N(10,k d);
c;
}
i{
g=k e;
a!g)g=dlsym(0,M);
a d b 61&j){
c;
w f;
N(6,g);
}
i a u 40){
N(8,g);
a C b 11){
N(0,g);
l z);
c;
}
}
}
}
a d b 40){
a g b 1)l 80);
r s(60545,0);
c;
j=0;
p u 41){
w f;
s(2393225,j);
a d b 44)c;
j=j t;
}
k r j;
c;
a!g){
e=e t;
k e=s(232,k n;
}
i a g b 1){
s(2397439,j);
j=j t;
}
i{
s(232,g-q-5);
}
a j)s(50305,j);
}
}
O y{
F e,g,m;
a j--b 1)T(1);
i{
O y;
r 0;
p j b C){
g=d;
e=z;
c;
a j>8){
r S(e,m);
O y;
}
i{
l 80);
O y;
l 89);
a j b 4|j b 5){
Z(n;
}
i{
l n;
a g b 37)l 146);
}
}
}
a m&&j>8){
r S(e,m);
H(e^1);
B(5);
A(m);
H(n;
}
}
}
w f{
O(11);
}
U f{
w f;
J S(0,0);
}
I y{
F m,g,e;
a d b 288){
c;
c;
r U f;
c;
I y;
a d b 312){
c;
g=B(0);
A(m);
I y;
A(g);
}
i{
A(m);
}
}
i a d b 352|d b 504){
e=d;
c;
c;
a e b 352){
g=q;
r U f;
}
i{
a u 59)w f;
c;
g=q;
r 0;
a u 59)r U f;
c;
a u 41){
e=B(0);
w f;
B(g-q-5);
A(n;
g=e t;
}
}
c;
I(&m);
B(g-q-5);
A(m);
}
i a d b 123){
c;
ab(1);
p u 125)I y;
c;
}
i{
a d b 448){
c;
a u 59)w f;
K=B(K);
}
i a d b 400){
c;
k j=B(k j);
}
i a u 59)w f;
c;
}
}
ab y{
F m;
p d b 256|u-1&!j){
a d b 256){
c;
p u 59){
a j){
G=G t;
k d=-G;
}
i{
k d=v;
v=v t;
}
c;
a d b 44)c;
}
c;
}
i{
A(k(d t));
k d=q;
c;
c;
r 8;
p u 41){
k d=m;
r m t;
c;
a d b 44)c;
}
c;
K=G=0;
l 15042901);
r s(60545,0);
I(0);
A(K);
l 50121);
k r G;
}
}
}
main(g,n{
Q=stdin;
a g-->1){
e=e t;
Q=fopen(k e,"r");
}
D=strcpy(R V," int if else while break return for define main ")+48;
v V;
q=ac V;
P V;
o f;
c;
ab(0);
J(*(int(*)f)k(P+592))(g,n;
}
+145
View File
@@ -0,0 +1,145 @@
Best abuse of the rules:
Fabrice Bellard
451 chemin du mas de Matour
34790 GRABELS
France
http://bellard.org
Judges' Comments:
To build:
make bellard
Try:
./bellard bellard.otccex.c
<JUDGES_COMMENTS>
Selected Author's Comments:
OTCC is an Obfuscated Tiny C Compiler for i386-linux. It generates
FAST! i386 32 bit code (no bytecode) and it is powerful enough to
compile itself. OTCC supports a strict subset of C. This subset is
compilable by a standard ANSI C compiler. OTCC compiles,
assembles, links and runs C code without the need of any other
program.
You can use it by typing:
./bellard bellard.c [args]...
or by giving the C source to its standard input.
'args' are given to the 'main' function of bellard.c (argv[0] is
bellard.c).
Examples:
- Sample compilation and execution:
./bellard bellard.otccex.c 10
- Self compilation:
./bellard bellard.c bellard.otccex.c 10
- Self compilation iterated...
./bellard bellard.c bellard.c bellard.otccex.c 10
An alternate syntax is to use it as a script interpreter: you can
put '#!/usr/local/bin/otcc' at the beginning of your C source if
you installed otcc at this place.
Supported C language subset (read joint example 'otccex.c' to have
an introduction to OTCC dialect):
- Expressions:
* binary operators, by decreasing priority order: '*' '/' '%',
'+' '-', '>>' '<<', '<' '<=' '>' '>=', '==' '!=', '&',
'^', '|', '=', '&&', '||'.
* '&&' and '||' have the same semantics as C : left to right
evaluation and early exit.
* Parenthesis are supported.
* Unary operators: '&', '*' (pointer indirection), '-'
(negation), '+', '!', '~', post fixed '++' and '--'.
* Pointer indirection ('*') only works with explicit cast to
'char *', 'int *' or 'int (*)()' (function pointer).
* '++', '--', and unary '&' can only be used with variable
lvalue (left value).
* '=' can only be used with variable or '*' (pointer
indirection) lvalue.
* Function calls are supported with standard i386 calling
convention. Function pointers are supported with explicit
cast. Functions can be used before being declared.
- Types: only signed integer ('int') variables and functions can
be declared. Variables cannot be initialized in
declarations. Only old K&R function declarations are parsed
(implicit integer return value and no types on arguments).
- Any function or variable from the libc can be used because OTCC
uses the libc dynamic linker to resolve undefined symbols.
- Instructions: blocks ('{' '}') are supported as in C. 'if' and
'else' can be used for tests. The 'while' and 'for' C constructs
are supported for loops. 'break' can be used to exit
loops. 'return' is used for the return value of a function.
- Identifiers are parsed the same way as C. Local variables are
handled, but there is no local name space (not a problem if
different names are used for local and global variables).
- Numbers can be entered in decimal, hexadecimal ('0x' or '0X'
prefix), or octal ('0' prefix).
- '#define' is supported without function like arguments. No macro
recursion is tolerated. Other preprocessor directives are
ignored.
- C Strings and C character constants are supported. Only '\n',
'\"', '\'' and '\\' escapes are recognized.
- C Comments can be used (but no C++ comments).
- No error is displayed if an incorrect program is given.
- Memory: the code, data, and symbol sizes are limited to 100KB
(it can be changed in the source code).
Obfuscation:
No special effort was needed because obfuscation is almost
unavoidable for such a program :-) Defines must be used to
compress the code, and integrated i386 code generator leads to non
obvious code.
Portability:
OTCC only works on i386 linux because it generates i386 code. OTCC
also relies on little endianness, unaligned memory accesses and
ASCII representation of characters. It also supposes that no valid
pointers are less than 512. If all those constraints are met, then
OTCC could be theoretically used to "cross compile", although no
such support is currently integrated.
It was successfully compiled with gcc version 2.95.2. You get some
warnings because old K&R protos are used, some casts are implicit
and some functions are used before being defined. OTCC uses the
dynamic linker to resolve symbols with 'dlsym()', so '-ldl' must
be used as library when you compile it.
+126
View File
@@ -0,0 +1,126 @@
/* #!/usr/local/bin/otcc */
/*
* Sample OTCC C example. You can uncomment the first line and install
* otcc in /usr/local/bin to make otcc scripts !
*/
/* Any preprocessor directive except #define are ignored. We put this
include so that a standard C compiler can compile this code too. */
#include <stdio.h>
/* defines are handled, but macro arguments cannot be given. No
recursive defines are tolerated */
#define DEFAULT_BASE 10
/*
* Only old style K&R prototypes are parsed. Only int arguments are
* allowed (implicit types).
*
* By benchmarking the execution time of this function (for example
* for fib(35)), you'll notice that OTCC is quite fast because it
* generates native i386 machine code.
*/
fib(n)
{
if (n <= 2)
return 1;
else
return fib(n-1) + fib(n-2);
}
/* Identifiers are parsed the same way as C: begins with letter or
'_', and then letters, '_' or digits */
fact(n)
{
/* local variables can be declared. Only 'int' type is supported */
int i, r;
r = 1;
/* 'while' and 'for' loops are supported */
for(i=2;i<=n;i++)
r = r * i;
return r;
}
/* Well, we could use printf, but it would be too easy */
print_num(n, b)
{
int tab, p, c;
/* Numbers can be entered in decimal, hexadecimal ('0x' prefix) and
octal ('0' prefix) */
/* more complex programs use malloc */
tab = malloc(0x100);
p = tab;
while (1) {
c = n % b;
/* Character constants can be used */
if (c >= 10)
c = c + 'a' - 10;
else
c = c + '0';
*(char *)p = c;
p++;
n = n / b;
/* 'break' is supported */
if (n == 0)
break;
}
while (p != tab) {
p--;
printf("%c", *(char *)p);
}
free(tab);
}
/* 'main' takes standard 'argc' and 'argv' parameters */
main(argc, argv)
{
/* no local name space is supported, but local variables ARE
supported. As long as you do not use a globally defined
variable name as local variable (which is a bad habbit), you
won't have any problem */
int s, n, f, base;
/* && and || operator have the same semantics as C (left to right
evaluation and early exit) */
if (argc != 2 && argc != 3) {
/* '*' operator is supported with explicit casting to 'int *',
'char *' or 'int (*)()' (function pointer). Of course, 'int'
are supposed to be used as pointers too. */
s = *(int *)argv;
help(s);
return 1;
}
/* Any libc function can be used because OTCC uses dynamic linking */
n = atoi(*(int *)(argv + 4));
base = DEFAULT_BASE;
if (argc >= 3) {
base = atoi(*(int *)(argv + 8));
if (base < 2 || base > 36) {
/* external variables can be used too (here: 'stderr') */
fprintf(stderr, "Invalid base\n");
return 1;
}
}
printf("fib(%d) = ", n);
print_num(fib(n), base);
printf("\n");
printf("fact(%d) = ", n);
if (n > 12) {
printf("Overflow");
} else {
/* why not using a function pointer ? */
f = &fact;
print_num((*(int (*)())f)(n), base);
}
printf("\n");
return 0;
}
/* functions can be used before being defined */
help(name)
{
printf("usage: %s n [base]\n", name);
printf("Compute fib(n) and fact(n) and output the result in base 'base'\n");
}
+12
View File
@@ -0,0 +1,12 @@
#include <stdio.h>
int l;int main(int o,char **O,
int I){char c,*D=O[1];if(o>0){
for(l=0;D[l ];D[l
++]-=10){D [l++]-=120;D[l]-=
110;while (!main(0,O,l))D[l]
+= 20; putchar((D[l]+1032)
/20 ) ;}putchar(10);}else{
c=o+ (D[I]+82)%10-(I>l/2)*
(D[I-l+I]+72)/10-9;D[I]+=I<0?0
:!(o=main(c/10,O,I-1))*((c+999
)%10-(D[I]+92)%10);}return o;}
+86
View File
@@ -0,0 +1,86 @@
Best short program:
Raymond Cheong
Johns Hopkins University
USA
http://www.bme.jhu.edu/~rcheong/
Judges' Comments:
To build:
make cheong
Try:
./cheong 1024
./cheong 12345678901234567890
./cheong 05305265226926441255040573044986873789
Be sure to give an even number of digits in the argument. Add a
leading 0 if needed.
The source code is nice, compact, and self documenting
as all good programs should be! :-)
Selected Author's Comments:
Operation
=========
Compile normally and run with one argument, an integer with 2n digits.
Program will return the integer part of its square root (n-digits).
For example,
> gcc -o cheong cheong.c
> cheong 1234567890
35136
> cheong 0200000000000000000000000000
14142135623730
>
Deviation from these instructions will cause undefined results. :-)
Portability
===========
This program runs normally on any ANSI C compiler and is ASCII dependent.
Strict compiling gives just one unavoidable warning
> gcc -ansi -Wall cheong.c
cheong.c:3: warning: third argument of `main' should probably be `char **'
Obfuscation
===========
The main obfuscation is the algorithm used to calculate square roots,
sometimes known as the longhand method. The basic algorithm is itself
obfuscated in that it only uses subtraction to calculate square roots.
(For a detailed explanation, check Google or see Jack Crenshaw's article
at http://www.embedded.com/98/9802fe2.htm) This program uses an even
more obscured version which includes the following:
- A single string is used to store two numbers of different lengths
- Operations are done in a weird hybrid of base 10 and base 20
- Subtraction is done addition style, i.e. 4 minus 8 equals 6 carry a -1
- Recursive calls to main()
Minor obfuscations:
- Self documenting whitespace in rectangular code block, for fun and
glory (view with fixed-width font)
- Integer constants adjusted to less meaningful values, just for added
confusion
- Hard-to-read, meaningless variable names to spite the reader
Challenges for the masses:
- What are the meanings [sic, plural] of the variable o?
- Why is (c+999)%10-(D[I]+92)%10 not equivalent to (c-D[I]+7)%10?
- How does the program terminate?
- Is the programmer sane? ;-)
Appreciation
============
Thanks goes out to Bobby Rohde for numerous suggestions on how to shorten
the program.
+42
View File
@@ -0,0 +1,42 @@
#include<unistd.h>
#include<time.h>
#define k ("C9B7351A@D-/E+F?')G>H%J#=I"[(d[(i/13)*2]*91+d[(i/13)*2+1]-3220)&(\
4096>>(i%13))?l+1:l]-59)
#define g(n)e(n<13?n:n<20?n+1:n>20?11+n/10:13,0);e(n>12&&n<20?26:n>20&&n%10?n%\
10:-1,2);
#define x(n)g(localtime(&a)->tm_##n)
unsigned char *d="KZs2ITTwhwZYvec@JbYxOjf9-TZRGDb/el7#q(`SZ#|_neTwq\\MqJ5cVgte\
K-ReK-(Mq8+D'6Ui0tG88vXJ-Tu{VI=d%cR]h7CumwBq\\-#{thj8fw$OEfEvLHP13_##w.OD[7Cw2\
]<T{|[F}L;L:*+A#PwLnp{9'M3Mr|w_|unm'}$*(5]_$?O9zO{{wz4p6vP8Ipu}$BQospf=-Isnyl'\
|g53o^c`ov-P`-x+|ZAd<e?<'b9P|LkZOf{B-8`K([srqv&gy1,:}$|s7D{yN6M#cQyKpC|*_|#xA#\
'YfQ}$k$kr7dM#dcnWDg|PHdA#^j&q}$x@(a;k2JB]50ZKp{xRwbkTm.v\\a3fJ@V[`J#fN`s|sZeH\
mmHX7`JKiry4sm,bUfz69{rt'k*pBq^l,ut6UVvb9N%r%l:Py3r[.Z/pBkaz2J4u{GTu)hyp#%gbS$\
r`mzi9G|3M,r}-Dt?w)_##%fQt$k&n]e$HzFXu(|Fvt`i#$A#|ykrz+nhs'P#|pm*9[_#,5P#}$}$x\
&s(i,HzO'&d&g?/_$P#kZ7Dn]e$J{zi8ypi|hq$_.|cLx`sy;f8GRMQM#7R5$hym*:^`sxrvtfQ|z_\
N|ye[7dH[}#Ts\\59V@|#z}$}$y;usL)vXFiA0AukZ8H|fyKurd]|s5<|xq@Cpm,}${,e$KufO?/2M\
t$zmM#vtfQ|zRKlEA#P&fPOwJ#pf_$?/2#@|$w}$?fLxA#^-}$cM^aA#&g#wIv?^|yY#s)Lwt'K#ON\
yoXKYkpCl0m}D[9OGU7n([ZrL)[8eRy7uR*PJ#^5xRG>zSf>p]ZrJ_[9q?qgYe^4$r3lY$4SdsSyNv\
J_l&w2I?q#fN*F1n|s9OGUv|w&l+pR-3Nudtyn@|Dfq#^o|s9Pt=oZCol/{VdgkLdwyn1yDed}?Dzi\
}#Kje#d}Y${8pSt<q?qgIv|`DH?9}$O{k(LgE;|KU-tJnWOw*F@YP#|yY$b4|.50[2d}D'kaqhp;JE\
$r&fH&'6nykYGCv>K$t?yLbwtUn[F{ncOx_.:K#nwF#f|HQs&<&bfQPE?:uJm*&\\S=*/@|We*w@$@\
f0,*H])WL<i@^xX@)(a.>MV*p{Zqf&zH%###################u2#A#_$A#_$A#_$A#_$@tA#QI#\
3#0&:p#?1[P*6WQ@i#C1{[;@|1}S%^r#g.d^z#M}$ziZe|kU6oZbq5$kF]4[E^nA#_.|}e$Ku^r&WA\
#_$?/*P_$@t&gA#[;_$A#^j2#A#_*d}@v^z#8?D?D9Q`s}$5$L|u<3JC/xVz;#s^{?9$M}$x_Y,7uP\
$",p[6789];
int o[]={145,1145,1745,2545,3045,4045,4345,5145,5745,6369},i=0,j=0,l=0;
void e(n,h){
for(j=0;n>0;n-=!(p[j++]^9));
for(;!n&&j[p]^9;j++)write(1,p+p[j][o],o[p[j]+1]-p[j][o]);
for(i=0;i<h[o];i++)write(1,d+7,1);}
int main(){
time_t a=time(&a);
for(;i<8476;j[p]=k>=0?j<*o?k-2:(p[j+1]=k<<4):0,j+=k>=0?1+(j>=*o):0,
l=-k*(k<0),i++);e(21,4);x(hour)e(22,1);x(min)e(23,1);e(25,0);x(sec)e(24,0);
return;}
+136
View File
@@ -0,0 +1,136 @@
Most obfuscated sound:
Pierre-Philippe Coupard
Lineo, Inc.
ATTN : Pierre-Philippe Coupard
390 South 400 West
Lindon, UT 84042
USA
Judges' Comments:
To build:
make coupard
Try:
./coupard > /dev/audio
-or-
./coupard > /dev/sound/dsp
You may need to run this a few times to understand exactly what is
being said. You might even need to look somewhere on your desktop,
your arm or the wall for confirmation.
Selected Author's Comments:
Past years' IOCCC entries do many marvellous things in small packages,
such as console utilities, games, math, languages or even X
applications. But they all have one thing in common (despite being hard
to read obviously) : when they interact with the user, they only
*display* things, i.e. they display either text or drawings.
So, for a change, this program titillates the sense of hearing instead
of sight : this program is a self-contained speech synthesizer that
tells the current time through the computer's sound card - in just under
2 Kb of source code !
In the 2001 IOCCC rules and guidelines documents, there is no mention of
what is or isn't acceptable regarding audio I/Os, but it is mentioned
that hardware-specific and/or non-portable programs are not welcome. So,
in order to do audio and satisfy those requirements, the format required
by /dev/audio has been chosen : /dev/audio is a rather ancient
fixed-format audio interface that is supported by the majority of Unices
that can do sound, as a lowest-denominator sound I/Os interface.
Program usage :
* To listen to what the program says directly, invoke
./coupard > /dev/audio
the program then speaks out something like
"The time is HH hours MM minutes SS seconds"
in military time (24 hours). Of course, you need to have permissions
to write to /dev/audio, have your sound card enabled, the volume up,
the speakers connected ... :-)
* If you want to convert the audio output of the program into another
audio format, you can pipe it to sox for example (sox is the
Swiss army knife of Unix audio tools) : the command
./coupard | sox -c1 -r8000 -tub - -c2 -r44100 -twav test.wav
converts the output of the program into a 44.1KHz stereo .WAV
file and saves it into "test.wav".
The output format of the program is 8KHz, unsigned 8-bit samples.
NOTE : the program's return code is meaningless
Audio quality :
The quality of the sound produced by the program is cross between a
yogurt-pot-and-string telephone and a bad gramophone, i.e. the S/N
ratio is very low and the signal's top frequency is very low as well.
This is because the audio is stored internally at a sampling rate of
4KHz (the Nyquist frequency is only 2KHz) with only 4-bit samples
(adding 24db of quantization noise to an already poor signal).
In short, you might have to listen twice to understand what the
program is saying. 2048 bytes including the sound generation program
doesn't leave much room for audio quality ;-)
Speech generation :
Only 9 phonemes are used to generate the speech. Beside the limited
number of words the program has to generate (66 words), the low sound
quality is actually exploited to take liberties with certain
consonants (for example, "s" and "f" sound very much the same at 4KHz,
so they can be merged into one phoneme). Because the psychoacoustic
context around those phonemes is just sufficient, the words can be
interpreted correctly most of the time despite the fact that they are
pronounced quite wrongly.
Internally, a table is used to generate most of the words, and
composite words such as "thirty-five" are made up by the C code
externally.
Data compression :
Even at 4KHz / 4 bits, the weight of all the phoneme samples and the
word-to-phonemes table put together is over 1600 bytes, which is well
over 2048 bytes when encoded in a C string made of printable
characters. Therefore, a compression method was needed that's both
efficient and with a decompressor that is implementable in the
shortest amount of code possible. GSM compression is very good, but
needs large psychoacoustic tables to regenerate the original
signal. Raw FFT spectral compression is efficient too, but the
decompression code can't be made small enough.
The best compression compromise was found using a simple Huffman
compressor, and encoding the compressed data by blocks of 13 bits in
pairs of printable ASCII characters : the raw data is compressed to
8465 bits, and the resulting C string is therefore about 1300
characters, which leaves just enough room for the decompressor with a
hard-coded Huffman tree, and the code that plays the phonemes in the
right order.
Note on compiler warnings and lint :
The program should build with gcc's -Wall -Werror and -ansi flags. If
the -pedantic flag is used, gcc will complain about the length of the
data string and the sign of its type, and also the fact that main()
returns with no value. The confusion with the sign of the char type
doesn't matter with the data string because it's composed only of
printable characters under 127.
When linting the program with lclint, it complains about a huge list
of things that, if corrected to make lint happy, would probably double
the size of the source code.
+25
View File
@@ -0,0 +1,25 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <signal.h>
#define m(b)a=b;z=*a;while(*++a){y=*a;*a=z;z=y;}
#define h(u)G=u<<3;printf("\e[%uq",l[u])
#define c(n,s)case n:s;continue
char x[]="((((((((((((((((((((((",w[]=
"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";char r[]={92,124,47},l[]={2,3,1
,0};char*T[]={" |"," |","%\\|/%"," %%%",""};char d=1,p=40,o=40,k=0,*a,y,z,g=
-1,G,X,**P=&T[4],f=0;unsigned int s=0;void u(int i){int n;printf(
"\233;%uH\233L%c\233;%uH%c\233;%uH%s\23322;%uH@\23323;%uH \n",*x-*w,r[d],*x+*w
,r[d],X,*P,p+=k,o);if(abs(p-x[21])>=w[21])exit(0);if(g!=G){struct itimerval t=
{0,0,0,0};g+=((g<G)<<1)-1;t.it_interval.tv_usec=t.it_value.tv_usec=72000/((g>>
3)+1);setitimer(0,&t,0);f&&printf("\e[10;%u]",g+24);}f&&putchar(7);s+=(9-w[21]
)*((g>>3)+1);o=p;m(x);m(w);(n=rand())&255||--*w||++*w;if(!(**P&&P++||n&7936)){
while(abs((X=rand()%76)-*x+2)-*w<6);++X;P=T;}(n=rand()&31)<3&&(d=n);!d&&--*x<=
*w&&(++*x,++d)||d==2&&++*x+*w>79&&(--*x,--d);signal(i,u);}void e(){signal(14,
SIG_IGN);printf("\e[0q\ecScore: %u\n",s);system("stty echo -cbreak");}int main
(int C,char**V){atexit(e);(C<2||*V[1]!=113)&&(f=(C=*(int*)getenv("TERM"))==(
int)0x756E696C||C==(int)0x6C696E75);srand(getpid());system("stty -echo cbreak"
);h(0);u(14);for(;;)switch(getchar()){case 113:return 0;case 91:case 98:c(44,k
=-1);case 32:case 110:c(46,k=0);case 93:case 109:c(47,k=1);c(49,h(0));c(50,h(1
));c(51,h(2));c(52,h(3));}}
+40
View File
@@ -0,0 +1,40 @@
Worst Driver:
Chris King
115 Foster Center Road
Foster, RI, 02825
USA
Judge's Remarks:
To build:
make ctk
Try:
./ctk
No matter how careful you are, this guy eventually crashes. Most people
can make at least one successful road trip without crashing.
This is, of course, another of the retro games.
Selected Author's Comments:
This is a game based on an Apple ][ Print Shop Companion easter
egg named 'DRIVER', in which the goal is to drive as fast as
you can down a long twisty highway without running off the
road. Use ',./', '[ ]', or 'bnm' to go left, straight, and
right respectively. Use '1234' to switch gears. 'q' quits. The
faster you go and the thinner the road is, the more points you
get. Most of the obfuscation is in the nonsensical if statements
among other things. It works best on the Linux console: you
get engine sound (!) and the * Lock keyboard lights tell you
what gear you're in (none lit=4th). The 'q' argument (no
leading '-') will silence the sound. It won't work on a terminal
smaller than 80x24, but it works fine with more (try it in an
XTerm with the "Unreadable" font and the window maximized
vertically!).
+162
View File
@@ -0,0 +1,162 @@
#include <stdio.h>
#include <string.h>
#include <time.h>
#define A(x,y) i[a++]=(N){c,c+x,y};
#define B(x,y) j[b++]=(N){c,c+x,y};
#define C(j,k) for (j=0; j<k; j++){
#define D(x) C(_,8)if(!(c+x[_]&136)){ if(p[c+x[_]]*p[c]<0)B(x[_],0)else if(!p[c+x[_]])A(x[_],0)} }
#define J printf(
#define O(v) _=v; while(!(c+_&136)){ x=p[c+_]*p[c]; if(x<0){B(_,0)E; } else if(x>0)E; else A(_,0)_+=v; }
#define X(x) G(x,L)
#define Z(x,y) memcpy(x,y,256);
typedef struct {
F a,b,c;
} N;
F g[]="KSLAU",
p[256],v[]="{ ; } ; { ; ; ; { } ; { ; } { ; } { } ; { ; ; ; { ; } ; } } ; { ; ; { } ; { } } ; { ; ; { { ; ; { } } ; } ; ; { } ; { } } ; { ; ; { { ; { } } ; { ; ; { } ; { { ; ; { } ; ; ; ; { ; } { { ; ; ; { } ; { ; ; ";
F S[]="{}; ",W[256],L[1024];
P q[]={-14,-31,-33,-18,14,31,33,18},r[]={-1,-17,-16,-15,1,17,16,15},_,a,b,c,d,e,t=1,x,y,z;
N i[500],j[500],*k,u;
P f(N *V) {
a=b=0;
C(d,8)
C(e,8)
c=d<<4|e;
if(p[c]==0||p[c]*t<0)continue;
switch(p[c]<0?-p[c]:p[c]){
K 80:
if(56+t*40==(c&112)&&!p[c-32*t])
A(t*-32,0)
if(56+t*-40==(c&112)){
if(!(c-17*t&136)&&p[c-17*t]*t<0){
C(_,5)
B(-17*t,(g[_]^_)*t)}
}
if(!(c-15*t&136)&&p[c-15*t]*t<0){
C(_,5)
B(-15*t,(g[_]^_)*t)}
}
C(_,5)
A(t*-16,(g[_]^_)*t)}
}else{
if(!p[c-16*t])
A(t*-16,0)
if(!(c-(17*t)&136)&&p[c-17*t]*t<0){
B(-17*t,0)
}
if(!(c-(15*t)&136)&&p[c-15*t]*t<0){
B(-15*t,0)
}
}
E;
K 78:D(q)E;
K 81:
K 66:O(17)O(-17)O(15)O(-15)
if(p[c]==66||p[c]==-66)
E;
K 82:O(1)O(-1)O(16)O(-16)E;
K 75:D(r)
} ;
}
}
if ( b > 0 ) {
C(_,b)V[_]=j[_]; }
R b;
} else {
C(_,a)V[_]=i[_]; }
R a;
}
}
F *G(F *n, F *o){
a=b=0;
for(; n[b]; d=0){
do{
d*=4;
d+=W[n[b++]];
} while(++b<8*a+8);
o[a++]=d;
}
o[a]=0;
R o;
}
m(N a){ p[a.b]=a.c?a.c:p[a.a]; p[a.a]=0; }
h(){
J X("{ ; { { { ; ; { ; } { ; } { ; } { ; ; { ; } { ; } { ; } { ; ; { ; } { ; } { ; } { ; ; { ; } { ; } { ; } { ; ; { ; } { ; } { ; } { ; ; { ; } { ; } { ; } { ; ; { ; } { ; } { ; } { ; ; { ; } { ; } { ; } { ; ; { { ; ; "));
c=0; C(c,120)c%8==0&&putchar(56-c/16);
if(p[c]<0){
J X("} { { ; { { { ; ; ; { ; } } } ; { "),-p[c]);
} else if(p[c]>0)
J X("} { { ; { { { ; } } } ; { { ; { { "),p[c]);
else
J"| ");
c%8==7?J X("} { { { ; ; { ; { { { ; ; { ; } { ; } { ; } { ; ; { ; } { ; } { ; } { ; ; { ; } { ; } { ; } { ; ; { ; } { ; } { ; } { ; ; { ; } { ; } { ; } { ; ; { ; } { ; } { ; } { ; ; { ; } { ; } { ; } { ; ; { ; } { ; } { ; } { ; ; { { ; ; ")),c+=8:0;
}
}
s() {
b=0; C(a,256)
if(v[b]==94){
b++; C(c,v[b]-32)p[a++]=v[b+1]-120;}
b+=2; a--;
} else
p[a]=v[b++]-120;
}
}
P w() {
P v=0;
C(_,120)
p[_]&&(p[_]*t>0&&v--,p[_]*t<0&&v++);
}
v+=f(i); v-=b?100:0;t=-t; v-=f(i); v+=b?100:0;t=-t;
R v;
}
P V(P n, P o) {
P s=-I,G,H,Y;
N M[500];
F u[256];
if(!(n+o))R w()+time(NULL)%9-4;
if(!(H=f(M)))R I;
H<5?H==1?n++:(o<6?o++:0):0;
Z(u,p)
C(G,H)
Z(p,u)
m(M[G]);
t=-t;
s=(e=-V(n-1,o))>s?Y=G,e:s;
t=-t;
}
e=Y;
R s;
}
main(P db, F *bd[]){
N o[500];
F T[256];
C(a,256)W[a]=-1; }
C(a,4)W[S[a]]=a; }
G(v,v); s();
while(1){
h();
b=f(o);
scanf("%s",L);
if(strcmp(L,"quit")==0)R 0;
else if(strcmp(L,"g")==0){
Z(T,p)
J G("} } } ; } ; { } } ; { } } } } ; } } { ; { { { ; } } } ; } { { { ; ; ",L), V(db>1?atoi(bd[1]):3,0));
Z(p,T)m(o[e]); t=-t;
}else{
u.a=896-16*L[1];
u.b=896-16*L[3];
u.a+=L[0]-97;
u.b+=L[2]-97;
u.c=L[4]?L[5]:0;
C(a,b)
if(u.a==o[a].a&&u.b==o[a].b&&u.c==o[a].c)E;
}
a==b?J X("} { ; } } ; { } ; { } ; } } } ; } } ; { } } ; { { ; { { } ; } } ; } } ; } ; } } { { ; ; ")):(m(u),t=-t);
}
}
}
+218
View File
@@ -0,0 +1,218 @@
Best AI:
Doug Beardsley
Southern Adventist University
359 Davis Rd. NW
Cleveland, TN 37312
USA
Judge's Remarks:
To build:
make dgbeards
Try:
./dgbeards
This is probably the worst AI we've ever seen. So, then, why did
the entry win? Because it's *trying* to lose.
This is also one of the first chess games we've seen.
Of particular interest is the author's decision that the program should
crash if it loses. I've played chess with a lot of people like that, and
I appreciate the realism.
Selected Author's Comments:
FAQ:
Q: What does this program do?
A: It lets the user play two player or single player games of suicide
chess. Suicide Chess (also known as Losing Chess) is a variant of normal
chess. It is played on the same board and uses the same pieces. Here is
a list of the differences:
1. The object of the game is to get to a position where you have no legal
moves. This is usually accomplished by losing all of your pieces.
Sometimes, the game can end when you still have some pawns on the board,
but they are blocked and cannot move. The general rule is if a player
has no legal moves, the game is over. The winner is the player with fewer
pieces on the board. This is almost always the same player that had no
moves, but not always.
2. In suicide chess, piece captures are compulsory. If a player can
capture an opponent's piece, he is required to do so. If he can capture
more than one of the opponent's pieces or can capture one piece with more
than one of his own pieces, he can choose which capture to play.
3. The king is not significant. There is no concept of check and the king
can be captured.
4. Because of rule 3, pawns are allowed to promote to a king.
5. Castling is not allowed.
Q: How do you use this program?
A: The program is fairly straightforward. When you start the program,
it displays the opening position for a game of suicide chess and waits
for user input. Commands are as follows:
quit - Quits the program
g - Causes the computer to make a move
Moves are represented by the long algebraic notation for the move. For
those not familiar with long algebraic notation, a move consists of a
square to move from followed by a square to move to. Squares are denoted
by a letter and a number. The letter specifies the column or file of the
square and the number specifies the row rank. Files are named from left
to right by the letters a-h. Rows are numbered from bottom to top with
the numbers 1-8. A sample move from the opening position is e2e3. This
means to move a piece from square e2 to e3. From the opening position,
this corresponds to moving the king pawn forward one square. This is
generally to be considered one of the best opening moves in suicide
chess. All moves, captures and otherwise, are represented with this
notation. A special case is pawn promotion moves. They use the same
notation followed by an '=' and a letter representing the piece to
promote to. The letters are R,N,B,Q,K representing rook, knight, bishop,
queen, and king respectively. The letters must be upper case.
You can also specify a command line argument of a single digit to change
the search depth of the program. If no argument is specified, it
defaults to a depth of 3.
Q: Are there any limitations in your program?
A: Yes. The first of the limitations is that you can only play legal
moves according to the rules of suicide chess. En passant captures are
not recognized. They are rarely encountered in suicide chess and when
they do happen, they usually do not change the outcome of the game. As
mentioned above, castling is not allowed either.
It also does not detect the end of the game. It can see sure wins or
losses several moves ahead, but does not announce the end of a game or
the winner. Given the existing code it is easy to do this, but it was
deemed unnecessary fluff.
Q: What is the playing strength of this program?
A: Playing strength is a relative term. Relative to other computer
programs that play suicide chess, it is about the bottom. There is one
freeware program in existence called kenny that this program can beat,
but that is about it.
Suicide chess is a very tactical game. Most humans who do not have any
experience in suicide chess will lose to this program. The Free Internet
Chess Server (http://www.freechess.org) is a free online chess server
that supports suicide chess. This server keeps track of ratings. The
human ratings for suicide chess range from 1000 to about 2400. This
program would probably be rated somewhere around 1700-1900. It is better
than most players, but will get destroyed by experienced human opponents.
This program searches to a fixed depth of 3 ply. Because it does not
search very deep, it performs very poorly in quiet strategic positions.
In such positions, it will often just shuffle pieces around aimlessly
until a tactical exchange presents itself.
A small amount of randomness has been added to make the program a more
interesting opponent. The to avoid a call to srand(), rand() and the
extra code for the required include files, the time() function is used as
the source of random data. It is a slow function, and since it is
executed inside the search loop, there is a significant performance
decrease. To make it faster, replace the time() call with rand() and add
the line srand(time(0)); to the beginning of main(). I used the more
inefficient time() function to illustrate a different (and somewhat
obfuscated?) way of generating random numbers.
Q: Why is this program obfuscated?
A: Here are several reasons:
First, without preprocessing, the code is not easy to read. The
preprocessor is used to compress the code and obfuscate it. The main
obstacle to entering this program is the source code size limit. This is
the reason that the preprocessor was used so liberally. It is one of the
best ways to compress C source code.
Second, when possible, variables in the program were made global. Their
names are not descriptive and they are used for a variety of purposes
throughout the program. Because of this, it is difficult to determine
exactly what the code does even after preprocessing and beautifying the
code.
Third, all function names are a single character and are obviously not
descriptive of they're actual purpose. Again this serves the dual
purpose of compression and obfuscation.
Fourth, most string variables have been encoded. This encoding serves
to obfuscate the program as well as reduce the number of countable
characters and get the program under the size limit of this year's IOCCC.
There are some places where other simple encoding methods are used to
hide the real purpose of strings. These layers of obscurity cannot be
penetrated by just preprocessing and beautifying the program.
Fifth, various small obfuscations have been used in places all over the
program. Short circuit evaluation is used as a substitute for if()
statements in some places. The ternary operator is used. In the
author's opinion, use of the ternary operator is almost always a strong
argument for employee turnover.
Last, if you have succeeded in wading through the previous layers of
obfuscation, you are confronted by the fact that the game that it
implements is an obscure game. Casual inspection of the program might
lead one to believe that it is an implementation of classic chess, but
this is not so.
Q: What about the compiler warnings?
A: When compiled with gcc -Wall, the compiler generated the following
warnings:
suggest parentheses around + or - in operand of &
array subscript has type 'char'
return type defaults to 'int'
control reaches end of non-void function
value computed is not used
The "value computed is not used" warning happens because I use the &&
operator and take advantage of short circuit evaluation instead of using
an if() statement.
The "suggest parentheses..." warnings are given because of expressions
that depend on operator precedence details in the C language.
Eliminating these warnings would reduce obfuscation.
The other warnings are there because it would require more code to
eliminate them and that can't be done given the size limit.
Q: Why does this program crash when it loses?
A: What better way to admit defeat? The author thought this was
appropriate sportsmanship for a program of this genre and can think of
no worse job than trying to find an elusive bug in an intentionally
obfuscated program.
[judge's note: This was followed by a description of the bug, and
the comment:]
(Note, if this program wins, the author thinks it would be good to leave
this information out of the remarks and encourage others to try and
figure it out for themselves)
[should you be too lazy to figure it out yourself, here's the author's
fix. I would have rot13'd it, but the punctuation would have survived.]
begin 644 fix.txt
M5&AI<R!B=6<@8V%N(&)E(&9I>&5D(&EN(&$@;G5M8F5R(&]F('=A>7,L(&)U
M="!T:&5R90II<R!A('=A>2!T:&%T(&%D9',@;VYL>2!O;F4@8GET92!T;R!T
M:&4@<V]U<F-E(&-O9&4N("!);B!T:&4@<W1A=&5M96YT"G,]*&4]+58H;BTQ
M+&\I*3YS/UD]1RQE.G,[(&-H86YG92!T:&4@/B!T;R!A(#X](&%N9"!T:&4@
38G5G('=I;&P@8F4@9V]N92X*"FYG
`
end
+840
View File
@@ -0,0 +1,840 @@
16th International Obfuscated C Code Contest Guidelines, Hints and Comments |
Copyright (c) Leonid A. Broukhis, Simon Cooper, Landon Curt Noll and |
Peter Seebach, 2001. |
All Rights Reserved. Permission for personal, education or non-profit use is
granted provided this this copyright and notice are included in its entirety
and remains unaltered. All other uses must receive prior permission in
writing from the contest judges.
ABOUT THIS FILE:
This file is intended to help people who wish to submit entries to
the International Obfuscated C Code Contest (IOCCC for short).
This is not the IOCCC rules, though it does contain comments about
them. The guidelines should be viewed as hints and suggestions.
Entries that violate the guidelines but remain within the rules are
allowed. Even so, you are safer if you remain within the guidelines.
You should read the current IOCCC rules, prior to submitting entries.
The rules are typically sent out with these guidelines.
Changes from the 2000 rules are denoted by change bars. ---> |
Not every change is marked in this file is marked, but
most are. :-)
WHAT'S NEW IN 2001: |
The contest runs from 01-Oct-2001 00:00 UTC to 01-Dec-2001 23:59 UTC. |
HINTS AND SUGGESTIONS:
You are encouraged to examine the winners of previous contests. See
FOR MORE INFORMATION for details on how to get previous winners.
Keep in mind that rules change from year to year, so some winning entries
may not be valid entries this year. What was unique and novel one year
might be 'old' the next year.
An entry is usually examined in a number of ways. We typically apply
a number of tests to an entry:
* look at the original source
* convert ANSI tri-graphs to ASCII
* C pre-process the source ignoring '#include' lines
* C pre-process the source ignoring '#define' and '#include' lines
* run it through a C beautifier
* examine the algorithm
* compile it (with flags to enable all warnings) |
* execute it
You should consider how your entry looks in each of the above tests.
You should ask yourself if your entry remains obscure after it has been
'cleaned up' by the C pre-processor and a C beautifier.
Your entry need not pass all of the above tests. In certain
cases, a test is not important. Entries that compete for the
'strangest/most creative source layout' need not do as well as
others in terms of their algorithm. On the other hand, given
two such entries, we are more inclined to pick the entry that
does something interesting when you run it.
We try to avoid limiting creativity in our rules. As such, we leave
the contest open for creative rule interpretation. As in real life
programming, interpreting a requirements document or a customer request
is important. For this reason, we often award 'worst abuse of the
rules' to an entry that illustrates this point in an ironic way.
We do realize that there are holes in the rules, and invite entries
to attempt to exploit them. We will award 'worst abuse of the rules'
and then plug the hole next year. Even so, we will attempt to use
the smallest plug needed, if not smaller. :-)
Check out your program and be sure that it works. We sometimes make
the effort to debug an entry that has a slight problem, particularly
in or near the final round. On the other hand, we have seen some
of the best entries fall down because they didn't work.
We tend to look down on a prime number printer, that claims that
16 is a prime number. If you do have a bug, you are better off
documenting it. Noting "this entry sometimes prints the 4th power
of a prime by mistake" would save the above entry. And sometimes,
a strange bug/feature can even help the entry! Of course, a correctly
working entry is best.
People who are considering to just use some complex mathematical
function or state machine to spell out something such as "hello,
world!" may want to try and be more creative.
Ultra-obfuscated programs are in some cases some cases easier to
deobfuscate than subtly-obfuscated programs. Consider using
misleading or subtle tricks layered on top of or under an
appropriate level of obfuscation.
Programs that use VTxxx/ANSI sequences that are NOT limited to a
specific terminal brand and that can also work in a standard xterm
are considered portable.
OUR LIKES AND DISLIKES:
Doing masses of #defines to obscure the source has become 'old'. We
tend to 'see thru' masses of #defines due to our pre-processor tests
that we apply. Simply abusing #defines or -Dfoo=bar won't go as far
as a program that is more well rounded in confusion.
Many ANSI C compilers dislike the following code, and so do we:
#define d define
#d foo <-- don't expect this to turn into #define foo
When declaring local or global variables, you should declare the type:
int this_is_ok;
this_is_not; <-- don't use such implicit type declarations |
We suggest that you compile your entry with an ANSI C compiler. If you
must use non-ANSI C, such as K&R C, you must avoid areas that result in
compile/link errors for ANSI C compilers. For example, using gcc
local function declarations, such as:
int
main() {
void blah() { printf("blah\n"); }
blah();
}
are not allowed even though their existence seems tailor made for
this contest! But for now, since they are not in wide spread use
we cannot accept entries that use them.
If your entry uses functions that have a variable number of
arguments, be careful. Systems implement va_list as a wide variety
of ways. Because of this, a number of operations using va_list are
not portable and must not be used:
* assigning a non-va_list variable to/from a va_list variable
* casting a non-va_list variable into/from a va_list variable
* passing a va_list variable to a function expecting a non-va_list arg
* passing a non-va_list variable to a function expecting a va_list arg
* performing arithmetic on va_list variables
* using va_list as a structure or union
In particular, do not treat va_list variables as if they were a char **'s.
Avoid using <varargs.h>. Use <stdarg.h> instead.
If you use C preprocessor directives (#define, #if, #ifdef, ...),
the leading '#' must be the first non-whitespace character on a line.
While some broken C preprocessors do not allow whitespace before a
'#', most do.
The exit() function returns void. On some broken systems have exit()
return int. Your entry should assume that exit() returns a void.
Small programs are best when they are short, obscure and concise.
While such programs are not as complex as other winners, they do
serve a useful purpose. They are often the only program that people
attempt to completely understand. For this reason, we look for
programs that are compact, and are instructional.
One line programs should be short one line programs, say around 80
bytes long. Getting close to 160 bytes is a bit too long in our opinion.
We tend to dislike programs that:
* are very hardware specific
* are very OS version specific
(index/strchr differences are ok, but socket/streams specific
code is likely not to be)
* dump core or have compiler warnings
(it is ok only if you warn us in the 'remark' header item)
* won't compile or run under a POSIX P1003.1/P1003.2 like systems
* depend on a utility or application not normally found on most
most POSIX P1003.1/P1003.2 like systems
* abuse the build file to get around the size limit
* obfuscate by excessive use of ANSI tri-graphs
* are longer than they need to be
* are similar to previous winners
* are identical to previous losers :-)
* are identical to future losers (Windows XP) :-) |
Unless you are cramped for space, or unless you are entering the
'best one liner' category, we suggest that you format your program
in a more creative way than simply forming excessively long lines.
The build file should not be used to try and get around the size
limit. It is one thing to make use of a several -D's to help out,
but it is quite another to use 200+ bytes of -D's in order to
try and squeeze the source under the size limit. You should feel
free to make use of the build file space, but you are better off
if you show some amount of restraint.
|
You should try to restrict commands used on the build file to |
POSIX-like or common Un*x-like commands. You can also compile |
and use your own programs. If you do, try to build and execute |
from the current directory. This restriction is not a hard and |
absolute one. The intent is to ensure that the building if your |
program is reasonably portable. |
|
Don't forget that the building of your program should be done |
***without human intervention***. So don't do: |
|
cat > prog.c |
cc prog.c -o prog |
|
However, you can do something cute such as making your program |
do something dumb (or cute) when build 'automatically'. However |
when it is run with a human involved, do something more cleaver. |
For example, one could use the build instructions: |
|
cc prog.c -DNONHUMAN -o prog |
echo "See remarks section about alternate ways to compile" |
|
and then include special notes in the ---remarks--- section for |
alternate / human intervention based building. |
We want to get away from source that is simply a compact blob of
characters. To help, we give a break to source that contains
whitespace, and in certain cases ; { or } characters. While the
number of characters excluding whitespace (tab, space, newline),
and excluding any ; { or } followed immediately by either whitespace
or end of file, must be <= 2048, the total size may be less than 4096 |
bytes. This means that one may use "free of charge" up to 2048 |
bytes of whitespace, or ; { or } followed by either whitespace
or end of file.
Please do not use things like gzip to get around the size limit.
Given two versions of the same program, one that is a compact blob
of code, and the other that is formatted more like a typical C
program, we tend to favor the second version. Of course, a third
version of the same program that is formatted in an interesting
and/or obfuscated way, would definitely win over the first two!
We suggest that you avoid trying for the 'smallest self-replicating'
source. The smallest, a zero byte entry, won in 1994.
We do not like writable strings. That is, we don't want stuff like:
char *T = "So many primes, so little time!";
...
T[14] = ';';
Please don't make use of this feature, even if your system allows it.
However, initialized char arrays are OK to write over. This is OK: |
|
char b[] = "Is this Ok"; |
b[9] = 'K'; |
X client entries should be as portable as possible. Entries that
adapt to a wide collection of environments will be favored. Don't
depend on a particular type of display. For example, don't depend
on color or a given size. Don't require backing store.
X client entries should avoid using X related libraries and
software that is not in wide spread use.
We don't like entries that use proprietary M*tif, Xv*ew, or OpenL*ok |
toolkits, since not everyone has them. Use of OpenMotif is permitted |
because it is more widely and freely available. |
You should avoid depending on a particular window manager.
X client entries should not to depend on particular items on
.Xdefaults. If you must do so, be sure to note the required lines
in the ---remark--- section.
While we recognize that UN*X is not a universal operating system, the
contest does have a bias towards such systems. In an effort to expand
the scope of the contest, we phrase our bias in terms of POSIX P1003.1
and P1003.2 standards. This will allow certain non-UN*X OS users to
submit entries. On the other hand, this is a guideline and not a rule.
We will not reject an entry based on some POSIX technicality.
When dealing with OS and application environments, we suggest that you
be reasonable with a nod towards vanilla UN*X-like systems. POSIX will
evolve but not as much as the contest, so avoid stuff like POSIX real
time, security, etc.
We like programs that:
* are as concise and small as they need to be
* do something at least quasi-interesting
* are portable
* are unique or novel in their obfuscation style
* MAKE USE OF A NUMBER OF DIFFERENT TYPES OF OBFUSCATION <== HINT!!
* make us laugh and/or throw up :-) (humor helps!)
Some types of programs can't excel (tm) in some areas. Of course, your
program doesn't have to excel in all areas, but doing well in several
areas really does help.
You are better off explaining what your entry does in the
---remark--- section rather than leaving it obscure for the judges
as we might miss something and/or be too tired to notice.
We freely admit that interesting, creative or humorous comments in
the ---remark--- section help your chances of winning. If you had to
read so many twisted entries, you too would enjoy a good laugh or two.
We think the readers of the contest winners do as well. We do read
the ---remark--- section during the judging process, so it is worth
your while to write a remarkable ---remark--- section.
|
We dislike C code with trailing control-M's (\r or \015) that results |
in compilation failures. Some non-Un*x/non-Linux tools such as |
MS Visual C and MS Visual C++ leave trailing control-M's on lines. |
Users of such tools should strip off such control-M's before submitting |
their entries. In some cases tools have a "Save As" option that will |
prevent such trailing control-M's being added. |
|
We dislike entries that depend on non-portable libcurses features such |
as halfdelay(). One should restrict libcurses to portable features |
found on BSD and SVR4/System V curses. |
|
The rules disallow source that contains unescaped octets with values |
between 128 and 255. You must use \octal or \hex escapes instead: |
|
/* 123456789 123456789 123456789 123456 */ |
char *foo = "This string is 36 octets in length \263"; |
/* This octet requires 4 octets of source ^^^^ */ |
if (strlen(foo) == 36) printf("foo is 36 octets a final NUL\n"); |
Be creative!
ABUSING THE RULES:
Legal abuse of the rules is somewhat encouraged. Legal rule abuse may
involve, but is not limited to, doing things that are technically
allowed by the rules and yet do not fit the spirit of what we
intended to be submitted.
Legal rule abuse is encouraged to help promote creativity. Rule
abuse entries, regardless of if they receive an award, result in
changes to the next year's rules and guidelines.
Legal abuse of the rules is NOT an invitation to violate the
rules. An entry that violates the rules in the opinion of the
judges, WILL be disqualified. RULE ABUSE CARRIES A CERTAIN LEVEL
OF RISK! If you have an entry that might otherwise be interesting,
you might want to submit two versions; one that does not abuse the
rules and one that does.
If you intend to abuse the rules, indicate so in the ---remark---
section. You must try to justify why you consider your rule abuse
to be allowed under the rules. That is, you must plead your case
as to why your entry is valid. Humor and/or creativity help plead
a case.
Abusing the entry format tends to annoy us more than amuse us.
We are often asked why the contest rules and guidelines seem too
strange or contain mistakes, flaws or grammatical errors.
One reason is that we sometimes make genuine mistakes. But in many
cases such problems, flaws or areas of confusion are deliberate.
Changes to rules and guidelines in response to rule abuses, are
done in a minimal fashion. Often we will deliberately leave
behind holes (or introduce new ones) so that future rule abuse may
continue.
At the risk of stating the obvious, this contest is a parity of the
software development process. The rules and guidelines are
only a small part of the overall contest. Even so, one may think
the contest rule and guideline process as a parody of the sometimes
tragic mismatch between what a customer (or marketing) wants and
what engineering delivers.
ENTRY FORMAT:
In order to help us process the many entries, we must request your
assistance by formatting your entries in a certain way. This format,
in addition, allows us to quickly separate information about the
author from the program itself. (see JUDGING PROCESS)
We have provided the program, mkentry, as an example of how to
format entries. You should be aware of the following warning that
is found in mkentry.c:
This program attempts to implement the IOCCC rules. Every
attempt has been made to make sure that this program produces
an entry that conforms to the contest rules. In all cases,
where this program differs from the contest rules, the
contest rules will be used. Be sure to check with the
contest rules before submitting an entry.
|
NOTE: A copy of the mkentry program may be found at: |
|
http://www.ioccc.org/official/mkentry.c |
You are not required to use mkentry. It is convenient, however,
as it attempts to uuencode the needed files, and attempt to check
the entry against the size rules.
If you have any suggestions, comments, fixes or complaints about
the mkentry.c program, please send EMail to the judges. (see below)
The following is a sample entry (the change bars are not part
of the example, don't add them to your entry!)
---entry---
rule: 2001 |
fix: y
title: chlejhse
entry: 0
date: Wed Feb 2 00:47:00 2001 |
host: Un*x v6, pdp11/45
2.9BSD, pdp11/70
---remark---
This is a not-very-obfuscated C program. It is likely not to win a
prize, because it doesn't have what it takes to win and because the
author plans to forget to send it in before the deadline! :-)
---author---
name: Landon Curt Noll
org: IOCCC Judging Group
addr: Toad Hall
PO Box 170608
San Francisco, California
94117-0608
USA
Earth
email: chongo@no_spam.fake.address
nobody@toad.com
url: http://www.isthe.com/chongo/index.html |
anon: y
---author---
name: Leonid A. Broukhis
org: IOCCC Judging Group
addr: Toad Hall
PO Box 170608
San Francisco, California
94117-0608
USA
email: leob@no_spam.fake_org
url: http://www.mailcom.com/main.shtml
anon: n
---author---
name: Simon Cooper |
org: IOCCC Judging Group
addr: Toad Hall
PO Box 170608
San Francisco, California
94117-0608
USA
email: sc@no_spam.fake_edu |
url: http://www.sfik.com |
anon: n
---author---
name: Peter Seebach
org: IOCCC Judging Group
addr: Toad Hall
PO Box 170608
San Francisco, California
94117-0608
USA
email: seebs@no_spam.fake_com
url: none
anon: y
---info---
begin 664 info.file
M5&AI<R!F:6QE(&ES(&EN('1H92!P=6)L:6,@9&]M86EN+@H*:'1T<#HO+W=W
M=RYI;V-C8RYO<F<*"E1H870@=&AA="!I<RP@:7,N"E1H870@=&AA="!I<R!N
M;W0L"B`@("!I<R!N;W0@=&AA="!T:&%T(&YO="!I<RX*5&AA="!I<RP@=&AA
M="!T:&%T(&ES(&YO="P@:7,A"@H)"2TM(&-H;VYG;R`Q.3<T"@I/;F4@;6EG
M:'0@<V%Y.@H*"3(@:7,@=&AE(&=R96%T97-T(&]D9"!P<FEM92!B96-A=7-E
M(&ET(&ES('1H92!L96%S="!E=F5N('!R:6UE+@H)4V\@;6%N>2!P<FEM97,@
M+BXN('-O(&QI='1L92!T:6UE(0H*26X@,3DY,BP@;VYE('!E<G-O;B!T;VQD
M('5S('1H870@=&AE>2!A8W1U86QL>2!D96-O9&5D('1H:7,@9FEL92X@($EN
M"C$Y.3,@86YD(#$Y.30@82!F97<@;6]R92!D:60@=&AE('-A;64N("!);B`Q
M.3DU+"!A(&YU;6)E<B!O9B!P96]P;&4@9G)O;0I%87-T97)N($5U<F]P92!T
M;VQD('5S('1H870@=&AE>2!D96-O9&5D('1H:7,@9FEL92X@(%-E96US('1H
M97)E(&ES(&$*<VUA;&P@=75D96-O9&4@9W)O=7`@:6X@16%S=&5R;B!%=7)O
M<&4A("`Z+2D*"E=H>2!D;VXG="!Y;W4@=&5L;"!U<R!W:'D@>6]U(&1E8V]D
M960@=&AI<R!F:6QE(&)Y('-E;F1I;F<@14UA:6P@=&\Z"@H)<75E<W1I;VYS
M0&EO8V-C+F]R9PH*4&5R:&%P<R!Y;W4@;6EG:'0@<W5G9V5S="!A(&)E='1E
M<B!E>&%M<&QE(&9I;&4@86YD('!R;V=R86T@9F]R('1H:7,*<V%M<&QE(&5N
M=')Y/R`@268@>6]U(&1O('-E;F0@:7,@82!B971T97(@97AA;7!L92!F:6QE
M+"!B92!W87)N960@+BXN"G1H870@:70@8V%N;F]T(&)E(&-O;G-I9&5R960@
M87,@82!C;VYT97-T(&5N=')Y+B`@4V\@>6]U(&UI9VAT(&YO=`IW86YT('1O
M('-E;F0@:6X@>6]U<B!B97-T('=O<FL@+BXN('-A=F4@=&AA="!F;W(@=&AE
M(&-O;G1E<W0N("!/;B!T:&4@"F]T:&5R(&AA;F0@+BXN('EO=2!M:6=H="!W
M86YT('1O('-E;F0@=7,@>6]U<B!M;W-T(&AU;6]R;W5S('=O<FLN("`@.BTI
M"E5U96YC;V1E9"!C<F5D:70@=VEL;"!B92!G:79E;B!I9B!W92!P:6-K('EO
6=7(@97AA;7!L92X*"D9I>GIB:6XA"@``
`
end
---build---
begin 664 build
M9V-C("UA;G-I('!R;V<N8R`M3R`M1%9%4EE?4TE,3%E?1$5&24Y%("UO('!R
#;V<*
`
end
---program---
begin 664 prog.c
M;6%I;B@I"GL*("`@("\J"B`@("`@*B!.;W0@=F5R>2!O8F9U<V-A=&5D(&)U
M="!T:&5N('=H870@9&ED('EO=2!E>'!E8W0@+BXN('1H:7,@:7,@:G5S=`H@
M("`@("H@82!P;&%C96AO;&1E<B!E>&%M<&QE+@H@("`@("HO"B`@("!P<FEN
M=&8H(E-O;65D87D@22!M:6=H="!W<FET92!A(&)E='1E<B!E>&%M<&QE+EQN
M(BD["B`@("!P<FEN=&8H(D]N('-E8V]N9"!T:&]G=6AT("XN+B!N86@A7&XB
M*3L*("`@('!R:6YT9B@B4V5N9"!U<R!A(&=O;V0@97AA;7!L92!B=70@8F4@
M=V%R;F5D+"!A;GD@97AA;7!L92!Y;W5<;B(I.PH@("`@<')I;G1F*")S96YD
M('5S('=I;&P@;F]T(&)E(&-O;G-I9&5R960@87,@86X@96YT<GD@9F]R('1H
M92!C;VYT97-T(5QN(BD["B`@("!P<FEN=&8H(E-O('EO=2!M:6=H="!N;W0@
M=V%N="!T;R!S96YD(&%N(&5X86UP;&4@;V8@>6]U<B!B97-T('=O<FM<;B(I
M.PH@("`@<')I;G1F*"(N+BX@<V%V92!T:&%T(&9O<B!T:&4@8V]N=&5S="X@
M($)U="!A(&=O;V0@:'5M;W)O=7,@<')O9R!M:6=H=%QN(BD["B`@("!P<FEN
M=&8H(F1O("XN+B!A;F0@=V4@=VEL;"!G:79E('EO=2!U=65N8V]D960@8W)E
M9&ET(&EN(')E='5R;BY<;B(I.PH@("`@+RH@14UA:6PZ('%U97-T:6]N<T!I
M;V-C8RYO<F<@*B\*(VEF("%D969I;F5D*%9%4EE?4TE,3%E?1$5&24Y%*0H@
K("`@;6%I;B@I.PHC96YD:68*("`@(&5X:70H,C,R,#D@)2`Q,C<I.PI]"@``
`
end
---end---
Your entry's sections must be the same order as in the above example.
Typically the build file should assume that the source is prog.c
and will compile into prog. If an entry wins, we will rename
its source and binary to avoid filename collision. By tradition,
we use the name of the entry's title, followed by an optional
digit in case of name conflicts.
Please note that the title must match the following regexp:
^[a-zA-Z0-9_=][a-zA-Z0-9_=+-]*$
and must be 1 to 31 chars in length. Titles such as:
foo.c
this_invalid_title_is_too_long
/dev/null
are right out! :-)
Titles can be 31 chars long now, but please try to keep them short.
Why 31? Because at least one of the judges likes Mersenne primes!
It is suggested, but not required, that the title should incorporate
the author(s) username(s).
If the above entry somehow won the 'least likely to win' award,
we would use chlejhse.c and chlejhse. |
If your entry depends on, or requires that your build, source
and/or binary files be a particular name, please say so in the
---remark--- section. If this case applies, it would be be helpful
if you did one of the following:
* Tell us how to change the filename(s) in your entry.
* Have the build file make copies of the files. For example:
cc prog.c -o special_name
or rm -f special_src.c
cp prog.c special_src.c
cc special_src.c -o special_name
or rm -f special_build
tail +4 build > special_build
sh < special_build
* Assume that we will use the entry title. Send us a version of
your build/program files that uses the name convention. You
should uuencode these files in ---info--- sections.
If your entry needs to modify its source, info or binary files,
please say so in the ---remark--- section. You should try to avoid
touching your original build, source and binary files. You should
arrange to make copies of the files you intend to modify. This
will allow people to re-generate your entry from scratch.
Remember that your entry may be built without a build file. We
typically incorporate the build lines into a Makefile. If the
build file must exist, say so in the ---remark--- section.
Typically the ---build--- command will contain a "cc" command.
It is also ok to use a "gcc" command (and gcc args). However keep
in mind that your entry should be compilable by any standard ANSI C
compiler and thus should not depend on a special gcc feature.
If your entry needs special info files, you should uuencode them
into ---info--- sections. In the case of multiple info files,
use multiple ---info--- sections. If no info files are needed,
then skip the ---info--- section.
Info files are intended to be input, or detailed information that
does not fit well into the ---remark--- section. For example, an
entry that implements a compiler might want to provide some sample
programs for the user to compile. An entry might want to include a
lengthy design document, that might not be appropriate for a
'hints' file.
Info files should be used only to supplement your entry. For
example, info files may provide sample input or detailed
information about your entry. Because they are supplemental,
the entry should not require them exist.
In some cases, your info files might be renamed to avoid name
conflicts. If info files should not be renamed for some reason,
say so in the ---remark--- section.
Info files must uudecode into the current directory. If they
absolutely must be renamed, or moved into a sub-directory, say
so in the ---remark--- section.
When submitting multiple entries, be sure that each entry has
a unique entry number from 0 to 7. Your first entry should
have entry number 0.
With the exception of the header, all text outside of the entry
format may be ignored. That is, don't place text outside of the
entry and expect us to see it. (Our decoding tools are not AI
progs!) If you need tell the judges something, put it in the
---remark--- section, or send a EMail to:
questions@ioccc.org (not the address for submitting entries)
|
You must include the words 'ioccc question' in the subject of your |
EMail message when sending EMail to the judges. |
The date should be given with respect to UTC. (Some systems refer
to this as GMT or GMT0) The format of the date should be that as
returned by asctime() in the C locale. An example of such a string is:
Wed Feb 2 00:47:00 2001
This format is similar to the output of the date(1) command. The
string does not include the timezone name before the year. On many
systems, one of the following command will produce a similar string:
date -u "+%a %h %d %T 20%y"
date -u sed -e 's/... \(20[0-9][0-9]\)$/\1/'
sh -c 'TZ=UTC date sed -e "s/... \(20[0-9][0-9]\)$/\1/"'
sh -c 'TZ=GMT date sed -e "s/... \(20[0-9][0-9]\)$/\1/"'
sh -c 'TZ=GMT0 date sed -e "s/... \(20[0-9][0-9]\)$/\1/"'
You are allowed to update/fix/revise your entry. To do so, set
the 'fix' line in the ---entry--- section to 'y' instead of 'n'.
Be sure that the resubmission uses the same title and entry number
as well, as these are used to determine which entry is to be
replaced.
Again, you may want to use the mkentry program may be found at: |
|
http://www.ioccc.org/official/mkentry.c |
|
to format your entry. |
|
JUDGING PROCESS:
Entries are judged by Leonid A. Broukhis, Simon Cooper, Landon Curt Noll
and Peter Seebach.
Entries are unpacked into individual directories. The EMail message
is unpacked into individual files, each containing:
---entry--- section
all ---author--- sections
all ---info--- sections
---build--- section
---program--- section
any other text, including the EMail message headers
Prior to judging, the 'any other text' file is scanned to be sure
it does not contain useful information (or in case the entry was
malformed and did not unpack correctly). Information from the
---author--- sections and the title from the ---entry--- section
are not read until the judging process is complete, and then only
from entries that have won an award.
The above process helps keep us biased for/against any one particular
individual. We are usually kept in the dark as much as you are
until the final awards are given. We like the surprise of finding
out in the end, who won and where they were from.
We attempt to keep all entries anonymous, unless they win an award.
Because the main 'prize' of winning is being announced, we make all
attempts to send non-winners into oblivion. We remove all non-winning
files, and shred all related paper. By tradition, we do not even
reveal the number of entries that we received. (For the curious,
we do indicate the volume of paper consumed when presenting the IOCCC
winners at talks)
After the initial announcement, we attempt to send EMail to the
authors of the winning entries. One reason we do this is to give
the authors a chance to comment on the way we have presented their
entry. They are given the chance to correct mistakes and typos. We
often accept their suggestions/comments about our remarks as well.
This is done prior to posting the winners to the wide world.
Judging consists of a number of elimination rounds. During a round,
the collection of entries are divided into two roughly equal piles;
the pile that advances on to the next round, and the pile that does
not. We also re-examine the entries that were eliminated in the
previous round. Thus, an entry gets at least two readings.
A reading consists of a number of actions:
* reading the ---entry--- section
* reading the uudecoded ---build--- section
* reading the uudecoded ---program--- section
* reading the uudecoded ---info--- section(s), if any
* passing the source thru the C pre-processor
skipping over any #include files
* performing a number of C beautify/cleanup edits on the source
* passing the beautified source thru the C pre-processor
skipping over any #include files
In later rounds, other actions are performed:
* compiling/building the source
* running the program
* performing miscellaneous tests on the source and binary
Until we reduce the stack of entries down to about 25 entries, entries
are judged on an individual basis. An entry is set aside because it
does not, in our opinion, meet the standard established by the round.
When the number of entries thins to about 25 entries, we begin to form
award categories. Entries begin to compete with each other for awards.
An entry often will compete in several categories.
The actual award category list will vary depending on the types of entries
we receive. A typical category list might be:
* best small one line program
* best small program
* strangest/most creative source layout
* most useful obfuscated program
* best game that is obfuscated
* most creatively obfuscated program
* most deceptive C code
* best X client (see OUR LIKES AND DISLIKES)
* best abuse of ANSI C
* worst abuse of the rules
* (anything else so strange that it deserves an award)
We do not limit ourselves to this list. For example, a few entries are so
good/bad that they are declared winners at the start of the final round.
We will invent awards categories for them, if necessary.
In the final round process, we perform the difficult tasks of
reducing the remaining entries (typically about 25) down to 8 or 10
winners. Often we are confident that the entries that make it into
the final round are definitely better than the ones that do not
make it. The selection of the winners out of the final round, is
less clear cut.
Sometimes a final round entry os good enough to win, but is beat out
by a similar, but slightly better entry. For this reason, it is
sometimes worthwhile to re-enter an improved version of an entry
that failed to win in a previous year. This assumes, of course,
that the entry is worth improving in the first place!
More often than not, we select a small entry (usually one line), a
strange/creative layout entry, and an entry that abuses the contest
rules in some way.
In the end, we traditionally pick one entry as 'best'. Sometimes such
an entry simply far exceeds any of the other entries. More often, the
'best' is picked because it does well in a number of categories.
ANNOUNCEMENT OF WINNERS:
In Jan or Feb 2002 the judges will post an initial announcement of who |
won, the name of their award, and a very brief description of the |
winning entry on the IOCCC web site: |
|
http://www.ioccc.org/whowon.html |
|
We will also submit a brief announcement story to /.: |
|
http://www.slashdot.org |
|
that, depending on the willingness of the /. editors, may be posted |
to their site at the same time. |
|
Note that initial announcement will NOT contain source. This is because |
the winning authors are given a chance to review the judges comments, |
and test our Makefile. This review process typically takes a few weeks. |
|
Sometime after the initial announcement, and once the the review by |
the winners has been completed (perhaps Feb or Mar 2002), the winning |
source will be posted to the IOCCC web site: |
|
http://www.ioccc.org/years.html |
|
NOTE: previous winners are available at that URL |
|
We will submit a story announcing the availability of the winners |
to /. at the same time. |
Finally (again perhaps Feb or Mar 2002) the winning entries will be |
posted to the following groups: |
comp.lang.c comp.lang.c.moderated alt.sources
In addition, pointers to these postings are posted to the following
comp.sources.misc comp.windows.x comp.programming
misc.misc comp.std.c alt.folklore.computers
Often, winning entries are published in selected magazines from around
the world. Winners have appeared in books ("The New Hackers Dictionary")
and on T-Shirts.
Last, but not least, winners receive international fame and flames! :-)
FOR MORE INFORMATION:
You may contact the judges by sending EMail to the following address:
questions@ioccc.org (not the address for submitting entries)
You must include the words 'ioccc question' in the subject of your |
EMail message when sending EMail to the judges. |
|
Questions and comments about the contest are welcome. Comments about
confusing rules and guidelines are also welcome.
The rules and the guidelines may (and often do) change from year to
year. You should be sure you have the current rules and guidelines
prior to submitting entries.
Check out the IOCCC Web page:
http://www.ioccc.org
It has rules, guidelines and winners of previous contests (1984 to date).
Leonid A. Broukhis
Simon Cooper
chongo (Landon Curt Noll) /\cc/\
Peter Seebach
+327
View File
@@ -0,0 +1,327 @@
#define D define
#define U undef
#define n #
#undef __FILE__
n U __FILE__
n D f __FILE__
n D N endif
n D p e(prg)
n D e(x) #x
n D q #
n D o E #F
n D E Q(
n D G x,y,z)
n D H E y,z)
n D F ,)
n D g o else
n D d o D
n D u o U
n D w E o F D
#ifdef prg
#ifndef tape
n include p
n ifndef tape
n D tape O
n endif
#endif
n D O Z(O,
n D I Z(I,
q D i tape
n U O
n U I
n D O ,)
n D I ,)
q D v tape
n U O
n U I
#undef tape
n U tape
q U tape
#endif /* tape */
q ifndef P
q D H y ## z
#ifdef prg
d c 0 & 0
d R i W v
d B Initializing...
d L V /* the turing */
d M Y(O)/* state to */
d S(x) T(O,1, start ##x)
#else
d c 0
#endif
q D P P
q include f
q U Q
q D H H
q N
q U f
o ifndef P
E # D H y ## z F
d O 3
d I 3
d x 3
o if c+2
E o F include <stdio.h>
int main() {
return 2+c|!
printf
(
d y "\n"
d z ".."
d j " "
d P "*"
d k " "
o if c
w Y(Z) #Z
"Un"
"define"
"d state "
Y(B) y y
"Tape:"
o elif !c
"Usage:"
d M 0
" prg=myprg.turing "
d L ,
d R ,
"["
"tape="
"\""
"O I O..."
"\""
"]"
g
"Final "
"tape:"
o N
u O
u I
d O "O"
d I "I"
g
d j _
d z ...
d k ~
/*StarBox*/
/*********/
d P *
d y *
E E /,*) F
*
* State: B
/*********/
u O
u I
o N
u x
u a
u c
u B
o ifdef s
d J s
d A l
d B m
d C r
d t K
d a L
d b M
d c R
g
d J S
d A L
d B M
d C R
d T K
d a l
d b m
d c r
o N
y
/*Triangles*/
d V j j j j
d W j j j j
d X(G y j
d Z(G j y
d Y(x) P
y A B C
u X
u Y
u Z
u V
u W
d X(G y x
d Z(G x y
d V z O O
d W O O z
d Y(x) x
y A B C
u X
u Y
u Z
u V
u W
d V k k k k
d W k k k k
d X(G y k
d Z(G k y
d Y(x) P
y A B C
u X
u Y
u Z
u V
u W
y
u j
u k
u z
u P
u y
u O
/*EndOfTriang*/
/* Rain */
o ifndef I /*/*/ /*/*/
/*/*/*/*/*/ /*/*/
E E /*/*/*/*/*/,/) F
d K(G /*/*/ y
o if J(x)
u K
d K(G x
w a X(J(x),A F
u K
d Z(G x
d W O
w b Y(C)
d P C
u Z
o U W
d Z(G z ## y
w c C
u Z
g /* <- exit */
u K
d X(G z ## y
w a A
u X
d X(G x
d V O
w b Y(A)
d P A
u X
u V
d K(G x
w c Z(J(x),C F
u K
o N
u a
u b
o U c
d X(G J(_ ## x)
d V J(_O)
d Z(G J(_ ## x)
d W J(_O)
d Y(x) J(_ ## x)
o ifdef s
u t
d t(G z
d j S(x)
d k T
g
u T
d T(G z
d j s(x)
d k t
o N
u tape
o include p
u tape
d stop_O x
d stop_I x
w a(P) O&I&x
d O 0
d I 0
d x 0
w c a(P)
u O
u I
u x
d left 0
d right 1
w j k(P ## x)
u P
u left
u right
u stop_O
u stop_I
u Y
o U X
u V
u Z
o U W
u A
u B
o U C
u j
u k
w B J (.)
u J
u t
o U T
/*Codeblk*/
o D P P
o include f
E n U Q F
E n D H H F
g
);
}
w P x
o N
o N
o U f
u l
u L
o U m
u M
u r
o U R
u S
u s
o U B
u a
u c
+46
View File
@@ -0,0 +1,46 @@
/* Calculates the greatest common divisor of two numbers in
unary representation. Default tape: gcd(6, 10) = 2. */
#define tape I I I I I I O I I I I I I I I I I
#define start_O O, right, start
#define start_I I, left , st10
/* st1_O may not happen */
#define st1_I O, right, st2
#define st2_O O, right, st11
#define st2_I I, right, st3
#define st3_O O, right, st4
#define st3_I I, right, st3
#define st4_O O, right, st4
#define st4_I I, right, st5
#define st5_O I, left , st6
#define st5_I I, right, st5
/* st6_O may not happen */
#define st6_I O, left , st7
#define st7_O O, right, st13
#define st7_I I, left , st8
#define st8_O O, left , st9
#define st8_I I, left , st8
#define st9_O O, left , st9
#define st9_I I, left , st10
#define st10_O I, right, st1
#define st10_I I, left , st10
#define st11_O O, right, st11
#define st11_I O, right, st12
#define st12_O O, right, st16
#define st12_I I, right, st13
#define st13_O O, right, st14
#define st13_I I, right, st13
#define st14_O O, left , st_next_iteration
#define st14_I O, right, st14
/* The state "st_next_iteration" means the the turing machine
is about to do the next iteration of the Euklid algorithm.
(That is, during that state, there are two numbers on the
tape with the same gcd as the initial numbers.) */
#define st_next_iteration_O O, left , st_next_iteration
#define st_next_iteration_I I, left , st8
#define st16_O O, right, stop
#define st16_I O, right, st16
+363
View File
@@ -0,0 +1,363 @@
Best abuse of the C preprocessor:
Immanuel Herrmann
University of Freiburg, Germany
Rehlingstr. 17
79100 Freiburg
Germany
http://pcpool.mathematik.uni-freiburg.de/~immi/
Judges' Comments:
To build:
Running and building are combined for this entry.
Try:
./herrmann1.sh 'prg=herrmann1.times2'
-or-
./herrmann1.sh 'prg=herrmann1.gcd'
There are some clear hints in the source code as to the
purpose of this program. Perhaps the only way to figure out what is
going on is to look at the differences between the runs of the C
preprocessor! Computer Science students should recognize what is going
on.
Selected Author's Comments:
Many cool things have been done with the preprocessor,
e. g. calculation of prime numbers or the tower of Hanoi. However,
up to now, no one proved that the preprocessor is Turing complete,
and I wondered why. Well, the answer is simply that the
preprocessor is _not_ Turing complete, at least not if the program
is preprocessed only once. This is true even if the program is
allowed to include itself. (The reason being that for a given
program, the preprocessor has only a finite number of states, plus
a stack consisting of the places which the file has been included
from. This is only a push-down automaton.)
Well, this entry _is_ a Turing machine implemented in the
preprocessor; so of course, it has to be preprocessed several
times. Here are the main features:
- Easy to program: Write your own Turing programs in a nice
syntax.
- Easy to debug: (some) errors in the Turing machine program will
be reported nicely. (That's something which is not often seen in
IOCCC programs.)
- Ultra-fast: The resulting C program will print the output in
time O(n), where n is the length of the output. This means for
example that you can solve NP hard problems in polynomial time!
;-)
- And best of all: During the preprocessing, watch the animated
Turing machine running over the tape and doing its work in your
terminal!
How to use it
=============
For the impatient
-----------------
The info files "herrmann1.turing" and "herrmann1.gcd" are sample
programs for the Turing machine. For example, type
./herrmann1.sh 'prg=herrmann1.times2'
and watch the animated Turing machine multiply 8 by two (in
unary representation). Here's a screen shot during compilation:
/*
*
* State: st2.
*
* _ _ _ _ _ * _ _ _ _ _ _ _ _ _ _ _ _ _
* ... O O I I I I I O I I I I I O O ...
* ~ ~ ~ ~ ~ * ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
*
*/
(As on real videos, you'll see a bit of "white noise" at the
beginning and at the end.;-) After compilation has terminated,
type ./prog to see the final result. The output will be
Final tape:
*
..OOIIIIIIIIIIIIIIIIOOOO..
*
(Note that the last frame of the animation is _not_ the final
result.)
In the previous example, the Turing machine started on the default
tape of the program "times2.turing". To provide your own tape, type
(for example)
./build prg=times2.turing tape="O O O I I I O O O"
(The O's and I's are letters, not digits.) You might prefer to
provide only a finite portion of the tape, like I did above. In
this case, the remainder of the tape is filled with O's. ;-)
If you just type
./build
and run the program, you'll get a usage message (and the return
code will be 2).
Note: To get a really nice animation, you'll need a terminal which
is able to scroll fast enough. (xterm is not very good. The
kde terminal "konsole" or the text console under linux are much
better. Simply try some out.)
Writing your own programs
-------------------------
Now, let's assume you want to write a program which adds 1 to a
number in unary representation. (That is, a row of I's is
expected, and one more I is appended to the row.) Let's call it
"plus1.turing". Here's what it could look like:
/* Search beginning of number. */
#define start_O O, right, start
/* Number found. Move one step to the left. */
#define start_I I, left, st2
/* Write a I and stop */
#define st2_O I, left, stop
Some explanations:
- The tape alphabet is always O and I.
- The states can be anything starting with "st". "start" and
"stop" are the start and stop states, respectively.
- to define a state, use two lines: one for each letter on the
tape. You may omit one of the lines if the Turing machine will
never enter the state reading that letter. (In the example, the
line defining st2_I has been left out.)
- The order of the lines is irrelevant.
- You may use c-style comments. (Would you have guessed it?)
Now, the program can be used with
./herrmann1.sh 'prg=plus1.turing' 'tape="I I I"'
But what happens if no tape is provided? Up to now, the Turing
machine would start on an empty tape (that is, a tape filled with
O's). For many programs, this doesn't make much sense (as is
the case for "plus1.turing"). So you might want to provide a
default tape by adding a line like
#define tape O O O O O I I I I
to your program.
Debugging
---------
When writing long programs, the most common errors are to forget
to define a state or to misspell one. Let's assume you forgot the
line
#define start_I I, left, st2
Remove it and type
./herrmann1 'prg=plus1.turing'
The output will be
Undefined state start.
Tape:
*
..OOOOOOOOIIIIOO..
*
and the return code will be 1. As you can see, the Turing machine
moved over the O's, but when it arrived at the I (still in state
start), the error occurred.
Note that other kinds of errors can cause compilation to fail.
If this happens, the build script will write the error message of
gcc into a file called "error" and then exit.
What the build script does
==========================
In principle, the build script simply runs the preprocessor over
and over again, until nothing changes anymore; then, the program
is compiled. After each preprocessing step, the script outputs the
beginning of the program; this is where the animation takes place
(except in the first and last few steps).
However, there's a technical problem to overcome: Some compilers
(including gcc) insert a lot of white space during the
preprocessing. This is bad for two reasons. First, the animated
picture won't look right. And second, after some time, the file
will grow too big for your hard disk. (The amount of white space
grows exponentially.) So after each preprocessing, the first thing
the build script does is remove all the unnecessary white space
using sed.
(gcc would even insert #line directives if I didn't suppress
them with the -P option.)
Some more details
-----------------
- The arguments passed to the build script are passed on to gcc
with a "-D" before. I had a slight technical problem doing this
(especially with the spaces that can appear within the tape
argument). That made the build script a bit longer.
- It would be enough to pass the defines in the first
preprocessing. The program then "remembers" them. However, it
doesn't matter if they are passed in all preprocessings. (This
doesn't sound very impressive, but it has required some extra
lines of code.)
- During the preprocessing, intermediate files "herrmann1-1.c" and
"herrmann1-2.c" are generated.
- Also, a file "error" is generated. This file is removed after
the compilation, except if gcc produced an error; then it contains
the error message. (I can't let gcc output all its messages
directly, because the warnings would clobber the animation. I
could have made the compile script output the error file in case
of an error, but I didn't want to make it yet longer.)
Some technical details / obfuscations
====================================
- The program is compressed. In the first three preprocessing
passes, it uncompresses itself and initializes the
"variables". So if you want to understand how it works, the best
thing is to preprocess it three times and then look at it
again. (However, I wouldn't have wasted three passes if they
weren't needed anyway to initialize the tape in certain
cases. Find out why.)
- The first problem I had to solve when writing this program was
to write a preprocessor program which outputs itself. Of course,
each program which doesn't contain any preprocessor directives
is such a program, but that's not what I needed. In fact, to do
this, the program has to include itself, but even then, it's not
easy.
- The next problem to solve was how to pass results of a
calculation of one preprocessing to the next one. This is done
by outputting #defines with the result. But there's a problem
with this: it is impossible to output a "#define result xxx",
where xxx depends on the previous value of result. Try it if you
don't believe it. And find out what I did instead.
- What's a useful way to store information, especially the content
of the tape? Of course, a "#define tape OOIOOIOIIIIO" contains
the information, but then, how do you access the information?
(For example, you won't be able to write preprocessor code which
replaces the first O by I.) My answer looks very much like the
way a stack would have been implemented in lambda calculus. (The
tape is implemented as two stacks, to be exact.) And still,
there were some technical problems to solve. Look at the program
for more details.
- There are many other interesting things to look at, e.g. the way
to access the information in the user-provided program, the way
a non-defined state is detected, the way the picture is
produced, etc. If you want a real challenge, try to understand
what the line "w j k(P ## x)" does.
- Due to the fact that our alphabet has only 53 ;-) letters, I had
to use many variables more than once.
- I couldn't refrain from doing a little bit of nasty stuff like
#define a 0&0
#if !a
Of course, it is a bit more subtle, and even useful.
- The layout of the source code..., well, let's call it the
"modern art of programming" - a mixture of program-like
indenting and modern art. There are even some comments...
Compatibility
=============
- It works with many versions of gcc. I tested it with versions
2.7.2.1, 2.8.1, 2.95.2, and ecgs-2.91.66. However, an old version
of gcc produced "internal compiler errors" (obviously not my
fault).
- The only warnings I get tell me that I'm undefining __FILE__ and
that preprocessing directives are not recognized within macro
args. My answer to this is "yes, I know this and it's all
right". With "-Wall", I also get some warnings about "/*"
inside comments (Well, _I_ like some well-placed "/*/*/".) as
well as some suggestions where to place some more parentheses
(as if I didn't know the operator precedence).
- Different versions of cc all produced only rubbish. Apparently,
the preprocessors didn't really work. (I don't feel guilty
there, either. Even with very simple programs, they produced
mysterious output.)
- For Mac-Users: It works with the C compiler of Codewarrior (an
old version). This compiler even leaves out all that unnecessary
white space, so that no clean-up is needed. (It would be useful
to write a kind of script which does the equivalent to the build
script, so that one does not have to choose "preprocess" from
the menu over and over again. I leave this as an exercise to the
experienced Mac programmer.)
- In the build script, I passed the -P option to gcc to suppress
the insertion of #line directives. If your compiler doesn't
support this option (and does insert #line directives), you
should change the call to sed to remove them, too: Add
-e "/^#line/ d"
to the sed parameters. Or, if your #line directives look like
# 15 "filename"
add
-e "/^# [0-9]/ d"
instead.
- First, I had "-ansi -pedantic" turned on, but on some systems,
the stdio.h is not compatible to that, so I turned it back off.
- The build script probably needs a bash to run in. So perhaps you
have to add "#!/bin/bash" or something like this at the
beginning.
- On SunOS, I had to remove the "-q" option from diff in the build
script.
+29
View File
@@ -0,0 +1,29 @@
#!/bin/sh
name=herrmann1
# Make sure things are clean to start with...
rm -f ${name} ${name}-1.c ${name}-2.c ${name}-3.c
defs=""
for p in ${1+"$@"}; do
defs="$defs \"-D$p\""
done
cp ${name}.c ${name}-1.c
touch ${name}-3.c
until cmp -s ${name}-1.c ${name}-3.c > /dev/null; do
eval ${CC:-cc} -E ${name}-1.c -o ${name}-2.c -P $defs 2> error || exit
mv -f ${name}-1.c ${name}-3.c
sed -e 's/ */ /g' -e 's/^ //' -e '/^$/ d' -e 's:^/ \*:/*:' \
< ${name}-2.c > ${name}-1.c
head ${name}-1.c
done
eval ${CC:-cc} ${name}-1.c -o ${name} 2> error && rm error
eval ./${name}
# Clean up intermediates...
rm -f ${name}-1.c ${name}-2.c ${name}-3.c
+19
View File
@@ -0,0 +1,19 @@
/* Takes a number in unary representation and
multiplies it by two
*/
/* Default Tape: Multiply 8 by 2 */
#define tape I I I I I I I I
#define start_O O, right, start
#define start_I O, left, st1
#define st1_O I, left, st2
#define st2_I I, left, st2
#define st2_O I, right, st3
#define st3_I I, right, st3
#define st3_O O, right, st4
#define st4_O O, left, stop
#define st4_I O, left, st1
+23
View File
@@ -0,0 +1,23 @@
char*d,A[9876];char*d,A[9876];char*d,A[9876];char*d,A[9876];char*d,A[9876];char
e;b;*ad,a,c; te;b;*ad,a,c; te;*ad,a,c; w,te;*ad,a, w,te;*ad,and, w,te;*ad,
r,T; wri; ;*h; r,T; wri; ;*h; r; wri; ;*h;_, r; wri;*h;_, r; wri;*har;_, r; wri
;on; ;l ;i(V) ;on; ;l ;i(V) ;o ;l ;mai(V) ;o ;mai(n,V) ;main (n,V)
{-!har ; {-!har ; {har =A; {h =A;ad =A;read
(0,&e,o||n -- +(0,&e,o||n -- +(0,&o||n ,o-- +(0,&on ,o-4,- +(0,n ,o-=94,- +(0,n
,l=b=8,!( te-*A,l=b=8,!( te-*A,l=b,!( time-*A,l=b, time)|-*A,l= time(0)|-*A,l=
~l),srand (l),~l),srand (l),~l),and ,!(l),~l),a ,!(A,l),~l) ,!(d=A,l),~l)
,b))&&+((A + te,b))&&+((A + te,b))+((A -A+ te,b))+A -A+ (&te,b+A -A+(* (&te,b+A
)=+ +95>e?(*& c)=+ +95>e?(*& c) +95>e?(*& _*c) +95>(*& _*c) +95>(*&r= _*c) +95>
5,r+e-r +_:2-195,r+e-r +_:2-195+e-r +_:2-1<-95+e-r +_-1<-95+e-r ++?_-1<-95+e-r
|(d==d),!n ?*d||(d==d),!n ?*d||(d==d),!n ?*d||(d==d),!n ?*d||(d==d),!n ?*d||(d=
*( (char**)+V+ *( (char)+V+ *( (c),har)+V+ (c),har)+ (V+ (c),r)+ (V+ ( c),
+0,*d-7 ) -r+8)+0,*d-7 -r+8)+0,*d-c:7 -r+80,*d-c:7 -r+7:80,*d-7 -r+7:80,*d++-7
+7+! r: and%9- +7+! rand%9-85 +7+! rand%95 +7+!! rand%95 +7+ rand()%95 +7+ r
-(r+o):(+w,_+ A-(r+o)+w,_+*( A-(r+o)+w,_+ A-(r=e+o)+w,_+ A-(r+o)+wri,_+ A-(r+o)
+(o)+b)),!write+(o)+b,!wri,(te+(o)+b,!write+(o=_)+b,!write+(o)+b,!((write+(o)+b
-b+*h)(1,A+b,!!-b+*h),A+b,((!!-b+*h),A+b,!!-b+((*h),A+b,!!-b+*h),A-++b,!!-b+*h)
, a >T^l,( o-95, a >T,( o-=+95, a >T,( o-95, a)) >T,( o-95, a >T,(w? o-95, a >T
++ &&r:b<<2+a ++ &&b<<2+a+w ++ &&b<<2+w ++ ) &&b<<2+w ++ &&b<<((2+w ++ &&
!main(n*n,V) , !main(n,V) , !main(+-n,V) ,main(+-n,V) ) ,main(n,V) ) ,main),(n,
l)),w= +T-->o +l)),w= +T>o +l)),w=o+ +T>o +l,w=o+ +T>o;{ +l,w=o+T>o;{ +l,w &=o+
!a;}return _+= !a;}return _+= !a;}return _+= !a;}return _+= !a;}return _+= !a;}
+38
View File
@@ -0,0 +1,38 @@
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpppppppqqqqqqqqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqppppqqqppppqqqqqqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpppqqqqqpppqqqqqqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpppqqqqqpppqqqqqqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqppqqqppqqqqqqqqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpppqqqqqqqqqqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpppqqqqqqqqqqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpppppppqqqqqqqqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpppppppppppppppppqqqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqpppppppppppppppppppppppppppppqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqppoooooooooooooooooooooooooooooooooooppqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqpppooooooooooooonnnnnnnooooooooooooopppqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqppooooooooooooonnnnnnnnooooooooooooooppqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqppoooooooooooonnnooooooooooooooooooooppqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqppoooooooooooonnnooooooooooooooooooooppqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqppoooooooooooonnnooooooooooooooooooooppqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqppoooooooooooonnnnnnnnoooooooooooooppqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqppoooooooooooonnnnnnnooooooooooooppqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqppoooooooooooooooooooooooooooppqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqppoooooooooooooooooooooppqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpppooooooooooooooopppqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpppooooooopppqqqqqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpppppppqqqqqqqqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpppppqqqqqqqqqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpppppqqqqqqqqqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpppppppppqqqqqqqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpppppppppqqqqqqqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpppppqqqqqqqqqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpppppqqqqqqqqqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpppppqqqqqqqqqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpppppqqqqqqqqqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpppppppqqqqqqqqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpppppppppqqqqqqqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqoooooooooooooooooooqqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqoooooooooooooooooooqqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqoooooooooooooooooooqqqqqqqqqqqqqqqqqq
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
+195
View File
@@ -0,0 +1,195 @@
Most eye-crossing:
Immanuel Herrmann
University of Freiburg, Germany
Rehlingstr. 17
79100 Freiburg
Germany
http://pcpool.mathematik.uni-freiburg.de/~immi/
Judges' Comments:
To build:
make herrmann2
Try:
./herrmann2 < herrmann2.ioccc
./herrmann2 < herrmann2.cup
Be careful when staring at the source code - your eyes might cross, but
if you concentrate on your focus you will find illumination!
Selected Author's Comments:
You probably know those "magic eye" 3D pictures - pictures looking
like random noise, but when you look "through" the paper, you
either get a three dimensional picture or a head-ache. With this
program, you can create your own 3D pictures in ascii art. And
yes, the program itself is such a 3D picture.
How to use it
=============
1. Create a file which describes the desired 3D picture. The file
must be a block of lowercase letters the size of the desired
picture. The letters specify the depth of the corresponding pixel:
"a" means close to the paper, "z" means far away. The info files
are examples. Be aware that the size of the picture is restricted
to about 9k.
2. Pipe your picture into the program. The output will be your
3D picture, constructed of random characters (with ascii code between
32 and 126). For example, type
./herrmann2 < herrmann2.ioccc
3. If you want to control the characters used in the output (for
example if your picture is to consist only of digits), pass them
as the first argument. In this case, each time the program needs a
new random character, it will take the next one from the
argument. When it arrives at the end of the argument, it will
start over at the beginning. Example:
./herrmann2 "234 84 045 5 6765 7487 65190 84 656 254 12 43931 818 0 6542\
341 45 567 76967 7244 606 976567 895 81898 095 68678 1843 4650547\
565980691 389 04974" < herrmann2.ioccc
Some hints to get better results
--------------------------------
- Due to the way these 3D pictures work, the left part of the
picture won't look really 3D, so don't put things too much on
the left. The reason is that for each letter in the source file,
a character for the right eye is printed. The 3D effect appears
when the left eye sees the same character more to the left. This
is of course impossible on the left border of the picture.
- Don't use too different depths and don't use the depths very
close to the paper (beginning of the alphabet). This would make
it more difficult to see the picture.
- When passing an argument, don't use a too short one; the
repeating pattern which arises from the repetition of the argument
could interfere with the repeating pattern which creates the 3D
effect.
Extra-Features
==============
- The program is able to handle all common kinds of line breaks:
Unix, Dos and Mac. To get an output with a certain kind of line
breaks, simply use the same kind of line breaks in the input
file.
- As the source code is a 3D picture itself, the easiest way to
get it (if you lost it or if you don't have it already) is to use
the program itself on the right picture and with the right
argument:
./herrmann2 \
'char*d,A[9876];e;b;*ad,a,c; tw,ndr,T; wri; ;*h; _,ar ;on;'\
' ;l ;i(V)man,n {-!har ; =Aadre(0,&e,o||n -- +,o4,=9,l=b=8,'\
'!( te-*Aim)|(0~l),srand (l),,!A,d=,b))&&+((A + te-A(&(*)=+ +95>'\
'e?(*& c_*r=5,r+e-r +_:2-19<-+?|(d==d),!n ?*d| *( (char**)+V+), ('\
' +0,*d-7 ) -r+8)c:7:+++7+! r: and%9- 85! ()-(r+o):(+w,_+ A*(=er'\
'i+(o)+b)),!write,(=_((-b+*h)(1,A+b,!!((((-+, a >T^l,( o-95=+))w?'\
'++ &&r:b<<2+a +w) ((!main(n*n,V) , +-) ),l)),w= +T-->o +o+;{ &!'\
'a;}return _+= ' < herrmann2.ioccc
- If I had submitted the program last year, I would have said that
it has exactly the maximum allowed length: 1536 characters. Now
let's say it's a way of protesting against the inflation in
program length.
- The size of the source 3D picture has been chosen carefully: as
big as possible, but small enough to be viewed without problems
on normal-sized terminals.
Why this program should win
===========================
- The layout is of a completely new kind. And it describes what
the program does more precisely than any comment could.
- I don't think there has ever been an ioccc program with so
severe layout constraints. Once the 3D picture has been fixed,
only a sixth of the characters can be chosen freely! (457 of
1840, to be exact.) In contrast, in palindrome programs, for
example, half of the characters can be chosen freely.
- I did not cheat by using comments or -D options - something
I've seen even some palindrome programs do. In fact, at my first
attempt at writing the program I became convinced that it
isn't possible without cheating. But then I found out that with
comments or defines, it would become trivial, so I had to try
harder...
- If you don't believe the constraints are hard, try to write just
one single line which satisfies them. (To be able to make one
function call, for example, you have to fill an entire line with
stuff doing mostly nothing.)
- Just in case this is not enough: Yes, the code itself is
obfuscated: It's (almost) only one big expression, with deep
nesting of () and ?:, and full of unnecessary operations which
do not really help making it readable. And it contains a lot of
"magic numbers". (My favourite is the "7" in line 15 (each
one). Which is the other digit I could have put there instead,
and what other changes to the program would have been necessary?
Without violating the constraints of course.)
- The fact that the main loop of the program calls "main"
recursively is nothing new. New however is that this program
only needs a logarithmic recursion depth! (Find out how this
works.)
- When still in doubt about how to judge this program, type
./herrmann2 < herrmann2.cup
and let the result inspire you. ;-)
Requirements to the compiler / Compatibility
============================================
- I fear that gcc is the only compiler for which this program
works. Due to the severe restrictions, I was forced to use
declarations of int variables, functions and parameters without
specifying their type. The biggest problem was to put "int
main(int c, char ** v){" into the program. After some time, I
became convinced that this is impossible. Finally, at least I
managed to squeeze "main(c, v){" into the constraints instead.
- Also, a lot of warnings are produced - most of them "data
definition has no type or storage class", but also some
"parameter names (without types) in function declaration" and
"assignment from incompatible pointer type". I wasn't able to
get rid of them.
- At least, it probably works with all sufficiently recent
versions of gcc. I tested it with versions 2.7.2.1, 2.8.1,
2.95.2, and ecgs-2.91.66.
- Of course I couldn't put "#include"-lines at the beginning of
the program. Usually, this is not really necessary with
gcc. However, for this program it would have been, because some
functions appear as function pointers, and as such they are not
generated implicitly. So the build script has to pass "-include
..." to gcc. A problem with this is that the complete path of
the include files has to be provided. In the build script, I
assume that the path is /usr/include, but this can easily be
adapted.
+23
View File
@@ -0,0 +1,23 @@
nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnlllllllllllnnnnnnnnnnnllllllllllllnnnnnnnnnnnnnn
nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnlllllllllllnnnnnnnnnllllllllllllllllnnnnnnnnnnnn
nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnlllllnnnnnnnnnnnllllllnnnnnnllllllnnnnnnnnnnn
nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnlllllnnnnnnnnnnnlllllnnnnnnnnlllllnnnnnnnnnnn
nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnlllllnnnnnnnnnnnlllllnnnnnnnnlllllnnnnnnnnnnn
nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnlllllnnnnnnnnnnnlllllnnnnnnnnlllllnnnnnnnnnnn
nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnlllllnnnnnnnnnnnlllllnnnnnnnnlllllnnnnnnnnnnn
nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnlllllnnnnnnnnnnnllllllnnnnnnllllllnnnnnnnnnnn
nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnlllllllllllnnnnnnnnnllllllllllllllllnnnnnnnnnnnn
nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnlllllllllllnnnnnnnnnnnllllllllllllnnnnnnnnnnnnnn
nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
nnnnnnnnnnnnnnnnnnnnnnnnllllllllllnnnnnnnnnnllllllllllnnnnnnnnnnllllllllllnnnnn
nnnnnnnnnnnnnnnnnnnnnnllllllllllllnnnnnnnnllllllllllllnnnnnnnnllllllllllllnnnnn
nnnnnnnnnnnnnnnnnnnnnllllllnnnnnnnnnnnnnnllllllnnnnnnnnnnnnnnllllllnnnnnnnnnnnn
nnnnnnnnnnnnnnnnnnnnnlllllnnnnnnnnnnnnnnnlllllnnnnnnnnnnnnnnnlllllnnnnnnnnnnnnn
nnnnnnnnnnnnnnnnnnnnnlllllnnnnnnnnnnnnnnnlllllnnnnnnnnnnnnnnnlllllnnnnnnnnnnnnn
nnnnnnnnnnnnnnnnnnnnnlllllnnnnnnnnnnnnnnnlllllnnnnnnnnnnnnnnnlllllnnnnnnnnnnnnn
nnnnnnnnnnnnnnnnnnnnnlllllnnnnnnnnnnnnnnnlllllnnnnnnnnnnnnnnnlllllnnnnnnnnnnnnn
nnnnnnnnnnnnnnnnnnnnnllllllnnnnnnnnnnnnnnllllllnnnnnnnnnnnnnnllllllnnnnnnnnnnnn
nnnnnnnnnnnnnnnnnnnnnnllllllllllllnnnnnnnnllllllllllllnnnnnnnnllllllllllllnnnnn
nnnnnnnnnnnnnnnnnnnnnnnnllllllllllnnnnnnnnnnllllllllllnnnnnnnnnnllllllllllnnnnn
nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
+184
View File
@@ -0,0 +1,184 @@
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#define __ "Y\n : ! ,.?>"
#define D(f) ; } int f(int i) { return
#define E(a,b,c,d,e) b##d,c,e,a
#define e(a,b,c,d) a##b##c##d
#define B *p++ - ' ' || !p++
#define _(k) o(*#k - 64)
#define G(g,l,k,o,e,d,n,c,i,b,a,f,j,m,p) \
a#b#c#d#e#f#g#a#i#j#k#l#m#n#o e,i l##c,m##b; d g j n h(k 30:1); o p f}
G(E(f ( 9) -s
? -s + 'q'
? f( 5 ) -s &&'d' -
s?U( 3 ) ||_(J)
:A ( s- f( 5 ))
:(c= 4 *
4):
g(0)D(
V)c <= 3 *4 + 3&&c && V(X ( i) ) ;
}
int , time ( 0)& , c - 15 || P
(1
):0,
& ( !!d ( 0 )
||(a=! _(S)) ,b= 0 )||
a
?d(a = 0)
? _
(I): w ( j =!W(j=_ (V ))) ,
l(_
(Y+ s ) )
)e
(
main(){;
;;;s , ra,
n, d), && C ( j +R( s-j+t( i- 1) )
)D( W)m[ c* 4| z( j ) ]
&&_( X )E (d ( 0
)&& R( 6)/ 6
? c= 17|_ ( T )
:01,||+
, v =i & 3 ^ 2
,+j & 3&&W ( j)||y ( 10 )D (k) --
j ? k ( O[j]=R(15 ))
: 1 D
( H )o ( 7+! ! i+3 )+
i?
c=i /4 & 63,
a= 1
:0)
D ( f )( p =M ,q ( i),*p+86)
D ( l) * f, B?
B ?B ?B? B ?B ?B
?7 :B?B ?36: 59 * 89 *5 * 2 :B?6587
*77 :9 + 2:B ?B?B?9: 5 : 37 : B ? 5 +5:4:20:
B?B?B?32
:e( 4, 3 , 1 *4 * 59 * 1 , 7):B?
17: 34 : 19 :B ?
8 *2 :B ?
2:26: B?
B?B ?B ?
82 *+ 576: B ?33 :22 :5 * 5:3 *4 :3:B ?B ?B? B ?6 +
+ 17 : B?B?13:6 : 9 *2:B?15 : 7 *2 :
B ?
B ?
27:24: 31 : B?
B? + 29 :,
m [a^ 2 ] =T( 8 * 7) ;j= 3
;
;
Q, ;int
P ( int
i )
{time_t(x ) =+ 0+
time(0) ; j=E( u (i ) : i D(R )e(r ,
a ,n ,d) ()% i+1, ( e( l , o,
caltim , e ) (& x)) ->e( tm_h , o, u , r)
;retur , i?_( W
): _( U) D(Y) *p&& *p<3 * 11 ?
( ++ p ), n j= + 34 +( j< 6
||j>19 ),Y (i)
: *p
D ( F) i == 9 ?1 :
F( (i+ 7)% ( 7 + 3) ) +!O[ i
]D(u) *p &&* p -32? p ++)
D (h ) i ?*++*S=i% ( 38)- 1,
D ( A )! n?i&&!g ( (0 ) ) ||K ( j=4| ! !i ) : N(!i )D(
Q)++j<
(s ) &&Q ( t( i)^i )
D( U )i>= 0 ?U( i- 1 )||~f (i+1 ) == ~ s
&&H (m[c* 4 |z(i)] )
:0;D
( X) + b && b<, for (*S = M ; *
p; ),
gets ( L, + 98 , stdin ) ?
p= L, E (r( 0 ): 0 ,h( i / 38 ) : 0;D( C)!
( m[j]+m [a= i] ) ?m[j[m]= i]=j:0;D (d) !
b+(* O-
c)*
* O; D (z )
-~- ~ -~i +
v
& 3 D(y)( putchar ) ( i)
D ( q ) i& ,!(O[j = i]
|| _ ( O))+a :0;
D (w)O[ j] ==c && o
(( !i ++ ? ! !_ (M
):
0) +15)|| ++ j<9 &&w (
i)D ( r )*p? *p -4?
* p -6 ?
y(*p <9 + 2?__[
* p
]: * p+ 7 +79):o( j+1) : o (26+j),&q ( -!
* p ++ + i )D(x)i? a=x ( ( -- i)), ++ p )
D( t ) i, | C((j=i*
T(i-4 )) +R
(3 ) + 4 )
D(J) !j --E( 0 D ( K )!-!N, || i &,
_( R ) :i* c== (O
[ j ] ) &&n==f (j+ 6 + 5 * 4)?O
[j]= !i * c-_ ( L) :J(i )
D ( N ) j=9, & d(0 )? j= 6 | ! i , J(i )D
( o)(*S = p , ++ S,p = M , r (q (i) ),-- S, p = *S))
( (l (_ (Q )),n =s,i ^5 ) ) ;, E(j ,
sign , v ,ed ( b ) ;;
int c =1 ,O[9])
;int( s
)=
E (n ;char, 1 ,a,6 ,o ())* Z[
E(M [37 * 9 *3 ] ,0,L [ 99] ,3] , * *S=Z ) ;
E (*p=+1 ,char( m)[6 , co , 4 ],ol)
+,
V ( v=*O = k( j= 9 )) ;
return ! c&& - ~ ~ - -! printf
( ( "%d \n") , F (P ( 0) +6) *50 + ! ! b*
( +b - (int)time ( 0 )) )
;, ( b= 60 + time ( 0)+ 60 * 4) ;, n =Y
(u (s =Y (i) ) )
: (exit( 0)
,i)D( g )x ( _(N) ^ 9)? !( a =0) : _ ( P )D (T)! i|,
(2); s=35; Q(3);
s=59; Q(6);
a=1;
)
+122
View File
@@ -0,0 +1,122 @@
Best Of Show:
Jason Orendorff
5 Buchanan St.
Nashua, NH 03060
USA
http://www.jorendorff.com/
Judge's Remarks:
To build:
make jason
Try:
./jason
You are in a maze of twisty little passages, all alike.
The really amazing part of this is tha it's a text adventure, and there's
not a single word in the source that isn't a C keyword or function name,
being used as such.
The interface isn't very tolerant of errors, but you can't really
expect that from something this small.
Of particular interest: Go ahead, run it through the preprocessor. You
*still* won't see the words that are used in the game.
Selected Author's Comments:
TED shroyer came up with the idea that made it possible to hide all
the text. Thanks, TED. You won. :)
$ cc -o prog prog.c
$ ./prog
you are in a maze of twisty little passages
caves lead: left forward back
you see
a lamp
> _
This program is a rather nostalgic little labyrinth game. Start
out by typing "get lamp", then use the direction words "left",
"right", "forward", and "back" to explore the caves. Note that
these words can refer to different passages depending on which way
you're facing. "back" always takes you back the way you came.
Type "quit" to quit.
The maze is randomly generated each time you play. The algorithm
ensures that you start at least 6 hops away from the exit. All
passages are two-way.
(There is a trick, well-known among adventure game fans, to
keeping one's bearings in games like this. Unless you know the
trick, it can be very difficult to find your way around. Try it
out first; I'll give away the secret at the bottom of this
document.)
The goal is to collect 8 treasures (plus the lamp) and escape into
the sunlight - or moonlight, as the case may be. After a few
minutes, the lamp runs out of oil, and things become perilous.
If you manage to escape, you score 50 points for your hide, 50
points per item, and bonus points for speed.
Why I think this program is obfuscated:
* 70% more # symbols than the average entry.
* Where are all the messages? The game is downright chatty for
only having two string literals ("%d \n" and "Y\n : ! ,.?>").
* There is exactly one loop in the program, a for loop, and it is
clearly the product of a deranged mind. Running the
preprocessor only makes it worse.
* Microsoft Visual C++ won't even compile this program, even
though it is plain ANSI C (*innocent look*) and limits itself to
the most standard and portable of the standard library
facilities.
* Most of the whitespace is significant, so attempts to
beautify it can easily lead to segmentation faults.
* Attempts to replace the one-character identifiers with longer,
more meaningful names will likewise cause problems. In fact,
simply changing all the Y's to Z's and vice versa results in
some unexpected side effects.
When all warnings are enabled, some compilers express the desire
to see a few more parentheses. I respectfully submit that there are
plenty of parentheses in the program (370 in all.) Besides, any
more would put me over the size limit. gcc also generates a
warning about some calculations not being used. Having just spent
19 hours staring at this program, sweating over every character, I
swear gcc is wrong.
The program is formatted as a poem, to make it more readable.
I find the plaintive chorus "B? B?" particularly poignant.
Also, smiley faces are formatted flush left. (If you don't find
the game entertaining, see if you can find
the fish scales Q)++j<
the shooting star -~- ~ -~i +
in the source code.)
[GAME STRATEGY SPOILER: The trick, of course, is to drop items in
empty rooms to mark them. That way you usually know if you're in a
room you've seen before. It greatly aids mapping.]
+121
View File
@@ -0,0 +1,121 @@
#include <unistd.h>
#include <curses.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/time.h>
#define o0(M,W) mvprintw(W,M?M-1:M,"%s%s ",M?" ":"",_)
#define O0(M,W) M##M=(M+=W##M)-W##M
#define l1(M,W) M.tv_##W##sec
#define L1(m,M,l,L,o,O) for(L=l;L--;)((char*)(m))[o]=((char*)(M))[O]
#define I1 lL,(struct sockaddr*)&il
#define i1 COLS
#define j LINES
#define L_ ((j%2)?j:j-1)
fd_set I;struct socka\
ddr_in il;struct host\
ent*LI; struct timeval
IL,l;char L[9],_[1<<9]
;void ___(int __
){_[__--]=+0;if(
++__)___(--__);_
[__]='=';}double
o,oo=+0,Oo=+0.2;
long O,OO=0,oO=1
,ii,iI,Ii,Ll,lL,
II=sizeof(il),Il
,ll,LL=0,i=0,li,
lI;int main(int\
iL,char *Li[]){\
initscr();cbreak
();noecho();nonl
();___(lI=i1/4);
_[0]='[';_[lI-1]
=']';L1(&il,&_,\
II,O,+O,+lI);il.
sin_port=htons((
unsigned long)(\
PORT&0xffff));lL
=l_;if(iL=!--iL)
{il. sin_addr .\
s_addr=0;bind(I1
,II);listen(lL,5
);lL=accept(I1,&
II);}else{oO-=2;
LI=gethostbyname
(Li[1]);L1(&(il.
sin_addr),(*LI).
h_addr_list[0],\
LI->h_length,iI,
iI,iI);(*(&il)).
sin_family=(&(*\
LI))->h_addrtype
;connect(I1,II);
}ii=Ii=(o=i1*0.5
)-lI/2;iI=L_-1;O
=li=L_*0.5;while
(_){mvaddch(+OO,
oo,' ');o0(ii,iI
);o0(Ii,Il-=Il);
mvprintw(li-1,Il
,"%d\n\n%d",i,LL
);mvhline(li,+0,
'-',i1);mvaddch(
O,o,'*');move(li
,Il);refresh();\
timeout(+SPEED);
gettimeofday(&IL
,+0);Ll=getch();
timeout(0);while
(getch()!=ERR);\
if(Ll=='q'&&iL)\
write(lL,_+1,1);
if(ii>(ll=0)&&Ll
==','){write(lL,
_,-(--Il));}else
if(Ll=='.'&&ii+\
lI<i1){write(lL,
_+lI,++Il);}else
if(iL||!Il)write
(lL,_+lI-1,4-3);
gettimeofday(&l,
0);II=((II=l1(IL
,)+(l1(l,u)-=l1(
IL,u))-l1(l,)+(\
l1(l,)-=l1(IL,))
)<0)?1+II-l1(l,)
+1e6+(--l1(l,)):
II;usleep((II+=\
l1(l,)*1e6-SPEED
*1e3)<0?-II:+0);
if(Ll=='q'&&!iL)
break;FD_ZERO(&I
);FD_SET(lL,&I);
memset(&*&IL,ll,
sizeof(l));if((\
Ll=select(lL+1,&
I,0,0,&IL)));{if
(read(lL,&L,ll+1
)){if(!*L){ll++;
}else if(*L==ll[
_]){ll--; }else\
if(*(&(*L))==1[_
]){break;}}else{
break;}}O0(o,O);
O0(O,o);if(o<0){
o*=-1;Oo*=-1;}if
(o>i1){o=i1+i1-o
;Oo*=-1;}if(o>=(
Ii+=ll)&&O<1&&oO
<0&&o<Ii+lI){O=2
;oO=~--oO;Oo+=ll
*4e-1;}if(O<0){O
=iI;LL++;}if(o>=
(ii+=Il)&&O>iI-1
&&oO>0&&o<ii+lI){O=iI-
2;oO=~--oO;Oo+=Il*4e-1
;}if(+O>+iI){O-=O;i++;
}}endwin();return(0);}
+195
View File
@@ -0,0 +1,195 @@
Best Curses Game:
Kevin Pulo
School of Information Technologies
Madsen Building F09
University of Sydney, NSW, 2006
Australia
http://www.kev.pulo.com.au/
Judge's Remarks:
To build:
make kev
Try:
./kev
and then in another window,
./kev localhost
Continuing with this year's "retro game" theme, this is another old game;
arguably, one of the oldest. Requires a functioning network, and curses.
The graphics aren't the impressive part; the graphics and network are.
How many games come out at $50 and still require you to wait for a patch
to come out before you can play multiplayer? This one works out of the
box.
Selected Author's Comments:
NETWORK P*NG!
[=================]
Kevin Pulo
kev@pulo.com.au
REQUIREMENTS
------------
* TCP sockets
* curses
* usleep
DESCRIPTION
-----------
This program is a two-player networked version of the eighties
arcade classic, "pong". It uses standard TCP sockets to
communicate over the net, and ncurses for display. It supports
variable terminal sizes (though both players must have the same
terminal size) and game speeds. Each player has a paddle to hit
the ball, and you get points for getting the ball past your
opponent's paddle. It's pretty fun! :)
RUNNING
-------
Run the server first without any command line arguments, ie.
./kev
Then run the client with a single command line argument which is
the name of the machine running the server, eg.
./kev localhost
Make sure that the terminals on both ends are the same size.
Also, the TCP port number specified in the build file mustn't be
blocked by a firewall.
Here's a good quick example to see it in action on your own
machine, assuming you have Xwindows:
xterm -geometry 80x40 -fg green -bg black -fn 9x15bold -e ./kev &
xterm -geometry 80x40 -fg green -bg black -fn 9x15bold -e ./kev localhost&
PLAYING
-------
Your paddle is the one at the bottom of the screen, your opponent
is at the top. To move your paddle left, hold down ',' (ie. '<'
but don't press shift). To move your paddle right, hold down '.'.
To quit, either player may press 'q'.
The current score is shown on the left side of the halfway line.
Your score is the lower number, your opponents score is the upper
number. Your score is the number of times your opponent has
missed the ball.
You can control the speed of the ball by the motion of your paddle
when the ball hits it. If your paddle is still, then the ball
just bounces normally off it. If your paddle is moving in the
same direction as the ball, then the ball's speed in that
direction will increase. If your paddle is moving in the opposite
direction to the ball, then the ball's speed in that direction
will decrease (or if the ball is going slowly enough, it'll turn
around).
You might want to increase your keyboard repeat rate before
playing. On the Linux console try "kbdrate -r 24.0 -d 250"
(kbdrate might be "hidden" from normal users in /sbin, and you
might need to be root anyway), in Xwindows try "xset r rate 250
24" (find out your current rate first with "xset q", so that you
can reset it later).
Look below in the Building section for info on how to speed up or
slow down the game (useful if your increase or decrease the
terminal size).
BUILDING
--------
Just run the Makefile as above. The "SPEED" variable in the Makefile
controls the speed of the game (defaults to 50). This speed is
the delay between frames in milliseconds. Thus a value of 0 will
make the game go as fast as your network can handle, and values
less than 50 are useful for larger terminals or more exciting
games. The program needs bandwidth equal to 1/s bytes per second
(where "s" is the speed value). Any latency on the network will
be added to s - so you should probably subtract any latency from
the value of s you want to have. Given that loopback and fast
Ethernet LANs are both much less than 1ms of latency, you should
only need to worry about this if you plan on playing over a slower
link like a cable modem, DSL, or (God-forbid) dialup.
The TCP port to use for network communications is specified by the
"PORT" variable in the Makefile. If the default of 5455 is
blocked for whatever reason, you can change it to something else.
Of course if you use a port < 1024, you'll need to be root.
OBFUSCATION
-----------
The program's broad structure is fairly straightforward, but
individual tasks are rarely done in a straightforward manner. ;)
Identifier names have mostly been chosen to resemble paddles and
balls, and to generally decrease readability.
The source has been cleverly formatted to resemble one of the
paddles from the game, rotated 90 degrees. ;) (The "source
paddle" has approximately the same aspect ratio as the game at 80
columns wide, which is 1:10.)
Finally, the number of "non-whitespace characters" (as defined by
the rules) in the file is exactly 2048, which I think is rather
unexpectedly cool. :)
BUGS
----
There are 3 warnings when I compile with gcc 2.95.3 (-Wall -ansi
-pedantic) on my Linux system, but all are completely harmless.
I don't like the curses and/or termcaps/terminfos on IRIX and
Solaris (the only two non-Linux systems I have access to).
Despite calling timeout(0), notimeout(win, TRUE), nodelay(win,
TRUE) and/or keypad(win, FALSE), it still seems to force a delay
into calls to getch() - I'm guessing at a termcap/terminfo level.
At any rate, I can't seem to force no delay. This is a shame,
because it basically plays havoc with the input code, particularly
the read-ahead canceller. It still works, but not nearly as well
(keypresses are dodgey and holding down keys doesn't always work),
and so I _much_ prefer and recommend Linux libncurses.
Sometimes when 'q' is pressed in one, the other will crash out
with "Broken pipe".
If the specified port can't be bound or connected to, the program
segfaults.
If your terminal is too wide (we're talking gigantic here - over
500 characters wide) then the program can segfault. It's also
possible to crash the program a player scores over a billion
points (1e9). Maybe you can consider that the goal... ;)
If you run the client and server on different architectures, both
architectures need to have the same character systems (ie. don't
try mixing ASCII and EBCDIC). It is independent of endianness
though.
+1301
View File
File diff suppressed because it is too large. Load diff
+21
View File
@@ -0,0 +1,21 @@
#define n ((e[++a]-42)/9-f[d+1])?
#define o printf("%c",c[" 01./:;|\\"]);
char e[]="**3<HRZcir+3@OXakt;=GOXds*\?HRZcir*7HNZ`i19JS\\p*H[m1:CJSz*>H[`mr25\
\?Hx,P,B2Gs-KTfzRdv1SeyCR-ISeu.<Ev+9+P,z,4PfzIdvO2*HRZcir6GPis=MU*3HRZcir*HZi\
1JS\\epy*>H[m1JSey*DH[m*3<HZiu-@P*3HZi<N]q1JS\\epy:[m1CJSeny06I[m*4\?HRZcir,\
\?*6HRZcir1J]q2K*H[m2K*H[m2@K]qtO@M2DK]q,]q1JS\\epy[m1:JSey+[m*3<HRZcir13Gt,\
=GVs*3<HRZcir1J]qz*HF*AH2;DK]qua0=G2:K]q]q1CJS\\pDVu1:JS*D!+3:BIOSY`egilqtxz\
\177.0249<==>EJMUY`ejov#$59@CJOXYZbfhlnrxy&+.57=@IMR[``bcfmnq!#),@",*f;
int main(int j,char *k[]) {
int a,b,c,d,g,h,i=19;
printf(" ");
for(g=0[f=(char *)calloc(80+(h=atoi(1[k])),1)]=1; g<=h; g++) {
if ((g>30)&&(f[i-2]+f[i-1]!=0)) i++;
for(d=c=0; d<i; d++) {
o f[d]=(e[b=c*9,b+=(c=d[f]),(((a=e[345+b]+b/19*85-33-b/40*12-b/80*4)[e]
-42)/9-f[d+1])?n n n n n n n n 0:a:a:a:a:a:a:a:a:a]-42)%9; }
o if (0[f]-1) printf("\n%6i ",g); else printf("\n "); }
}
+109
View File
@@ -0,0 +1,109 @@
Best primal ASCII graphics:
Nicolas Ollinger
Ecole Normale Superieure de Lyon
LIP, ENS Lyon
46, allée d'Italie
69364 Lyon Cedex 07
France
http://www.ens-lyon.fr/~nollinge/
Judges' Comments:
To build:
make ollinger
Try:
In a large window, say 200 chars wide and 100 high (200x100)
with a tiny font, try:
./ollinger 1000 | cut -c -200
Do get lost in the programs line of thought! :-)
Selected Author's Comments:
What's this?
------------
What do you see? On the left, you will see an enumeration of all successive
primes from 2 to the parameter you gave to the program. On the right part,
you can see the sieve used to find these primes. The big diagonals from
right to left are used to erase composed numbers. When no diagonal crosses
a number, then the left cell take value 1 and the number is prime.
The parallel version of this algorithm works in real time n. This C
sequential version is slower as it works in O(n*log n). But you have some
nice picture instead... the cost is a constant number of operation for each
character printed on the screen.
Why do you wrote it?
--------------------
Let's just quote the FAQ :
Q: Are there types of entries that are submitted so frequently that the
judges get tired of them?
A: Yes, there are types of entries that show up over and over again.
The guidelines say:
We tend to dislike programs that:
are similar to previous winners
We like variety. However too often we see (please look at the winning
examples given to be aware of the level of the competition):
(snip)
generating small primes (below is the list of all
prime related winners)
1985/august
1988/applin
1994/weisberg
1995/makarios
1996/dalbec
2000/bellard
As you can see, just a list of primes (let alone small primes)
does not cut it anymore.
(snip)
entries that use some complex state machine/table to print
something
1988/isaak
1988/phillipps
Unbeaten for 12 years and counting...
I think this is enough motivation for trying to submit a program which uses
some complex state machine/table to generate small primes and print them.
The way it works
----------------
This program simply prints the space-time diagram of some particular
cellular automaton. The automaton is a 9-state automaton by Korec in 1998.
It is an optimization of an old automaton for recognizing primes designed
by Fischer in 1965.
The table of the automaton is encoded into the string e and consists of
345 transitions of the kind f(left,middle,right). This encoding into e
is obfuscated to reduce its size, restrict it to characters 32 to 127 and
guarantee a constant time.
The main loop simply iterates this transition function on each cell.
"The rest is silence" (Hamlet, V.2)
Enjoy!
+58
View File
@@ -0,0 +1,58 @@
#ifdef s
z
r(
){z
k=0,l
=0,n,x
XQueryPointer(i
,XRootWindow (i,j),&m,
&m,&o,&p,&n,&n,( ghj)&n),(o
>=s(g)||s(o
)<=0)&&(k=1),
(p>=h||p<=0)&&
(l=1),(e==1)&&(
c=o,d=p,e=0,1)||(
(k==0&&o-c-(z)(a+y
(a)*.5)!=0)&&(a=o-c
),(l^-1==-1&&p-d-(z)(
b+y(b)*.5)!=0)&&(b=p-d),a/=f,b/=f
,k=0,l=0);(o >=s(g)||o<=0)&&(a=-a),(
p>=h||s(p)<=0) &&(b=-b),c=o,d=p,I(XWarpP
,ointer)(i,None,None,0,0,s
(g),h,(z)(a+y(a)*.5),(int)(
b+y(b)*.5 JJ(float B;int)C,D;
#else/*Egads! something has */
#include<X11/Xlib.h>/*taken a*/
#include<stdio.h>/*huge bite o-*/
#include<stdlib.h>/*ut of the m-*/
#include<time.h>/*ouse pointer!!!*/
#define H(a, b) (((a)&(7<<3*(b)))>>3*(b))
#define G(c,d) ((H(c,d)<<3*(d+1))|((H(c,d+1)<<3*d)|/*
_XSetPointer(display, screen,GREASY|BOUNCY)*/c&~(63<<3*(d))))
#define s(e) (G(G(G(G(G(G(e,(z)0),1),2),1),0),1))
typedef int z;float a=0,b=0,c,d,f=1.03;z e
=s(512),g,h,j;
Display/**/*i;
#define y(X)((X>0)-(X<0))
#define x o,p; Window m;
#define ghj unsigned int*
#define I(aa,bb)aa##bb
#define JJ(X)\
));return 0;}X
z r();int main
(z X,char**Y){
clock_t q=0;(X
==2)&&(f=atof(Y[1])),((i
=XOpenDisplay(0) )==0)&&(exit(1
),1),j=I(Defa, ultScreen)(i),
g=s(I(Display,
Width)(i,j)-1)
,h=I(DisplayH,
eight)(i,j)-1;
for(;;((I(clo,
ck)()-q)*100>(
CLOCKS_PER_SEC
))&&(r(),q=clock()));}
#include __FILE__
#endif
+143
View File
@@ -0,0 +1,143 @@
Best abuse of the user:
Edward Rosten
Oxford University
34 The Chilterns
Gloucester Green
Oxford
OX1 2DF
United Kingdom
http://users.ox.ac.uk/~scat1148
Judges' Comments:
To build:
make rosten
Try:
./rosten 1.03
./rosten 1.00
For some abuse, try:
./rosten 0.99
Friction can be your friend if it does not rub you (or your mouse
cursor) in the wrong way. :-)
Selected Author's Comments:
NAME
rosten - make the mouse act as if it has been greased
SYNOPSIS
rosten [greasiness]
DESCRIPTION
This program is designed primarily to make your X windows interface more
obfuscated. Try doing something mouse driven (such as using a mouse
driven editor on this program) whilst it is running. If you're not sure
what it does, looking at the code should give a fair idea.
It also has a [cat] man page if you want to install it as a `utility'.
OPTIONS
It only takes one optional option: the greasiness factor. This is the
number that the speed is divided by on each iteration. The default is
1.03. A setting of 1 (no friction is fun), as is 0.99.
Being an X program, it recognised the DISPLAY variable.
PORTABILITY
The program is very portable, even to non X architectures. All that is
required is a large desk and some good grease.
COMMENTS
It is really rather surprising that code like this should not only be
portable, but compile with almost no warnings on most of the compilers
tested. It's a kind of shame that none of the compilers do anything
like this:
$make greasymouse
cc greasymouse.c -o greasymouse -lX11
greasymouse.c:30: This macro should have more text and spaces in it
greasymouse.c:32: This is a really stupid way to perform this operation
greasymouse.c:42: This program would look better with a newline here
greasymouse.c:48: That's a really silly thing to do
greasymouse.c:55: So is that
...
greasymouse.c:58: This program is rubbish. I'm not going to link it.
The code is best viewed with tabstops every 8 spaces.
BUGS
The mouse gets stuck completely if you give it an option of less
than 1 and leave it for too long. This is quite annoying if it
didn't leave the terminal if was run from in focus.
It gets very jerky if the processor is being used. There are
better time functions than clock() but I haven't used them.
It deflects slightly when it gets very slow.
It annoys other people if you run it on their display too
often. Maybe I should make future versions print funny jokes to
keep the humor fresh.
It's pretty ropey over a 56K modem.
It's even ropier over a 56K modem and tunneled through 3 ssh links.
WARNINGS
Pages and pages and pages of things, with GCC at any rate.
It suggests loads of ()'s where they're not needed.
It reckons I have not used some of the values I have computed. I
would never do a thing like that: I just haven't used them in
the way it's used to.
The MIPS compiler suggests an == instead of an = in expressions
such as:
&&(a=b)
but I its suggestions would break my program. It also reckons
that r() has no prototype.
Giving the -pedantic option to the MIPS compiler causes it to generate
warnings about its own header files, but not any extra ones with this
program.
With all warnings enabled, the DEC compiler, oddly enough finds some
problems with its own include files, but none with my program.
ERRORS
The DEC compiler of this version:
DEC C V5.6-079 on Digital UNIX V4.0 (Rev. 878)
can't compile the code. It thinks that preprocessor lines can not have
whitespace preceding the #. Moving the preprocessor directives to the
beginning of the line wrecks the layout but makes it compile.
+234
View File
@@ -0,0 +1,234 @@
16th International Obfuscated C Code Contest Rules |
Copyright (c) Leonid A. Broukhis, Simon Cooper, Landon Curt Noll and |
Peter Seebach, 2001. |
All Rights Reserved. Permission for personal, education or non-profit use is
granted provided this this copyright and notice are included in its entirety
and remains unaltered. All other uses must receive prior permission in
writing from the contest judges.
Obfuscate: tr.v. -cated, -cating, -cates. 1. a. To render obscure.
b. To darken. 2. To confuse: his emotions obfuscated his
judgment. [LLat. obfuscare, to darken : ob(intensive) +
Lat. fuscare, to darken < fuscus, dark.] -obfuscation n.
obfuscatory adj.
GOALS OF THE CONTEST:
* To write the most Obscure/Obfuscated C program under the rules below.
* To show the importance of programming style, in an ironic way.
* To stress C compilers with unusual code.
* To illustrate some of the subtleties of the C language.
* To provide a safe forum for poor C code. :-)
The 16th IOCCC contest window is: |
01-Oct-2001 00:00 UTC to 01-Dec-2001 23:59:59 UTC |
NOTE: Some of the changes from the 2000 rules are denoted by change bars. ---> |
RULES:
To help us with the volume of entries, we ask that you follow these rules:
1) Your entry must be a complete program.
2) The uudecoded size of your program source must be <= 4096 bytes in |
length. The number of characters (after uudecoding your program) |
excluding whitespace (tab, space, newline, formfeed, return), and |
excluding any ; { or } immediately followed by whitespace or end |
of file, must be <= 2048.
3) Your entry must be submitted in the following format:
|
NOTE: The change bars are not part of the rules, don't add the |
change bars to your entry! |
---entry---
rule: 2001 |
fix: y or n (n => this is a new entry, y => this replaces an older entry)
title: title of entry (see comments below)
entry: Entry number from 0 to 7 inclusive (your 1st entry should by 0)
date: Date/time of submission in UTC (see comments below)
host: Machine(s) and OS(s) under which your entry was tested
Use tab indented lines if needed
---remark---
Place remarks about this entry in this section. It would be helpful if
you were to indent your remarks with 4 spaces, though it is not a
requirement. Also, if possible, try to avoid going beyond the 79th
column. Blank lines are permitted.
---author---
name: your name
org: School/Company/Organization
addr: postal address
use tab indented lines to continue
don't forget to include the country
email: EMail address from a well known site or registered domain.
If you give several forms, list them on separate tab indented lines.
url: http://your/home/page.html or say none if you don't have one
anon: y or n (y => remain anonymous, n => OK to publish this info)
---info---
If your program needs an info file, place a uuencoded copy of it in
this section. In the case of multiple info files, use multiple info
sections. If your entry does not need a info file, skip this section.
---build---
Place a uuencoded copy of the command(s) used to compile/build your program
in this section. It must uudecode into a file named 'build'. The resulting
file must be 521 bytes or less. |
---program---
Place a uuencoded copy of your program in this section. It must uudecode
into a file named is 'prog.c'. The resulting file must follow rule #2.
---end---
Regarding the above format:
* The title must match the expression:
^[a-zA-Z0-9_=][a-zA-Z0-9_=+-]*$
and must be 1 to 31 characters in length.
It is suggested, but not required, that the title should
incorporate the author(s) username(s).
* The date in the ---entry--- section should be given with respect
to UTC. The format of the date should be as returned by asctime()
using the C locale. (see guidelines for more info)
* You may correct/revise a previously submitted entry by sending
it to the contest email address. Be sure to set 'fix' in the
---entry--- section to 'y'. The corrected entry must use the same
title and entry number as submission that is being corrected. Be
sure that you note the re-submission in the ---remark--- as well.
* With the exception of the header, all text outside of the above
format may be ignored by the judges. If you need to tell the judges
something, put it in the ---remark--- section, or send a separate
EMail message to the judges.
* Information from the ---author--- section will be published unless
'y' was given to the respective author's 'anon' line.
* To credit multiple authors, include an ---author--- section for
each author. Each should start with ---author--- line, and
should be found between the ---entry--- and ---build--- sections.
* The home page URL in the ---author--- section must be fully
qualified or must be the word `none'.
* The entry's remarks should include:
- note if this entry is a re-submission of a previous entry.
- what this program does
- how to run the program (sample args or input)
- special compile or execution instructions, if any
- special filename requirements (see rule 4 and 5)
- information about any ---info--- files
- why you think the program is obfuscated
- any other remarks (humorous or otherwise)
* Do not rot13 your entry's remarks. You may suggest that certain
portions of your remarks be rot13ed if your entry wins an award.
* Info files should be used only to supplement your entry. They
should not be required to exist.
* If your entry does not need an info file, skip the ---info---
section. If your entry needs multiple info files, use multiple
---info--- sections, one per info file. You should describe
each info file in the ---remark--- section.
* Your sections must in the same order as in the above template.
|
* The size limits of the program source apply to the decoded version |
of the ---program--- section. |
4) If your entry is selected as a winner, it will be modified as follows:
'build' is incorporated into a makefile, and 'build' is removed
'prog.c' is renamed to your entry's title, followed by an optional
digit, followed by '.c'
your entry is compiled into a file with the name of your entry's
title, possibly followed by a digit
If your entry requires that a build file exist, state so in your
entry's remark section. The makefile will be arranged to execute a
build shell script containing the 'build' information. The name of
this build shell script will be your entry's title, possibly followed
by a digit, followed by '.sh'.
If needed, your entry's remarks should indicate how your entry must
be changed in order to deal with the new filenames.
5) The build file, the source and the resulting executable should be
treated as read-only files. If your entry needs to modify these files,
it should make and modify a copy of the appropriate file. If this
occurs, state so in your entry's remarks.
6) The uudecoded ---program--- section must be able to be compiled
cleanly by an ANSI C compiler, or if there are any compile errors,
they must be documented in the ---remark--- section.
7) The program must be of original work. All submitted programs are |
are thereby put in the public domain. All explicitly copyrighted |
programs will be rejected. |
8) Entries must be received prior to 01-Dec-2001 23:59:59 UTC. (UTC is |
essentially equivalent to Greenwich Mean Time) EMail your entries to:
entry@ioccc.org
|
You must include the words ``ioccc entry'' in the subject |
of your EMail when sending in your entry! Failure to do so may |
result in the loss of your entry! !
If possible, we request that you hold off on EMailing your entries
until 01-Oct-2001 00:00 UTC. Early entries will be accepted, however. |
We will attempt to EMail a confirmation to the sender of any entry
received after 01-Oct-2001 00:00 UTC and before the close |
of the contest.
9) Each person may submit up to 8 entries per contest year. Each entry
must be sent in a separate EMail letter.
10) Entries requiring human interaction to be built are not allowed.
11) Programs that require special privileges (setuid, setgid, super-user,
special owner or group) are not allowed.
12) Legal abuse of the rules is somewhat encouraged. An entry that, in
the opinion of the judges, violates the rules will be disqualified.
Entries that attempt to abuse the rules must try to justify why
their rule abuse is legal in the ---remark--- section.
|
13) Your source may not contain unescaped octets with the high bit set. |
I.e., your source may not contain octet values between 128 and 255. |
|
14) Any program that fails to compile because of lines with trailing |
control-M's (\r or \015) will be rejected. |
FOR MORE INFORMATION:
The judging will be done by Leonid A. Broukhis, Simon Cooper, Landon |
Curt Noll and Peter Seebach. Please send questions or comments
about the contest, to:
questions@ioccc.org (not the address for submitting entries)
You must include the words ``ioccc question'' in the subject of your |
EMail message when sending EMail to the judges. |
The rules and the guidelines may (and often do) change from year to
year. You should be sure you have the current rules and guidelines
prior to submitting entries. To obtain them, visit the IOCCC web page:
http://www.ioccc.org
It has rules, guidelines and winners of previous contests (1984 to date).
|
NOTE: A copy of the mkentry program may be found at: |
|
http://www.ioccc.org/official/mkentry.c |
+1
View File
@@ -0,0 +1 @@
main(int c,char**v){return!m(v[1],v[2]);}m(char*s,char*t){return*t-42?*s?63==*t|*s==*t&&m(s+1,t+1):!*t:m(s,t+1)||*s&&m(s+1,t);}
+73
View File
@@ -0,0 +1,73 @@
Best one-liner:
Jens Schweikhardt
Marconi Communications
Schlartaeckerweg 3
D-71384 Weinstadt
Germany
http://www.schweikhardt.net/
Judges' Comments:
To build:
make schweikh
Try:
./schweikh foo 'f??'; echo $?
./schweikh 'best short program' '??st*o**p?*'; echo $?
./schweikh bar 'f??'; echo $?
Do you get the pattern here?
Selected Author's Comments:
This one-liner program is a glob pattern matcher. It understands
the glob characters `*' meaning `zero or more characters' and
`?' meaning exactly one character, just like your unix shell.
Run it with two args, the string and the glob pattern. The exit
status is 0 (shell true) when the pattern matches, 1 otherwise.
The glob pattern must match the whole string, so you may want to
use * at the beginning and end of the pattern if you are looking
for something in the middle.
You can use it for your shell scripting needs similar to a silent grep
(and without stdout redirected to /dev/null):
if prog "${VARIABLE}" '<glob>'; then
echo VARIABLE matches
else
echo no match
fi
Bugs: there is no way to escape the meta characters. Dammit Jim, I'm a
one-liner, not a regexp lib.
All obfuscation is obviously in the recursive m() function, an 86
character glob pattern evaluator, returning nonzero for a match:
* just a single complex return expression.
* nested ternary operator ?: to save on if/else verbosity.
* short circuiting && and || to save even more on if/else verbosity.
* Subtraction instead of an equality operator in "*t - 42".
* ASCII codes for '*' and '?'.
* careful use of blanks even though this year's rules have extended
that resource limit.
* the source is a complete preprocessed C program. Because it communicates
with the world out there by means of argv and the exit status, there
is no need for stdio bloat. An asm guru could surely squeeze this
program in less than a screenful.
* indent(1) is probably not too helpful.
The recursion wonderfully and magically takes care of iteration and
backtracking. I could tell you how it works but then I would have to
kill^Wrequest an NDA from you :-) Run it under a debugger with several
inputs, it will be quite helpful and instructive. Handling of '?' is
straightforward; for '*' start out with '*foo' and 'foo*' against 'foo'.
How does it deal with sequences of adjacent `*'? How could this be
improved? If all else fails, recode the ?: operators with if/else and
try again. For extra credit implement character classes like [a-z].
+37
View File
@@ -0,0 +1,37 @@
main(i)??<char c??(81??)??(81??);for(i=0;gets(*(c+i)); i++);A(i,c);J(i-1,c);??>
/* { /KC 0000 K } */
S(c,r,i)char*c; ??<printf("|");for(;*(c+i); i++)putchar(T(*(c+i),r));U(c,i);??>
char* B,*r; X(c,k)??<return isupper(c)?0:V(*(r+k),B); ??>
J(i,c,j)char*c; ??<for(j=t(i,0) ; j+j<i; j++)L(c,j,i-j); M(i,c); ??>
U(c,i)char*c; ??<while(i++<80)printf(" "); puts("|"); ??>
A(i ,c,j ,k) char *c; ??< for(j= -1; ++j<i; )for (k =j; k<i; )D(c ,j, k++); ??>
R(c,r) char *c; ??< printf( "/%-80s|??/n" ,c); for (; r< 13; r++)S (c,r,0); ??>
t(a,b)??<return a;??>
M(i,c)char c??(81??)??(81??);??<i++;while(i--)t(1,0)?puts(*(c+i)):P(*(c+i));??>
char*d= "yyzzyzz zz z0y000 zz 00yzz00y00yzz Brian Westley zyy00yy0yy 0" ; ; ;
#define t(a,b) t(b,a)
char* K;Y (c ,r) ??< int i=V ( tolower (c) ,K); return(i <0)?1 :Z(c ,r, i); ??>
char*m= "7831734578 9547693564569528334164263z284106579 52626423135477"; ; ; ;
P(c)char*c; ??<Q(1,0); R(c,1 ); Q(0,0); ??>
char* d,*m,*B; Z(c,i,k)??<return W(i, V(*(d+k), B),V(*( m+k),B) ,X(c, k)); ??>
char*K= "gh$j|lm'pq&rv<x>z#);@_winky,.%/+*!=3-284106579 (:obfuscated??/?" ; ;
L(c,i,j)char c??(81??)??(81??);??<G(* (c+i),*(c+j));??>
char*r= "008y8yy8yyyyz8z8z88888z0yyz888 8888 88y00zz00z0088";
D(c,i,j) char c??(81??)??(81??);??<E(*(c+i),*(c+j));??>
E(r,s)char*r,*s; ??< if(t( 0,1)&& F(r,s)<0)G(r,s); ??>
H()??<static i=0; if (!i) ??< time(&i); srand(i); ??> return rand()-rand(); ??>
F(r,s)char*r,*s; ??<return t(0,1)?H():strcmp(r,s); ??>
T(c,r) ??< return Y(c, r)?'??(' :' '; ??>
G(r,s)char*r,*s; ??<char t??( 81??); strcpy(t,r); strcpy(r,s); strcpy(s,t); ??>
W(r,a,b,c)??<return r==a||r==b||r==c; ??>
Q(t,i)??< printf(t?" ":"|"); for(; i<80; i++) printf("_"); puts(t?"_":"|"); ??>
char*B=" yz0123456789";
V(c,k,i) char*k; ??<for (i=0; *(k+i) &&*(k+i)!=c; i++); return *(k+i)?i:-1; ??>
+155
View File
@@ -0,0 +1,155 @@
Best position-independent code:
Brian Westley
Firesign Theatre webmaster
1906 James Ave
St. Paul, MN 55105
USA
http://www.firesigntheatre.com
Judges' Comments:
To build:
make westley
Try:
./westley < westley.c > westley2.c
cc westley2.c -ansi -o westley2
echo 'Bozos, please deflate shoes before entering the bus!'| ./westley2
sort -b < westley2.c > westley3.c
cc westley3.c -ansi -o westley3
./westley3 < westley.c | diff - westley.c
./westley3 < westley.c | diff - westley2.c
./westley3 < westley.c | diff - westley3.c
Try copying the source to a new file and changing around the
order of the lines. Does it produce the exact same output?
By changing the order of the source, figure out in how many different
ways this program can transform input to output.
NOTE: The entry has been modified for portability reasons. The
original source may be found in the westley.orig.c file.
This assortment obfuscated lines takes position-independant code
to a new level! :-)
Selected Author's Comments:
Punch cards, or Hollerith cards, were becoming obsolete just
as C was becoming more popular*; this is rather unfortunate,
because C has an advantage over many other languages when it
comes to punch cards - C programs can be written to be "drop
proof".
Consider the following C program:
main(){a();b();c();}
a(){printf("A");}
b(){printf("B");}
c(){printf("C");}
This program will compile and run no matter what order the
lines are in. If you punch it on cards (one line of code per
card, naturally) and drop them, you don't need to put them in
any particular order**; it will always produce "ABC" as output.
You can also use global variables:
char *greet = "Hello, world!";
char *greet; main(){puts(greet);}
It would be trivial to write an entire C program that is
"drop proof" using the above techniques; surprisingly, it's
possible to write a program that will always compile but
behave differently depending on the line order:
test(a,b){return a;}
#define test(a,b) test(b,a)
main(){if (test(0,1)) printf("T"); else printf("F");}
This program will print out "T" if the #define statement
falls between the declaration of test() and its use in
main(), otherwise it will print out "F". Furthermore,
you can use the same call to test() repeatedly in
different lines to return different values:
#define test(x,y) test(y,x)
main(){int i=0;a(&i);b(&i);c(&i);d(&i);printf("%d\n",i);}
a(i)int*i;{if (test(0,1)) *i += 1;}
b(i)int*i;{if (test(0,1)) *i += 2;}
c(i)int*i;{if (test(0,1)) *i += 4;}
d(i)int*i;{if (test(0,1)) *i += 8;}
test(x,y){return x;}
If you enter the above program on punch cards, throw them
up in the air, gather them up, and run it, you will get
a number from 0 to 15 printed out. Now *that's* a random
number generator...
Of course, there are drawbacks to C programming on punch
cards; an 80-character line limit can be restricting, and
(to be maximally portable) you need to use trigraphs for
the characters "^[]{}\" (these aren't found on every
keypunch, and have various encodings).
My C program entry does the following:
1) reads in lines
2) rearranges the lines, or not
2a) if it rearranges the lines, they are sorted or scrambled
3) reverses the order of the lines, or not
4) prints out the lines as either text or EBCDIC punch cards.
The code, as written, scrambles the input and prints it out
as normal text, so you can simulate 'dropping' the cards.
You can repeatedly scramble the code to get all 12 variants
(but the scrambling isn't very random; it's just a bubble
sort with a random number, so some variants are more common
than others). You can also just swap the arguments in the
calls to t() in all combinations to get all the variations.
If you sort the lines, you will get the version that just
prints out the input as punch cards (you will need to display
at least 82 columns of text, or clip the last few chars by
piping it through "sed s/...$//"). If you use this on the
original code, you will see that it spells out "HOLLERITH"
when punched on cards (you can see the tall, thin letters
spelling out "HOLLERITH" if you turn the C code sideways).
You will also see why "/KC 0000 K" is a "Hollerith emoticon".
Unrecognized characters are punched as a lace column.
(You can see an ASCII simulation of the code as punch cards
by looking at card.gif)
For a nice test pattern, try
&-0123456789ABCDEFGHIJKLMNOPQR/STUVWXYZ:#@'=".<(+|!$*);,%_>?abcmnoxyz^[]{}\
If you want to analyze the program, sorting the lines while
ignoring leading blanks works best (sort -b). This will
produce the version that just reverses the line order, and
the routines in the code are in a sensible order.
This program should work on EBCDIC computers. It assumes
that the time_t ptr param to time() will work with an int
ptr, and that "passing through" a char[][] array as a simple
char* is ok. Your compiler MUST understand trigraphs, or it
will miss the trigraph backslash before the double quote in
the K string and complain about a malformed string; for GNU
C, use -ansi or -trigraphs. Entering a line of more than 80
characters, or more than 81 lines, will jam the card reader.
I've used the a[b] ==> *(a+b) trick, because this is
actually shorter than the trigraph version of a??(b??).
With 28 lines of code (not counting the blank lines or the
comment), there are technically 28! different programs, or
304,888,344,611,713,860,501,504,000,000 different versions,
all legal C.
*except in Florida voting machines
**all cards must be face down, nine-edge first, of course.
+37
View File
@@ -0,0 +1,37 @@
main(i)??<char c??(81??)??(81??);for(i=0;gets(*(c+i)); i++);A(i,c);J(i-1,c);??>
/* { /KC 0000 K } */
S(c,r,i)char*c; ??<printf("|");for(;*(c+i); i++)putchar(T(*(c+i),r));U(c,i);??>
char* B,*r; X(c,k)??<return isupper(c)?0:V(*(r+k),B); ??>
J(i,c,j)char*c; ??<for(j=t(i,0) ; j+j<i; j++)L(c,j,i-j); M(i,c); ??>
U(c,i)char*c; ??<while(i++<80)printf(" "); puts("|"); ??>
A(i ,c,j ,k) char *c; ??< for(j= -1; ++j<i; )for (k =j; k<i; )D(c ,j, k++); ??>
R(c,r) char *c; ??< printf( "/%-80s|??/n" ,c); for (; r< 13; r++)S (c,r,0); ??>
t(a,b)??<return a;??>
M(i,c)char c??(81??)??(81??);??<i++;while(i--)t(1,0)?puts(*(c+i)):P(*(c+i));??>
char*d= "yyzzyzz zz z0y000 zz 00yzz00y00yzz Brian Westley zyy00yy0yy 0" ; ; ;
#define t(a,b) t(b,a)
char* K;Y (c ,r) ??< int i=V ( tolower (c) ,K); return(i <0)?1 :Z(c ,r, i); ??>
char*m= "7831734578 9547693564569528334164263z284106579 52626423135477"; ; ; ;
P(c)char*c; ??<Q(1,0); R(c,1 ); Q(0,0); ??>
char* d,*m,*B; Z(c,i,k)??<return W(i, V(*(d+k), B),V(*( m+k),B) ,X(c, k)); ??>
char*K= "gh$j|lm'pq&rv<x>z#);@_winky,.%/+*!=3-284106579 (:obfuscated??/"?" ; ;
L(c,i,j)char c??(81??)??(81??);??<G(* (c+i),*(c+j));??>
char*r= "008y8yy8yyyyz8z8z88888z0yyz888 8888 88y00zz00z0088";
D(c,i,j) char c??(81??)??(81??);??<E(*(c+i),*(c+j));??>
E(r,s)char*r,*s; ??< if(t( 0,1)&& F(r,s)<0)G(r,s); ??>
H()??<static i=0; if (!i) ??< time(&i); srand(i); ??> return rand()-rand(); ??>
F(r,s)char*r,*s; ??<return t(0,1)?H():strcmp(r,s); ??>
T(c,r) ??< return Y(c, r)?'??(' :' '; ??>
G(r,s)char*r,*s; ??<char t??( 81??); strcpy(t,r); strcpy(r,s); strcpy(s,t); ??>
W(r,a,b,c)??<return r==a||r==b||r==c; ??>
Q(t,i)??< printf(t?" ":"|"); for(; i<80; i++) printf("_"); puts(t?"_":"|"); ??>
char*B=" yz0123456789";
V(c,k,i) char*k; ??<for (i=0; *(k+i) &&*(k+i)!=c; i++); return *(k+i)?i:-1; ??>
+73
View File
@@ -0,0 +1,73 @@
#include <X11/Xlib.h>
#include <unistd.h>
typedef long O; typedef struct { O b,f,u,s,c,a,t,e,d; } C;
Display *d; Window w; GC g; XEvent e;
char Q[] = "Level %d Score %d", m[222];
#define N(r) (random()%(r))
#define U I[n++]=L[n]=l; n%=222
#define K c=-l.u; l=I[i]; l.t=0; c+=l.u
#define E l.e--&&!--L[l.e].d&&(L[l.e].t=3)
#define M(a,e,i,o) a[0]=e,(a[1]=i)&&XFillPolygon(d,w,g,(void*)a,o,1,1)
#define F return
#define R while(
#define Y if(l.t
O p ,B,
D,A=6,Z ,S=0,v=
0,n=0,W=400 ,H=300,a[7]
={ 33,99, 165, 231,297,363} ;
XGCValues G={ 6,0 ,~0L,0,1} ; short
T[]={ 0,300,-20,0,4 ,-20,4,10,4,-5,4,5,
4,-20,4,20,4,-5,4,5,4, -10,4,20},b[]={ 0,0,4,
0,-4,4,-4,-4,4,-4,4,4} ; C L[222],I[222];dC(O x){
M(T,a[x],H,12); } Ne(C l,O s) { l.f=l.a=1; l.b=l.u=s;
l.t=16; l.e=0; U; } nL(O t,O a,O b,O x,O y,O s,O p){ C l;
l.d=0; l.f=s; l.t=t; y-=l.c=b; l.e=t==2?x:p; x-=l.s=a;s=(x|1)
%2*x; t=(y|1)%2*y; l.u=(a=s>t?s: t)>>9;l.a=(x<<9)/a;l.b=(y<<9)/a;
U; } di(C I){ O p,q,r,s,i=222;C l; B=D=0; R i--){ l=L[i]; Y>7){ p=I.s
-l.s>>9; q=I.c-l.c>>9; r=l.t==8?l.b: l.a; s=p*p+q*q; if(s<r*r||I.t==2&&s<
26) F S+=10; s=(20<<9)/(s|1); B+=p*s; D+=q*s; }} F 0; } hi(O x,O d){ O i=A;
R i--&&(x<a[i]-d||x>a[i]+d)); F i; } dL(){ O c,r=0, i=222,h; C l; R i--){ l=L[i];
Y){ r++;c=l.f; Y==3){c=l.u; l.t=0; E; }R c--){-- l.u;h=l.c>>9; Y>7){XDrawArc(d,w,g,
(l.s>>9)-++l.a,h-l.a,l.a*2,l.a*2,0 ,90<<8); if(!l.u){ I[i].t-=8; l=I[i]; } } else Y==2)M
(b,l.s>>9,h,6); else XDrawPoint(d ,w,g,(l.s+=l.a)>>9, h=(l.c+=l.b)>>9); Y==4&&!l.u){ Ne
(l,20); K; } Y&&l.t<3&&(di(l)||h> H)){ if(h>H&&(c=hi( l.s>>9,25))>=0){ dC(c); a[c]=a[--
A]; }Ne(l,30); Y==1){ E;K; } else c=l.t=0;} Y==1&&h<H -75&&!N(p*77)){ do{ nL(1,l.s,l.c,
N(W<<9),H<<9,1,i+
1); I[i].d++;
}R N(3)
); K;
l.u=c; c=0; } Y
==2){ l.s+=l.a+B;
l.a= (l.e-l.s)/((H+
20-h)|1); l.c+=l.b+D;
M(b,l.s>>9,l.c>>9,6); }
} L[i]=l; } } F r; } J(){
R A) { XFlush(d); v&&sleep(
3); Z=++v*10; p=50-v; v%2&&hi
((a[A]=N(W-50)+25),50)<0 &&A++;
XClearWindow (d,w); for(B=0; B<A;
dC(B++)); R Z|dL()){ Z&&!N(p)&&(Z--
,nL(1+!N(p),N(W<<9), 0,N(W<<9),H<<9,1
,0)); usleep(p*200); XCheckMaskEvent(d,
4,&e)&&A&&--S&&nL(4,a[N(A)]<<9,H-10<<9,e.
xbutton.x<<9,e.xbutton.y<<9,5,0);}S+=A*100;
B=sprintf(m,Q,v,S); XDrawString(d,w
,g,W/3,H/2,m,B); } }
main ()
{
O i=2;
d=XOpenDisplay(0);
w=RootWindow(d,0);
R i--) XMapWindow(d,w=XCreateSimpleWindow(d,w,0,0,W,H,0,0,0));
XSelectInput(d,w,4|1<<15);
XMaskEvent(d,1<<15,&e);
g=XCreateGC(d,w,829,&G);
srandom(time(0));
J();
puts(m);
}
+58
View File
@@ -0,0 +1,58 @@
Best Graphic Game:
John Williams
941 E 25 S
Lindon UT 84042
USA
Judge's Remarks:
To build:
make williams
Try:
./williams
The only way to win is not to play. No, really; you can't actually win.
:)
The formatting really wants a wide screen; if you can't read it that way,
it's the standard "three triangles around a circular" logo for nukes.
This is a pretty straightforward game.
Selected Author's Comments:
What this program does:
It plays Missile Command, complete with MIRVs, smart bombs,
extra cities, and scoring.
Command line arguments and input files are ignored.
To play, just point and click where you want your ABMs to explode.
The score is 10 points for each missile which is destroyed before
it reaches the ground, -1 point for each ABM used, and 100 bonus
points for each city left at the end of a level.
The game ends when you lose all your cities, although you will have
to wait until the level finishes raining down to see your final score.
The main obfuscation technique is the need to compress the code to fit
all the functionality within the size limits. I could not have included
smart bombs without the rule excluding { } ; characters in the counts.
All of the #defines are there to reduce code size.
On the other hand, I did waste a few characters in order to include
some rather obfuscated math in the program. It uses fixed-point
arithmetic, resulting in the overuse of bitwise shift operators.
Another example is (x|1), which is used in a couple different ways.
The purpose of A/(x|1) is probably obvious, but what does (x|1)%2 do?