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.
+244
View File
@@ -0,0 +1,244 @@
# %W% %G% %U%
#
# 1992 makefile
#
# Copyright (c) 1992, Landon Curt Noll & Larry Bassel.
# All Rights Reserved. Permission for personal, educational or non-profit
# use is granted provided this this copyright and notice are included in its
# entirety and remains unaltered. All other uses must receive prior permission
# from Landon Curt Noll and Larry Bassel.
SHELL=/bin/sh
CHMOD=chmod
CP=cp
RM=rm
SED=sed
LN=ln
UNIQ=uniq
CB=cb
GREP=grep
# set this to where your C Processor resides
#
# On some systems:
# CPP=/lib/cpp
#
CPP=/usr/ccs/lib/acpp
# 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 may want nothing
# at all. Adjust the CFLAGS line as needed.
#
# NOTE: Some compilers cannot optimize, or optimize some entries
# entries incorrectly. You might want need to turn on -O
# to see if your compiler can handle them.
#
#CFLAGS=-O -Xa
CFLAGS=-Xa
CC=cc
# misc shell babble
#
NOINCLUDE=$(SED) -e 's/^.\([ ]*\)include/%include/'
SPACECLEAN=$(SED) -e 's/\([^ ]\)\([ ]\)[ ][ ]*/\1\2/g'
CPPCLEAN=$(GREP) -v '^. [0-9][0-9]*'
# winners that compile under ANSI C
#
WINNERS= adrian albert ant buzzard.1 buzzard.2 gson kivinen imc \
lush marangon nathan vern westley
ALT_NAMES= adgrep am babble first ag whereami
all: $(WINNERS) $(ALT_NAMES)
adrian: adrian.c
$(CC) $(CFLAGS) adrian.c -o adrian
$(RM) -f ad.temp adwc.c adbasename.c adecho.c adhead.c adsleep.c
$(SED) '1s/\..*\./. wc ./' adrian.c > ad.temp
-./adrian ad.temp <ad.temp >adwc.c
$(CC) -o adwc adwc.c
$(SED) '1s/\..*\./. basename ./' adrian.c > ad.temp
-./adrian ad.temp <ad.temp >adbasename.c
$(CC) -o adbasename adbasename.c
$(SED) '1s/\..*\./. echo| ./' adrian.c > ad.temp
-./adrian ad.temp <ad.temp >adecho.c
$(CC) -o adecho adecho.c
$(SED) '1s/\..*\./. head; ./' adrian.c > ad.temp
-./adrian ad.temp <ad.temp >adhead.c
$(CC) -o adhead adhead.c
$(SED) '1s/\..*\./. sleep ./' adrian.c > ad.temp
-./adrian ad.temp <ad.temp >adsleep.c
$(CC) -o adsleep adsleep.c
$(RM) -f ad.temp
# NOTE: this is the original source that won
#
adrian.orig: adrian.orig.c
$(CC) $(CFLAGS) adrian.orig.c -o adrian.orig
albert: albert.c
$(CC) $(CFLAGS) albert.c -o albert
# NOTE: this is the original source that won
#
albert.orig: albert.orig.c
$(CC) $(CFLAGS) albert.orig.c -o albert.orig
ant: ant.c
$(CC) $(CFLAGS) ant.c -o ant
buzzard.1: buzzard.1.c
$(CC) $(CFLAGS) buzzard.1.c -o buzzard.1
babble.cppcb: buzzard.1.c
$(NOINCLUDE) buzzard.1.c | \
$(CPP) $(CPPFLAGS) | \
$(CPPCLEAN) | \
$(CB) $(CBFLAGS) | \
$(UNIQ) | \
$(SPACECLEAN) > babble.cppcb 2>&1
buzzard.2: buzzard.2.c
$(CC) $(CFLAGS) buzzard.2.c -o buzzard.2
# NOTE: this is the original source that won
#
buzzard.2.orig: buzzard.2.orig.c
$(CC) $(CFLAGS) buzzard.2.orig.c -o buzzard.2.orig
gson: gson.c
$(CC) $(CFLAGS) gson.c -o gson
# NOTE: some systems may only need:
#
# $(CC) $(CFLAGS) kivinen.c -o kivinen -lX11
#
kivinen: kivinen.c
$(CC) $(CFLAGS) kivinen.c -o kivinen -lX11 -lsocket -lresolv -lnsl
# NOTE: this is the original program that won
#
# NOTE: some systems may only need:
#
# $(CC) $(CFLAGS) kivinen.c -o kivinen -lX11
#
kivinen.orig: kivinen.orig.c
$(CC) $(CFLAGS) kivinen.orig.c -o kivinen.orig -lX11 \
-lsocket -lresolv -lnsl
imc: imc.c
$(CC) $(CFLAGS) imc.c -o imc
# NOTE: this is the original program that won
#
imc.orig: imc.orig.c
$(CC) $(CFLAGS) imc.orig.c -o imc.orig
lush: lush.c
$(CC) $(CFLAGS) lush.c -o lush
lush.again: lush.c
$(CC) $(CFLAGS) lush.c -o lush.again
$(RM) -f lush.again
# NOTE: this is the original program that won
#
lush.orig: lush.orig.c
$(CC) $(CFLAGS) lush.orig.c -o lush.orig
# NOTE: some systems may need:
#
# $(CC) $(CFLAGS) marangon.c -o marangon -lcurses -ltermcap
#
marangon: marangon.c
$(CC) $(CFLAGS) marangon.c -o marangon -lcurses
# NOTE: this is the original program that won
#
# NOTE: some systems may need:
#
# $(CC) $(CFLAGS) marangon.orig.c -o marangon.orig -lcurses -ltermcap
#
marangon.orig: marangon.orig.c
$(CC) $(CFLAGS) marangon.orig.c -o marangon.orig -lcurses
nathan: nathan.c
$(CC) $(CFLAGS) nathan.c -o nathan
# NOTE: this is the original program that won
#
nathan.orig: nathan.orig.c
$(CC) $(CFLAGS) nathan.orig.c -o nathan.orig
vern: vern.tmp.c
$(CC) $(CFLAGS) vern.tmp.c -o vern
vern.tmp.c: vern.c
$(RM) -f vern.tmp.c
$(SED) <vern.c 's/{ /(/g;s/} /)/g;s/; /#define /' | \
$(SED) 's/} /=/g;s/{ /i/g' >vern.tmp.c
# NOTE: this is the original program that won
#
vern.orig: vern.orig.tmp.c
$(CC) $(CFLAGS) vern.orig.tmp.c -o vern.orig
vern.orig.tmp.c: vern.orig.c
$(RM) -f vern.orig.tmp.c
$(SED) <vern.orig.c 's/{ /(/g;s/} /)/g;s/; /#define /' | \
$(SED) 's/} /=/g;s/{ /i/g' >vern.orig.tmp.c
westley: westley.c
$(CC) $(CFLAGS) westley.c -o westley
# alternate names for selected entries
#
adgrep: adrian
$(RM) -f adgrep
$(LN) adrian adgrep
am: ant
$(RM) -f am
$(LN) ant am
babble: buzzard.1
$(RM) -f babble
$(LN) buzzard.1 babble
first: buzzard.2
$(RM) -f first
$(LN) buzzard.2 first
ag: gson
$(RM) -f ag
$(LN) gson ag
whereami: westley
$(RM) -f whereami
$(LN) westley whereami
clean:
$(RM) -f *.o a.out core
$(RM) -f vern.tmp.c lush.again babble.cppcb vern.orig.tmp.c
$(RM) -f ad.temp adwc.c adbasename.c adecho.c adhead.c adsleep.c
clobber: clean
$(RM) -f $(WINNERS) a.out
$(RM) -f $(ALT_NAMES)
$(RM) -f adwc adbasename adecho adhead adsleep
$(RM) -f adrian.orig lush.orig nathan.orig buzzard.2.orig
$(RM) -f kivinen.orig imc.orig albert.orig marangon.orig vern.orig
am_clobber: clean am
$(RM) -f am.safe
$(CP) am am.safe
$(RM) -f $(WINNERS) a.out
$(RM) -f $(ALT_NAMES)
$(RM) -f adwc adbasename adecho adhead adsleep
$(RM) -f adrian.orig lush.orig nathan.orig buzzard.2.orig
$(RM) -f kivinen.orig imc.orig albert.orig marangon.orig vern.orig
$(CP) am.safe am
$(RM) -f am.safe
nuke: clobber
@true
install: all
cat $(WINNERS) > /dev/null
+88
View File
@@ -0,0 +1,88 @@
1992 marked the "The Ninth International Obfuscated C Code Contest"
Copyright (c) 1992, Landon Curt Noll & Larry Bassel.
All Rights Reserved. Permission for personal, educational or non-profit use is
granted provided this this copyright and notice are included in its entirety
and remains unaltered. All other uses must receive prior permission in writing
from both Landon Curt Noll and Larry Bassel.
Use make to compile entries. It is possible that on BSD or non-unix
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). A number of compilers had problems optimizing certain
entries. Some compilers do optimize, but the resulting program
does not work. By default we have left off -O from compile lines.
You might want to add -O back, or add it back for certain entries
where performance is important.
This year marked an all time high for number of entries as well as the
quality of entries. Nearly twice the usual number of entries made it
to the final judging rounds. Even when we raised the standards for
winning, we still wound giving out a few more awards than in other
years. The new size rules size probably contributed to the overall
high quality.
FYI: By tradition, we do not record the count the number entries,
nor do we give our our guess as to the number of entries
received. For folks who wonder, we can say that we consumed
about 2000 pages of output (printing between 2 and 4 normal
pages per side) during the judging process this year.
The new instructions for submitting entries worked well - we were
able to write scripts to unpack them and eliminate duplicates.
As promised last year, we accepted programs that made use of the X
libraries for the first time. We now consider ANSI C compilers to be
the "standard" version that the entries were compiled with.
Name and address information are separated from the actual program
prior to judging. This eliminates any chance that we would bias our
judging for/against any person or group. In the end, we are surprised
as you are to see who as won. Even so, it is worth noting that
Brian Westley has submitted a winning entry for the past 6 years!
A few notes regarding future contests:
We did not give awards to some traditional contest categories such as
"Best Layout". We felt that to do so would deny awards to more
deserving entries. These categories have not been eliminated. We will
likely be awarding them in future years.
We received a few entries whose instructions were rot13'd. While
nothing was said about this in the rules, we found that it made the
judging process a little harder, so we may request that this not
be done this in the future.
Some thought has been given to a separate obfuscated perl contest.
Watch comp.lang.perl for details!
Be sure to wait until the 1993 rules are posted before submitting entries.
We may fine tune the rules to reflect the some ideas above.
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:
...!{sun,pacbell,uunet,pyramid}!hoptoad!judges
judges@toad.com
If you use, distribute or publish these entries in some way, please drop
us a line. We enjoy seeing who, where and how the contest is used.
If you have problems with any of the entries, AND YOU HAVE A FIX, please
Email the fix (patch file or the entire changed file) to the above address.
Credits:
We would like to thank Barbara Frezza for her role as official chef of
the contest. Landon Noll and Larry Bassel appreciated the opportunity
to serve as official taste testers. Yummo!
+113
View File
@@ -0,0 +1,113 @@
/* . wc . */
#include<stdio.h>/* Wht majr flwchrt? */
#include<string.h>/* That mjr flwchrt! */
#define P 257
#define G 17
#define z 8
#define v(jr) jr
int W ,head;
#define S(W,b,f) strncpy(W,b,f),W[f]=0\
char *wcs=" \t\n";
struct{ char X[z+1];
char f ;
int e ;
struct{ char g[z+1];
int b ;
} w[ G];
} o[ P];
int L=0,j= -28;
void E(int i, int m,char*c)
{
for(; i<43; i+=3)
putc("}|uutsrq`_^bji`[Zkediml[PO]a_M__]ISOYIRGTNR"[i]+i-9,stderr);
fprintf(stderr,"(%d): %s\n" ,m,c);
exit(1);
}
int N(int m, char *t)
{
int i ;
if (strlen (
t)>z) t[z ]=0;
for(i= 0; i< L ; i++) if(
!strcmp (o[ i] . X
, t))return i;
if( L== P)
E(0, m, t);
S (o[ L] . X , t
,z);
head; W = .1* head;
o[L ].f = !( strchr( t,']' )== 0 );
o[L ++ ] . e = 0;
return L -1 ; }
#define v(x )
int A(char *R)
{
int c=0, i;
while(* R) {
i = -1;
while(j){
if( ++ i==o[ c].e ) return 0;
if(o[
c] .w[i ] .g[0 ]
=='.' ||strchr (o[ c].w[i] .g ,* R)){
c=
o[ c ] .w[i].b; break;/*
main(int sl,char *j[]){
sleep (~~~~~~~~atoi(j[1])) ;/* . sl
sl s l . sl
l l ]
sl */ }
}
R++;
}
return o[ c].f;
}
main(int wc,char *V[]){char Y[999],*s;FILE*W;int m=0,echo,jr,q,wcl=0,wcw=0,wcc=0;
v(s = V[1]; if (*V=strrchr(s,'/'))s=*V+1; if(( !strncmp( s + (jr=strlen(s)) -
(q=strlen(V[2]) ),V[2],q))&&jr!=q) s[jr-q] = 0; puts(s); )
int e,p,C=0,Q ,basename;
W= fopen(wc>= 2 ? V[1] : "adgrep.c","rt");
echo| m^ e| 5| (int) .8| echo|
wc |C ==o[o[C] .e] .
e| e==+p,p; s[o[C] .e ]
;
while( fgets(Y,998,W)) { wcc += strlen(Y); m++;
if( s = strtok(Y,wcs)) wcw++;
else continue ;
C=
basename= j +j+*"* . basename"
+j+*"* r ] " + N(m,s) ;
while( s = strtok(0,wcs)) {
if( o[ C ] . e ==
G) E(1 ,m,o[C] .X) ;
S(o[C
] .w[o[C ] .e].g,s, z);
Q= C ;
if(! ( s =strtok ( 0 ,wcs )))wcw --
,E( 2 , m, o[C]
. w[ o[ Q ] .e] . g );
e
= o[C ] .w[o[C ] .e++ ] .b= N(m,s)
; wcw += 2; }
0&&
W && wcl++
< 10 && printf((W,Y)); }
if(j+28) { {
; } printf("%7u%7u%7u\n", wcl , wcw , wcc); }
while( gets(Y) ) if(A(Y)) puts(Y);
W, jr; }
O(int wc,char**V) {
--wc && (printf("%s ",*++V), main(wc,V), 1) || printf("\n"); }
+4
View File
@@ -0,0 +1,4 @@
<q0> a <q1> The first state to appear is the start state
<q1> b <q2>
<q2> c [q3]
[q3]
+4
View File
@@ -0,0 +1,4 @@
<q0> a <q1>
<q1> b <q2>
<q2> c [q3]
[q3] . [q3]
+4
View File
@@ -0,0 +1,4 @@
<q0> a <q1> . <q0>
<q1> b <q2> a <q1> . <q0>
<q2> c [q3] a <q1> . <q0>
[q3] . <q1>
+3
View File
@@ -0,0 +1,3 @@
[q0] a <q1>
<q1> b <q2>
<q2> c [q0]
+4
View File
@@ -0,0 +1,4 @@
<q0> ab <q1>
<q1> cd <q2>
<q2> ef [q3]
[q3]
+8
View File
@@ -0,0 +1,8 @@
<q0> F <q1>
<q1> r <q2>
<q2> o <q3>
<q3> m <q4>
<q4> : <q5> . [q6]
<q5> . <q5>
[q6] . [q6]
+4
View File
@@ -0,0 +1,4 @@
<q0> t <q1> . <q0>
<q1> hc <q2> t <q1> . <q0>
<q2> eh [q3] t <q1> . <q0>
[q3] . <q1>
+227
View File
@@ -0,0 +1,227 @@
Most Educational:
Adrian Mariano
University of Washington
2729 72nd Ave SE
Mercer Island, WA 98040
USA
Judges' comments:
To build:
make adrian
Try:
adrian adrian.grep.try < adrian.hint
For the slow minded, try:
adsleep 32767
Once you get past the obfuscation, you have an opportunity to learn
about regular expressions and state machines.
NOTE: Some compilers have had trouble optimizing this entry.
Selected notes from the author:
ADrian's GREP (adgrep)
For those confused by the complexity of full-blown egrep style regular
expressions, this program offers an alternative. It implements an
equivalent search, using a deterministic finite automaton.
A deterministic finite automaton consists of a finite set of states,
along with transition rules to move from one state to another, an initial
state, and a set of accepting states. The automaton takes a string as
input and begins in the start state. It reads a character of the string
and consults the rules for the current state, moving to the new state
indicated by the appropriate rule. This process is repeated until the
string is consumed. If the current state at this point is one of the
accepting states, then the string is accepted.
The deterministic finite automaton is specified as a series of rules for
each state:
<state> chars1 <dest1> chars2 <dest2> ...
chars1 is a list of characters (only the first 8 are significant) which
should trigger a transition to <dest1>. <dest1> is another state which
should have a similar specification somewhere. A state is accepting if
it is specified in square brackets: [final], and state strings are
significant to only eight characters.
Example 1: matches ^abc$
<q0> a <q1> The first state to appear is the start state
<q1> b <q2>
<q2> c [q3]
[q3]
Technically, a deterministic finite automaton should have a rule for each
possible input character at each state. To simplify descriptions of the
automata, if no rule is present, the string will not be accepted. Also,
the '.' character matches any character if it occurs first in the
character list.
Example 2: ^abc
<q0> a <q1>
<q1> b <q2>
<q2> c [q3]
[q3] . [q3]
Example 3: abc$
<q0> a <q1> . <q0>
<q1> b <q2> a <q1> . <q0>
<q2> c [q3] a <q1> . <q0>
[q3] . <q1>
Example 4: ^(abc)*$
[q0] a <q1>
<q1> b <q2>
<q2> c [q0]
Example 5: ^[ab][cd][ef]$
<q0> ab <q1>
<q1> cd <q2>
<q2> ef [q3]
[q3]
Example 6: ^(abc|efg)$
<q0> a <q1> e <q3>
<q1> b <q2>
<q2> c [q5]
<q3> f <q4>
<q4> g [q5]
[q5]
With the automaton specification in 'filename', invoke the program by
typing
adgrep 'filename'
It will read stdin and print out all the lines which the automaton
accepts. If the file cannot be opened, a system error message will
be printed. If the input contains errors, then an error message along
with the number of the offending line will be printed to stderr. The
number of rules for each state is limited to 17. If more than 17 rules
are present, you get the error to_many_rules, and the state that was
being processed is printed. Error no_destination occurs if you specify a
set of characters, but no destination state, and error too_many_states
occurs if your automaton has more than 257 states.
Running
adgrep from < your_mailbox
will perform a function similar to that of the unix from command.
If no filename is specified on the command line, then "adgrep.c" is used
as the specification for the automaton. (This file has been renamed
to adrian.c by the judges.) In this case, the program will search for
matches to the regular expression:
^.[^|C][^w[Q]*(Q|[w[]c).*|^.[C|]$
I suggest using adgrep.c as input, and storing the output in adwc.c:
adgrep < adgrep.c > adwc.c
Compiling the new file, mywc.c, yields a clone of the unix wc command. It
runs on one file (defaulting to "adgrep.c" if no file is given) and
displays the number of lines, words, and bytes in the input file.
Another possibly interesting automaton can be created by slightly
adjusting the adgrep.c file. Change the first line to read
/* . echo| . */
and repeat the process above
adgrep <adgrep.c > adecho.c
The new file now contains all lines which match
^.[^5|m^]*[m^]([e=p,;]|[^e=+p,;].*)$
Compile and run. This is an echo clone. Note the efficient algorithm
employed.
Two other adjustments to the first line also yield useful results. By
changing it to
/* . head; . */
you can search for matches to
^.[^W]*W..*$
By some freak happenstance, lines of adgrep.c which match this regular
expression form a unix head command. It prints the first ten lines of
the file specified on the command line (or adgrep.c if no file is
specified).
By setting the first line to
/* . basename . */
a clone of the unix basename command can be unearthed. The automaton will
search for
^.[^j]*jr.*$
on standard input. And the program which results by running adgrep.c
through this filter requires two parameters. The first is meant to be a
filename, and the second, an extension. All leading pathname components
are removed from the filename, and the extension is removed if present.
The resulting base name is printed to stdout.
Lastly, by setting the first line to
/* . sleep . */
you can search for
^.[^(~][^s]*sl.*$
Filtering adgrep.c through this search yields a clone of the sleep
command. Invoke with a single integer parameter, and it will pause
for that many seconds.
If either adbasename or adsleep is invoked with too few parameters,
the program will print the error message:
Segmentation fault (core dumped)
(The exact text of the above error messages varies from machine to
machine.) The four programs which read from stdin require lines
shorter than 999 characters.
The other info files are adrian.grep.[1-6] which contain the six
examples that appear above, and from, which is used to emulate the
unix from command. For reasons of clarity, the name "from" should
probably not be changed if possible. I wouldn't want to be accused of
confusing people by giving the input files weird names.
If you want to change the default input filename (line 80) you must be
careful to choose a name that doesn't match the wrong search patterns,
introducing extra lines into one of the programs.
The program will produce at least one warning and possible several
when compiled depending on the compiler.
Copyright (c) 1992, Landon Curt Noll & Larry Bassel.
All Rights Reserved. Permission for personal, educational or non-profit use is
granted provided this this copyright and notice are included in its entirety
and remains unaltered. All other uses must receive prior permission in writing
from both Landon Curt Noll and Larry Bassel.
+113
View File
@@ -0,0 +1,113 @@
/* . wc . */
#include<stdio.h>/* Wht majr flwchrt? */
#include<string.h>/* That mjr flwchrt! */
#define P 257
#define G 17
#define z 8
#define v(jr) jr
int W ,head;
#define S(W,b,f) strncpy(W,b,f),W[f]=0\
char *wcs=" \t\n";
struct{ char X[z+1];
char f ;
int e ;
struct{ char g[z+1];
int b ;
} w[ G];
} o[ P];
int L=0,j= -28;
void E(int i, int m,char*c)
{
for(; i<43; i+=3)
putc(i["}|uutsrq`_^bji`[Zkediml[PO]a_M__]ISOYIRGTNR"]+i-9,stderr);
fprintf(stderr,"(%d): %s\n" ,m,c);
exit(1);
}
int N(int m, char *t)
{
int i ;
if (strlen (
t)>z) t[z ]=0;
for(i= 0; i< L ; i++) if(
!strcmp (o[ i] . X
, t))return i;
if( L== P)
E(0, m, t);
S (o[ L] . X , t
,z);
head; W = .1* head;
o[L ].f = !( strchr( t,']' )== 0 );
o[L ++ ] . e = 0;
return L -1 ; }
#define v(x )
int A(char *R)
{
int c=0, i;
while(* R) {
i = -1;
while(j){
if( ++ i==o[ c].e ) return 0;
if(o[
c] .w[i ] .g[0 ]
=='.' ||strchr (o[ c].w[i] .g ,* R)){
c=
o[ c ] .w[i].b; break;/*
main(int sl,char *j[]){
sleep (~~~~~~~~atoi(j[1])) ;/* . sl
sl s l . sl
l l ]
sl */ }
}
R++;
}
return o[ c].f;
}
main(int wc,char *V[]){char Y[999],*s;FILE*W;int m=0,echo,jr,q,wcl=0,wcw=0,wcc=0;
v(s = V[1]; if (*V=strrchr(s,'/'))s=*V+1; if(( !strncmp( s + (jr=strlen(s)) -
(q=strlen(V[2]) ),V[2],q))&&jr!=q) s[jr-q] = 0; puts(s); )
int e,p,C,Q ,basename;
W= fopen(wc>= 2 ? V[1] : "adgrep.c","rt");
echo| m^ e| 5| (int) .8| echo|
wc |C ==o[o[C] .e] .
e| e==+p,p; s[o[C] .e ]
;
while( fgets(Y,998,W)) { wcc += strlen(Y); m++;
if( s = strtok(Y,wcs)) wcw++;
else continue ;
C=
basename= j +j+*"* . basename"
+j+*"* r ] " + N(m,s) ;
while( s = strtok(0,wcs)) {
if( o[ C ] . e ==
G) E(1 ,m,o[C] .X) ;
S(o[C
] .w[o[C ] .e].g,s, z);
Q= C ;
if(! ( s =strtok ( 0 ,wcs )))wcw --
,E( 2 , m, o[C]
. w[ o[ Q ] .e] . g );
e
= o[C ] .w[o[C ] .e++ ] .b= N(m,s)
; wcw += 2; }
0&&
W && wcl++
< 10 && printf((W,Y)); }
if(j+28) { {
; } printf("%7u%7u%7u\n", wcl , wcw , wcc); }
while( gets(Y) ) if(A(Y)) puts(Y);
W, jr; }
O(int wc,char**V) {
--wc && (printf("%s ",*++V), main(wc,V), 1) || printf("\n"); }
+152
View File
@@ -0,0 +1,152 @@
#include <stdio.h>
#include <malloc.h>
#include <setjmp.h>
#include <ctype.h>
#define new(PP) (PP *) malloc(sizeof(PP))
typedef struct q {
jmp_buf ppp;
long qq;
struct q *P;
struct q *p;
}
PP;
PP *P;
int aaaaaa=2;
int aaaaaaa=1;
long qqq;
aaAaaa(aa,aaa)
char *aa;
char *aaa;
{
char aaaa = 0;
if ((((( aaa )))))
{
aaaa = *aa;
*aa=0;
aa+=strlen(aa+1);
P =new(PP);
P->P=P;
P->p=P;
}
if ((((( !setjmp(P->ppp) )))))
{
if ((((( !isdigit(*aa) )))))
longjmp(P->ppp,aaaaaaa);
else {
P->p->P = new(PP);
P->p->P->P = P;
P->p->P->p = P->p;
P->p = P->p->P;
P->qq = *aa--;
P = P->p;
aaAaaa(aa,0);
}
} else {
if ( !aaaa&&!*aa )
longjmp(P->p->ppp,aaaaaaa);
if ((((( (P->qq=aaaa)<10 &&!
(isdigit(aaaa)) ||!
(isdigit(*aa) ||!
*aa ))))))
{
fprintf(stderr,"Usage %c%s <number>\n",
(aaa[0]?7:aaaa),aaa+!aaa[0]);
exit(1);
}
}
}
ppPppp(pp,ppp)
PP **pp, *ppp;
{
int aa;
if ((((( !(aa=setjmp(ppp->ppp))||aa==aaaaaa )))))
{
if ((((( *pp==ppp )))))
{
ppp = (*pp)->p;
if ( qqq<47 ) return;
if ( ppp->qq!=48 ) return;
while ( ppp->qq==48 )
{
printf("%ld\n",qqq-45);
*pp = ppp;
ppp = ppp->p;
}
qqq -= 1;
longjmp(ppp->ppp,aaaaaaa);
} else {
PP *p;
ppPppp(pp,ppp->p);
for (p=ppp;p!=*pp;p=p->p)
{
int qq=4;
if ((((( qqq<47 &&
(qq=0,p->qq+=p->p->qq-96)>=48-qqq ||
qqq>46 &&
(p->qq-=p->p->qq)<0 )))))
{
p->qq += qqq+qq;
if ( p->p==P && qqq<=46 )
{
P->p->P = new(PP);
P->p->P->P = P;
P->p->P->p = P->p;
*pp = P = P->p = P->p->P;
P->qq = 48;
}
p->p->qq+=qq==0;
p->p->qq-=qq!=0;
}
else
{
p->qq += 48;
}
}
if ( ppp->P==P ) longjmp(ppp->ppp,aaaaaaa);
}
}
else
{
qqq += 1;
while (48==P->qq )
{
P->P->p = P->p;
P = P->p->P = P->P;
}
if ( ppp!=ppp->p->p || qqq<47 )
longjmp(ppp->ppp,aaaaaa);
else
{
printf("At most one remains\n");
exit(0);
}
}
}
main(aaa,aaaa)
int aaa;
char **aaaa;
{
aaAaaa(aaa==aaaaaaa?aaaa[0]:aaaa[1],aaaa[0]);
qqq = 39;
ppPppp(&P,P->p);
}
+34
View File
@@ -0,0 +1,34 @@
#include <stdio.h>
main(argc,argv)
int argc;
char **argv;
{
long arg[100];
int i,j;
int base = 10;
int start = 0;
int end= strlen(argv[1]);
for (i=0;i<end;i++)
arg[i] = argv[1][i]-'0';
while ( end-start > 2 )
{
while ( arg[end-1] == 0 ) {
printf("%d\n",base);
end--;
}
while ( arg[start] == 0 ) start +=1;
base += 1;
for (i=start+1;i<end;i++)
for (j=i;j>start;j--)
if ( (arg[j]-=arg[j-1])<0 )
{
arg[j]+=base;
arg[j-1] -= 1;
}
}
}
+22
View File
@@ -0,0 +1,22 @@
From: leo _at_ zycad -dot- com (Leo Broukhis)
Date: Tue, 30 Jan 96 17:37:51 PST
To: judges _at_ toad -dot- com
Subject: IOCCC 1992 - a bug
Dear Judges,
albert.c (even in its fixed form) still has a bug. Although I don't
remember the number that exposed the bug (afair, resulting in coredump)
in albert.orig.c that has been fixed in albert.c,
I've found a number exposing another bug: 10000000001 (that's 9 0's).
Both albert and albert.orig loop without printing anything, although
the first factor is 101 and is usually found in an instant.
Unfortunately, the e-mail address in albert.hint is no longer valid,
and neither whois, nor replacing old domain name with a new one according
to the MX records, nor Altavista Web search were successful.
...Fortunately, Albert van der Horst did send me an unobfuscated
(but somewhat limited - it doesn't check the number for factors 2, 3, 5, 7)
version of his program. I didn't have a chance to augment its functionality
to the one of the contest entry.
+85
View File
@@ -0,0 +1,85 @@
Most Useful Program:
Albert van der Horst
S P&A R&C
Oranjestraat 8
3511 RA UTRECHT
The Netherlands
Judges' comments:
For a canned example:
make albert
albert 1234567890123456789
We were impressed with the speed at which it was able to factor
arbitrarily large numbers consisting of factors that fit into
a long.
Selected notes from the author:
The Obfuscated version of the Horst algorithm.
This program will factor unlimited length numbers and print the
factors in ascending order. Numbers of one digit (e.g. 8)
are rejected without notice.
It quits as soon as there is at most one
factor left, but that factor will not be shown.
It accomplishes this efficiently, without resorting to division
or multiplication, until the candidate factor no longer fits in
a signed long.
The nicest way is to rename the program into e.g. 4294967297
if you want to factor Fermat's 4th number. Then just run it.
Or you may type "prog <some-number>"
A nice one is also (30 ones)
albert 111111111111111111111111111111
Apart from the foregoing there are no special execution instructions.
To customize the program into a factorizer of a fixed number, use
cc albert.c -o 4294967297
or some such.
There are no data files used, and it is not possible to feed input
via stdin.
I think this program is a nice example of algorithmic obfuscation.
Several times two similar algorithms are merged into one. Then you
need quite some tricks to get it running, such as long jumps
through recursive subroutines. I felt like a sword smith,
welding the sword very long, folding it again to the proper
length, keep on hammering till it is tight, then fold again.
Always keeping it at the proper red hot temperature, but not too
hot lest the hardness fades.
The strict naming conventions for subroutines did not make things
much clearer after all, but it was not supposed to.
I would like to draw attention to the robustness of the program
with respect to error handling and the nice stopping criterion.
The esthetic appeal of some lines is at the expense of clearness,
I apologize.
Running the program through the c-beautifier reveals nothing,
it will only destroy some of the lay out.
Running the program through lint shows the usual remarks for a
K&R program. Defeating this through casts does not make a program
cleaner in my opinion.
Here are some hints, but they may not be too helpful.
1. The Horst algorithm is described in the Hobby Computer Club
Newsletter, year 82, part 4, a real Dutch treat.
Assembler, c and Forth version have been around for some years.
2. Does fractal programming exist after all?
3. You remember the ToomCook algorithm in Knuth?
It uses iteration instead of recursion and is quite jumpy.
This program shares these disadvantages in a modified form.
4. The Conversion is to be found in Knuth, not so the Observation.
The Observation: "if it ends in a zero, it is divisible by ten"
Copyright (c) 1992, Landon Curt Noll & Larry Bassel.
All Rights Reserved. Permission for personal, educational or non-profit use is
granted provided this this copyright and notice are included in its entirety
and remains unaltered. All other uses must receive prior permission in writing
from both Landon Curt Noll and Larry Bassel.
+152
View File
@@ -0,0 +1,152 @@
#include <stdio.h>
#include <malloc.h>
#include <setjmp.h>
#include <ctype.h>
#define new(PP) (PP *) malloc(sizeof(PP))
typedef struct q {
jmp_buf ppp;
long qq;
struct q *P;
struct q *p;
}
PP;
PP *P;
int aaaaaa=2;
int aaaaaaa=1;
long qqq;
aaAaaa(aa,aaa)
char *aa;
char *aaa;
{
char aaaa = 0;
if ((((( aaa )))))
{
aaaa = *aa;
*aa=0;
aa+=strlen(aa+1);
P =new(PP);
P->P=P;
P->p=P;
}
if ((((( !setjmp(P->ppp) )))))
{
if ((((( !isdigit(*aa) )))))
longjmp(P->ppp,aaaaaaa);
else {
P->p->P = new(PP);
P->p->P->P = P;
P->p->P->p = P->p;
P->p = P->p->P;
P->qq = *aa--;
P = P->p;
aaAaaa(aa,0);
}
} else {
if ( !aaaa&&!*aa )
longjmp(P->p->ppp,aaaaaaa);
if ((((( (P->qq=aaaa)<10 &&!
(isdigit(aaaa)) ||!
(isdigit(*aa) ||!
*aa ))))))
{
fprintf(stderr,"Usage %c%s <number>\n",
(aaa[0]?7:aaaa),aaa+!aaa[0]);
exit(1);
}
}
}
ppPppp(pp,ppp)
PP **pp, *ppp;
{
int aa;
if ((((( !(aa=setjmp(ppp->ppp))||aa==aaaaaa )))))
{
if ((((( *pp==ppp )))))
{
ppp = (*pp)->p;
if ( qqq<47 ) return;
if ( ppp->qq!=48 ) return;
while ( ppp->qq==48 )
{
printf("%ld\n",qqq-45);
*pp = ppp;
ppp = ppp->p;
}
qqq -= 1;
longjmp(ppp->ppp,aaaaaaa);
} else {
PP *p;
ppPppp(pp,ppp->p);
for (p=ppp;p!=*pp;p=p->p)
{
int qq=4;
if ((((( qqq<47 &&
(qq=0,p->qq+=p->p->qq-96)>=48-qqq ||
qqq>46 &&
(p->qq-=p->p->qq)<0 )))))
{
p->qq += qqq+qq;
if ( p->p==P && qqq<=46 )
{
P->p->P = new(PP);
P->p->P->P = P;
P->p->P->p = P->p;
*pp = P = P->p = P->p->P;
P->qq = 48;
}
p->p->qq+=qq==0;
p->p->qq-=qq!=0;
}
else
{
p->qq += 48;
}
}
if ( ppp->P==P ) longjmp(ppp->ppp,aaaaaaa);
}
}
else
{
qqq += 1;
while (48==P->qq )
{
P->P->p = P->p;
P = P->p->P = P->P;
}
if (ppp!=ppp->p->p )
longjmp(ppp->ppp,aaaaaa);
else
{
printf("At most one remains\n");
exit(0);
}
}
}
main(aaa,aaaa)
int aaa;
char **aaaa;
{
aaAaaa(aaa==aaaaaaa?aaaa[0]:aaaa[1],aaaa[0]);
qqq = 39;
ppPppp(&P,P->p);
}
+271
View File
@@ -0,0 +1,271 @@
NAME
am Anthony's Make
SYNOPSIS
am <makefile> [target]
DESCRIPTION
AM is a programmer's tool to maintain, update, and regenerate groups
of files and/or programs. It is similar to MAKE as described by the
POSIX.2 draft standard 11.2, and this document parallels the draft
in order to point out the subtle differences between AM and MAKE.
The AM utility can be used as part of software development to update
files that are derived from other files. A typical case is one where
object files are derived from the corresponding source files. The AM
utility examines time relationships and updates those derived files
(targets) that have modified times earlier than the modified times of
the files (prerequisites) from which they are derived. A description
file ("makefile") contains a description of the relationships between
files, and the commands that must be executed to update the targets to
reflect changes in their prerequisites. Each specification, or rule,
shall consist of a target, optional prerequisites, and optional
commands to be executed when a prerequisite is newer than the target.
OPTIONS
None.
OPERANDS
makefile This required argument, is a pathname of a description
file, which is also referred to as the "makfile". A
pathname of "-", shall *NOT* denote the standard input.
target This optional argument, is the first target to be
processed. If no target is specified, when AM is
processing the makefile, the first target that AM
encounters shall be used.
EXTERNAL INFLUENCES
STANDARD INPUT
Not used.
INPUT FILES
The input file, otherwise known as the makefile, is a text file
containing rules, macro definitions, and comments.
ASYNCHRONOUS EVENTS
All traps are left to their default actions. If AM receives a SIGHUP,
SIGTERM, SIGINT, or SIGQUIT then AM will terminate as per request
*WITHOUT* removing the current target.
EXTERNAL EFFECTS
STANDARD OUTPUT
The AM utility shall write all commands to be executed to standard
output unless the command is prefixed with an at-sign (@). If AM is
invoked without any work needing to be done, it shall *NOT* write a
message to standard output indicating that no action was taken.
STANDARD ERROR
Standard error is used for diagnostic messages only.
OUTPUT FILES
None. However, the utilities invoked by AM may create additional files.
EXTENDED DESCRIPTION
The AM utility attempts to perform the actions required to ensure
that the specified target(s) are up-to-date. A target is considered
out-of-date if it is older than any of its prerequisites or it does
not exist. The AM utility shall treat all prerequisites as targets
themselves and recursively ensure that they are up-to-date, processing
them in the order which they appear in the rule. The AM utility shall
use the modification times of files to determine if the corresponding
targets are out-of-date.
After AM has ensured that all of the prerequisites of a target are
up-to-date, and if the target is out-of-date, the commands associated
with the target entry shall be executed. If there are no commands
listed for the target, the target shall be treated as up-to-date.
MAKEFILE SYNTAX
A makefile can contain rules, macro definitions, and comments. If a
macro is defined more than once, the value of the macro shall be the
last one specified. Comments start with a number-sign (#) and
continue until an unescaped <newline> is reached.
A backslash before a <newline> serves as a line continuation mark, and
is used to create long-lines. A line will continue to be extended until
an unescaped <newline> is reached.
When an escaped <newline> (one preceded by a backslash) is found anywhere
in the makefile, it shall be replaced, along with any leading white
space on the following line, with a single <space>.
MAKEFILE EXECUTION
Command lines shall be processed one at a time by writing the command
line to standard output, unless prefixed with an at-sign (@), and
executing the command(s) in the line. Commands shall be executed by
passing the command line to the command interpreter via the system()
function.
The environment for the command being executed shall contain all of the
variables in the environment of AM. All macros are considered to be part
of the environment too.
By default, when AM receives a non-zero status from the execution of a
command, it terminates with an error message to standard error. If
the command is prefixed by a hyphen (-) then any error found while
executing the command shall be ignored.
Command lines can have one or more of the following prefixes: a hyphen
(-) to ignore errors, an at-sign (@) to be silent, or a plus-sign (+)
if the command is always executed (this prefix is for compatibility with
MAKE and is ignored).
TARGET RULES
Target rules are formatted as follows:
target [target ...] : [prerequisite ...]
[<tab>command
<tab>command
...]
(line that does not begin with <tab>)
Target entries are specified by a <blank>-separated, non-null list of
targets, then a colon, then a <blank>-separated, possibly empty list
of prerequisite. All following lines, if any, that begin with a <tab>,
are command lines to be executed to update the target(s). The first
line that does not begin with a <tab> shall begin a new entry.
Target names can be any character supported by the host system,
excluding <blank>s, <tab>s, <newline>s, and colons (:), which are used
for delimiters.
For any given target there can be only one target rule. The first
occurrence of a target in a makefile shall be used. All subsequent
rules for the same target are ignored. There is *no* support for
adding prerequisites to a target's prerequisite list once a target
rule is defined.
There are no special targets or inference rule support.
MACROS
Macro definitions are in the form:
string1 = [string2]
The macro named string1 is defined as having the value of string2,
where string2 is defined as all characters, if any, after the equal
sign up to an unescaped <newline>. Any <blank>s immediately before or
after the equal sign shall be ignored.
Subsequent appearances of $(string1) shall be replaced by string2.
The parentheses are *NOT* optional if string1 is a single character.
The macro $$ shall be replaced by the single character $.
Macro names can be any character that the host system would allow in
the definition of environment variables, excluding parentheses, ( and ),
which are used for delimiters.
Macros can appear anywhere in the makefile, except within other macro
references (ie. no nesting). Macros in target and command lines shall
be evaluated when the line is read. Macros in macro definition lines
shall be evaluated *IMMEDIATELY*. A macro that has not been defined
shall evaluate to a null string without causing any error condition.
If a macro is defined more than once, the value of the macro shall be the
last one specified prior to it being referenced.
Macro assignments shall be accepted from the sources listed below, in
the order shown. If a macro name already exists at the time it is being
processed, the newer definition shall replace the existing definition.
1) The contents of the environment, including the variables with
null values in the order defined in the environment.
2) Macros defined in the makefile, processed in the order specified.
There are no internal macros supported. The SHELL macro shall *NOT* be
treated specially.
EXIT STATUS
0 Successful completion.
1 General error.
2 Usage error.
3 Failed to open makefile.
4 Failed to allocate memory.
INSTALLATION
AM can be built on any system providing at least K&R C. It has been
tested on
o SunOS with GCC
o ATARI Mega ST with Sozobon C
o PC clone with Turbo C
o Interactive UNIX System V/386 release 3.2
For all machines, the compile command line should be
cc -O -o am am.c
The value RULES represents the number of slots available to record
target rules, dependencies, and commands. The default value chosen
should handle most project makefiles. RULES can be overridden on the
command line with -DRULES=nn, where 0 < nn < INT_MAX.
On a DOS machine using Turbo C, it may be necessary to add the include
directive
#include <time.h>
with the rest of the includes if sys/stat.h does not properly define or
use time_t. Also, on some older K&R C compilers, stdlib.h may not be
defined and so it might be necessary to remove the include directive for
it.
REFERENCES
[Mil87] Webb Miller, "A Software Tools Sampler", Prentice Hall, 87
ISBN 0-13-822305-X, chaper 2
[POSIX] POSIX.2 draft 11.2 MAKE
FILES
ant.c Obfuscated source
ant.README Manual for AM
ant.test.mk Test makefile
BUGS
Unknown as of 20 March 92.
+178
View File
@@ -0,0 +1,178 @@
#define W while
#define S strspn
#define R return
#define F fprintf(stderr,
#define C continue;
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#ifndef RULES
#define RULES 500
#endif
#define N(p, i) (p += i, p += S(p, w), i = strcspn(p, w))
char *b, l[BUFSIZ], *t[RULES], *d[RULES], *c[RULES], w[] = "\n\t ";
time_t M();
int T();
void U();
time_t
M(f)
char *f;
{
int j, x;
size_t i = 0;
struct stat s;
N(f, i);
x = f[i];
f[i] = 0;
j = stat(f, &s);
f[i] = x;
R j < 0 ? 0 : s.st_mtime;
}
int
T(f)
char *f;
{
char *q;
size_t i = 0, j, k = 1;
N(f, i);
W ((q = t[k])) {
j = 0;
W (N(q, j)) {
if (i == j && !strncmp(f, q, i))
R k;
}
++k;
}
R 0;
}
void
U(f)
char *f;
{
time_t t = M(f);
size_t i = 0, j = !t, k = T(f);
char *p = d[k], *q = c[k];
if (!N(p, i) && q && *q != '\t' && j) {
F "am: Don't know how to make '%s'.\n", f);
exit(1);
}
W (0 < i) {
U(p);
if (t < M(p))
j = 1;
N(p, i);
}
if (j && q && *q == '\t') {
sleep(1);
W (*q++ == '\t') {
i = j = 1;
W (0 < S(q, "-+@")) {
if (*q == '@')
i = 0;
if (*q++ == '-')
j = 0;
}
if (i)
puts(q);
if (system(q) && j) {
F "am: Error making '%s'\n", f);
exit(1);
}
q += strlen(q) + 1;
}
c[k] = 0;
}
}
int
main(u, v)
int u;
char **v;
{
FILE *f;
struct stat s;
size_t i, j, k;
char *m, *n, *p, *q, *r;
if (u < 2) {
F "usage: am <makefile> [target]\n");
R 2;
}
if (stat(*++v, &s) || !(f = fopen(*v, "r")))
R 3;
q = b = malloc(2*s.st_size);
if (!b)
R 4;
i = 1;
k = 0;
m = 0;
*t = *d = *c = "";
W ((r = fgets(l, BUFSIZ, f))) {
if (RULES <= i) {
F "am: Number of target-rules exceeds %d.\n", RULES);
R 1;
}
if (k) {
*q++ = ' ';
r += S(r, w);
} else {
if (t[i])
c[i++] = q;
if (m && putenv(m))
F "am: No more environment space.\n");
m = 0;
if (*l == '#' || *l == '\n')
C
p = q;
}
W (!(k = *r == '\\' && r[1] == '\n') && *r) {
if (*r == '$') {
if (r[1] == '(') {
n = r+2;
r += strcspn(r, ")");
*r++ = 0;
n = getenv(n);
if (n)
q = strcpy(q, n) + strlen(n);
C
}
if (*r == r[1])
++r;
}
if (*r == '=' && *l != '\t' && !m) {
*q = 0;
m = p;
j = 0;
q = N(m, j) + m;
*q++ = *r;
j = 1;
if (!N(r, j))
*q++ = 0;
C
}
if (*r == ':') {
t[i] = p;
*r = 0;
d[i] = q+1;
}
if (*r == '\n')
*r = 0;
*q++ = *r++;
}
}
fclose(f);
U(2 < u ? *++v : t[1]);
R 0;
}
+38
View File
@@ -0,0 +1,38 @@
Best Utility:
Anthony C Howe
Mortice Kern Systems Inc.
Unit 1, 14 Weber Street North
Waterloo, Ontario
N2J 3G4
Canada
Judges' comments:
To use:
make am
am ant.test.mk
Like much of Posix, obfuscation has its place. Your task is to
figure out where.
This entry comes complete with a Posix-like command description.
Interested Posix balloters should lobby the IEEE for an obfuscated
P1003 sub-committee.
We also suggest that you try:
make am
am Makefile am_clobber <-- clobber everything except am
am Makefile all
Selected notes from the author:
See the file ant.README.
Copyright (c) 1992, Landon Curt Noll & Larry Bassel.
All Rights Reserved. Permission for personal, educational or non-profit use is
granted provided this this copyright and notice are included in its entirety
and remains unaltered. All other uses must receive prior permission in writing
from both Landon Curt Noll and Larry Bassel.
+196
View File
@@ -0,0 +1,196 @@
#
# Test makefile for AM
#
#
# Allow for empty macros.
#
EMPTY=
#
# Allow for white space in macro assignment.
#
TEXT_1=no white space
TEXT_2 =left hand side
TEXT_3= right hand side
TEXT_4 = both sides
TEXT_5 = tabs boths sides
#
# Test psuedo targets.
#
all : print_macros repeat redefine many flags multiple split errors done
print_macros : empty t1 t2 t3 t4 t5 t.all
#
# Targets with no dependencies.
#
empty :
echo EMPTY='$(EMPTY)'
t1 :
echo TEXT_1='$(TEXT_1)'
t2 :
echo TEXT_2='$(TEXT_2)'
t3 :
echo TEXT_3='$(TEXT_3)'
t4 :
echo TEXT_4='$(TEXT_4)'
t5 :
echo TEXT_5='$(TEXT_5)'
t.all :
echo $(TEXT_1) $(TEXT_2) $(TEXT_3) $(TEXT_4) $(TEXT_5)
#
# Test redefinition of macros. AM allows redefinition and
# evaluates macros immediately.
#
TEXT_1 =text number 1
TEXT_2 = test macro split \
across lines \
three lines
TEXT_3 = test dollar macro '$$'
TEXT_4 = test dollar again "$$(TEXT_1)"
TEXT_5 = imbeded macro '$(TEXT_1)'
redefine : r1 r2 r3 r4 r5
r1 :
echo TEXT_1='$(TEXT_1)'
r2 :
echo TEXT_2='$(TEXT_2)'
r3 :
echo TEXT_3='$(TEXT_3)'
r4 :
echo TEXT_4='$(TEXT_4)'
r5 :
echo TEXT_5='$(TEXT_5)'
#
# Try to update a prerequisite more than once. Subsequent occurences
# should be ignored once a prerequisite has been updated.
#
repeat: t1 repeat.a t3
repeat.a : t2 t1
#
# Target with multi-line receipe.
#
many : leaf.1 leaf.2
echo Execute receipe with multiple commands.
ls -1 leaf.*
echo Last line of receipe for target 'many'.
leaf.1 :
touch leaf.1
leaf.2 :
touch leaf.2
#
# Test receipe line flags.
#
flags : silence ignore always combination
# Command not displayed before execution.
silence :
echo You should not see the 'ls' command printed.
@ls leaf.*
# Ignore errors from command.
ignore :
echo The 'ls' command should fail but not terminate AM.
-ls unknown
# This flag is ignored by AM since we don't support a silence option (-n).
always :
+echo The '+' flag is accepted and ignored.
combination:
-@echo The next displayed line should not be 'ls unknown'
@-ls unknown
@+-echo Combined flags test completed.
#
# Multiple targets.
#
multiple : node.2 node.5
node.1 node.2 node.3 : leaf.1 leaf.2
touch node.1 node.2 node.3
node.4 node.5 : node.2 leaf.3
touch node.4 node.5
leaf.3 :
touch leaf.3
#
# Test split lines.
#
split : node.6 leaf.4 split.cmd
echo Completed split line tests.
# Target dependencies split across lines.
node.6 : leaf.1 \
leaf.2 \
leaf.3
echo Test dependency list split across lines.
touch node.6
# Target list split across lines.
split.tar \
leaf.4 \
leaf.5 :
echo Test target list split across lines
touch leaf.4 leaf.5
# Command lines split across lines.
split.cmd:
echo Try spliting command \
lines across more \
than one line.
#
# Test AM error reports and exit statuses.
#
errors:
-am test.mk error.1
-am test.mk error.2
-am test.mk error.3
# Target that does not exist, has no dependencies, and no commands.
error.1:
# Target where dependency does not exist.
error.2: unknown
# Receipe command causes error.
error.3: t1 fail t2
fail:
ls -l unknown
#
#
#
done:
echo AM Test Complete
clean:
rm leaf.* node.*
+61
View File
@@ -0,0 +1,61 @@
#define A(c,a,b) t=b;t+=a;_(c)
#define B(b,a) P(u,a)t=0;t-=a;R t+=u;t+=1;t/=2;_(b)
#define b(x) x(g)
#define C ;main(argc,argv)char**argv;{for(;!w;){q=0;l
#define c(y) x
#define D(c,a,b) t=a;t/=b;_(c)
#define d(x) S(x,x,1)
#define E(a,d) t=d;t-=p;t*=r;t*=a;p+=t;t=1;t-=a;r*=t;
#define e(x) y
#define f(x) x(e)
#define G(x,y) Q(x,atoi(argv[y]))
#define g(x) x(b)
#define H Q(w,1)Q(p,0)r=0;
#define h(x) x(c)
#define i(c,a,b) a(b,b,c)
#define J(x) Q(p,x)r=0;
#define j(x) Q(f(g),x)
#define K(x) Q(x,argc)
#define k(x) S(a,y,x)
#define L(x) u=p;u-=x;t=u;t*=u;R r+=2;r-=t;r/=2;
#define l L(q) q+=1;
#define M(c,a,b) t=a;t*=b;_(c)
#define m(x) x(a,a)
#define n(x) x(a,y)
#define O(c,a,b) t=b;t+=1;t+=a;t/=2;Q(c,t)
#define o(x,y) M(x,x,y)
#define P(b,a) t=a;R _(b)
#define R t+=2047;t/=2048;t+=8191;t/=8192;
#define Q(a,b) t=b;_(a)
#define S(c,a,b) t=a;t-=b;_(c)
#define T }
#define U(c,a,b) u=b;t=b;t-=1;t*=r;t+=1;b=t;t=a;t/=b;b=u;_(c)
#define V int t,u,q,p=0,r,w=0,
#define X(y) printf("%x\n",y);
#define Z(a,d) t=p;t-=d;t*=a;t+=d;_(p)r*=a;
#define _(a) t-=a;t*=r;a+=t;
V a,x,y,s C
G(f(g),q)G( g(h),2)n(B)Z(a,4)n(
P)E(a,1)j(2989)H l k (1)m(B)Z(a,6)l k(h(b))
B(s,a )m(P) Z(s ,8)E
(a,q )Q( s,h (g)
)Q( f(c ),f
(g) )j( s)l
i(b (h) ,S,
f(b ))n (B)
E(a ,2) J(8)
l j( x)Q(x,1)l n(P)Z(a,8
)o(x ,g(f))d(f(e))J(5)l j
(x)l d(x )S(a
,x, 1)m (B)
Z(a ,10 )U(
a,y ,x) o(a
,x) k(a )m(
P)E( a,7) l j (0)
Q(s,1 )l D(a ,x, q)o(
a,q)S(a,h(g),a)i(s, M,a)i(a,A,g(f))i(q,D,x
)o(s,16)B(a ,x)E(a,9)H l j(2766)H
T X(b(f)) T
+221
View File
@@ -0,0 +1,221 @@
Most Obfuscated Algorithm:
Sean Barrett
Software Construction Company
430 Southwest Parkway, #1906
College Station, TX 77840
USA
Judges' comments:
To see clearly why this won an award:
make babble
Try:
babble 0 10
babble 56 720
babble 1 521
To see good C Preprocessor babble, try:
make babble.cppcb
cat babble.cppcb
Notice how many statements it takes to do anything useful?
Selected notes from the author:
What you shouldn't think about babble:
babble doesn't just do a mass of #defines as its obfuscation.
What you should be glad about:
I didn't just submit the post-C-preprocessed output as an entry.
Cute trick warning:
babble contains only a numeric printf, yet sometimes it prints out
short strings.
What it does:
babble is a simple mathematical program. It expects two numeric
arguments.
% babble 0 <num>
will print out the factorial of <num>.
% babble <num1> <num2>
will print out the largest common factor of num1 and num2.
% babble 1 <num2>
will print out a factor of num2 if it's composite, or else
it will print a string informing you that num2 is prime.
If the first argument is less than 0, it prints out an
error message.
What it is:
babble is a translator from a pseudo-assembly language into a
subset of C suitable for execution on Charles Babbage's
Analytical Engine. Or rather, the #defines in babble are that
translator. The rest of babble is a babble program. If you run the
whole mess through CPP and a beautifier, you will see that
all you have is a loop that runs until a variable is not 0, and
a sequence of assignment statements. The assignment statements
are all of the form 'a op= b' or 'a = b'. The Engine actually
allowed 'a = b op c'. Only +, -, /, and * are used--no boolean
or bitwise operators. The infinite loop could have been
simulated on the AE by connecting the already-processed
card stack to the input card stack.
How to try to understand it:
*Don't* expand the #defines! Rather, decipher what they do.
Some of them are mere obfuscational fodder, put in to encourage
you to run it through CPP.
What it doesn't quite do right as an emulator:
Because of the definitional constraints, calls to atoi(argv[#])
also appear inside the loop. These could be put outside--
the initial values of the "registers" on the AE--but the
macro conventions being used didn't lend themselves to it.
Theoretical observations:
The simulated comparison operations only work with a certain
range of numbers; numbers that are too large will cause the
output code to fail to simulate the input code. This means
that this implementation of babble would not be turing-complete,
even if the AE could process indefinitely-sized numbers.
However, this is actually a constraint that no actual computer
can meet, either, so we can conclude that if an AE, with
card bins connected as suggested above, were hooked up to
a memory unit of sufficient size, it would be as turing
complete as any existing machine (or, for those who
interpret that excessively critically, i.e. "not at all" for
both, we can simply say that the AE could simulate any
existing machine--although not quickly). This would be a
good place to site some references on the AE, but I don't
have any.
Definition of the input language to babble:
(OR What Exactly Do All The Macros Do?)
[Don't read this unless you're stumped!]
MACRO FUNCTION MNEMONIC
V begin variable declarations Variable
C begin program Code
Q(b,a) let b = a eQuals
A(c,a,b) let c = a + b Add
S(c,a,b) let c = a - b Subtract
D(c,a,b) let c = a / b, where b is a *constant* Divide
U(c,a,b) let c = a / b, where b is anything Unknown
M(c,a,b) let c = a * b Multiply
O(c,a,b) let c = a boolean-or b (a,b are 0 or 1) Or
B(b, a) let b = boolean value of a Boolean
P(b, a) let b = 1 if a>0, else 0. Positive
l emit next sequential label Label
J(x) goto label #x Jump
Z(a,d) if a is 0 goto d (a is 0 or 1) Zero
E(a,d) if a is 1 goto d (a is 0 or 1) Else
H halt Haly
K(x) let x = number of cmd line arguments Kount
G(x,y) let x = the value if the yth argument Get argument
T end of code; begin output section Terminate
X(y) print out hexadecimal value of y heXadecimal
T end of output section and program Terminate
You can figure out the other macros yourself. In the sample
program, I've actually implemented subroutines by saving
a return address in a variable and then jumping to a routine--
specifically, a routine that converts a number into bcd, so
it can be output by the hexadecimal output statement.
How it works, i.e., how to get useful programs from a op= b
The essential statement to be able to do to do interesting
programs is the conditional (given that we have loops).
Since all you can do in the given operation output set is
assignment, we implement "conditional assignment":
if (x) y = z;
To implement this, we constrain x to be either 0 or 1, and
simply compute:
y = (z * x) + (y * (1-x));
This is more obscured by factoring out common terms and restricting
ourselves to two operand operations:
temp = z; (temp == z)
temp -= y; (temp == z-y)
temp *= x; (temp == (z-y)*x)
y += temp; (y == (z-y)*x + y)
( == z*x - y*x + y)
( == z*x + y*(1-x))
Next we imagine we have a pc. "I'm supposed to execute statement
pc next", says our emulator. But suppose we're not currently
coming up on statement pc. To handle this, we simply make every
operation conditional on the pc having the correct value:
if (pc == some_constant) y = z;
To combine this with other operations, we simply multiply by our
(pc == some_constant) flag right after the above 'temp *= x'.
To evaluate pc == some_constant requires one more trick. We assume
that numbers can only be in some limited range. Then we use successive
additions and divisions to reduce that number down to -1, 0, or 1.
You could, for instance, do this by using mod by 2 and div by 2 to
count bits, stopping after, say, 32 iterations. The number you get
is between 0..32, so another 6 iterations on it reduces it to 0..6.
Three iterations on this produces 0..2 (3 would be '7'), and then
two iterations on this produces 0 or 1. Instead I use a shorter
two-divide approach that assumes I'm allowed to use numbers slightly
larger than the numbers I'm operating on.
A similar approach is used to detect positive numbers.
Note that the obvious code to compute y/x will not work correctly,
because every value is computed, even if the pc is not set correctly;
if x is ever 0 when the real C code reaches this computation the
program will die. (This was discovered the hard way.) The solution
is to stick x in a temporary, and if the current code is not about
to be executed, set the temporary to 1.
Thanks to Bill Pugh for bringing the loopability of the AE to
my attention.
babble was originally named 'cb', for obvious reasons, and is
dedicated to the memory of Charles Barrett.
Copyright (c) 1992, Landon Curt Noll & Larry Bassel.
All Rights Reserved. Permission for personal, educational or non-profit use is
granted provided this this copyright and notice are included in its entirety
and remains unaltered. All other uses must receive prior permission in writing
from both Landon Curt Noll and Larry Bassel.
+22
View File
@@ -0,0 +1,22 @@
buzzard.2.README this file
buzzard.2.design description of FIRST (design documentation of THIRD)
third implementation of THIRD in FIRST
help.th online listing of THIRD primitives
FIRST demos: use 'first < {demo}'
demo1.1st prints Hello World! assuming ASCII
THIRD demos: use 'cat third {demo} | first'
demo1.th prints Hello World! regardless of character set
demo2.th demonstrates a simple loop
demo3.th demonstrates a simple if test
demo4.th recursive factorial calculating on the way up
demo5.th recursive factorial calculating on the way down
demo6.th demonstrates switching from compiler to execution mode
Interactive THIRD: use 'cat third - | first'.
To include the primitive on-line help, use
'cat third help.th - | first'.
+61
View File
@@ -0,0 +1,61 @@
#define c m[m[0]++] =
#define z;break;case
char s[5000];
int m[20000]={32},L=1,I,T[500],*S=T,t=64,w,f;
a(x)
{
c L;
L= *m-1;
c t;
c x;
scanf("%s",s+t);
t+=strlen(s+t)+1;
}
r(x)
{
switch(m[x++]){
z 5: for(w=scanf("%s",s)<1?exit(0),0:L;strcmp(s,&s[m[w+1]]);w=m[w]);
w-1 ? r(w+2) : (c 2,c atoi(s))
z 12: I=m[m[1]--]
z 15: f=S[-f]
z 1: c x
z 9: f *=* S--
z 7: m[f]= *S--;
f= *S--
z 0: *++S=f;
f=m[I++]
z 8: f= *S --- f
z 2: m[++m[1]]=I;
I=x
z 11: f=0>f
z 4: *m-=2;c 2
z 6: f=m[f]
z 10: f= *S--/f
z 3: a(1);
c 2
z 13: putchar(f);
f= *S--
z 14: *++S=f;
f=getchar();
}
}
main()
{
a(3);
a(4);
a(1);
w= *m;
c 5;
c 2;
I= *m;
c w;
c I-1;
for(w=6;w<16;)
a(1),c w++;
m[1]= *m;
for(*m+=512;;r(m[I++]));
}
+780
View File
@@ -0,0 +1,780 @@
FIRST & THIRD
almost FORTH
FORTH is a language mostly familiar to users of "small" machines.
FORTH programs are small because they are interpreted--a function
call in FORTH takes two bytes. FORTH is an extendable language--
built-in primitives are indistinguishable from user-defined
_words_. FORTH interpreters are small because much of the system
can be coded in FORTH--only a small number of primitives need to
be implemented. Some FORTH interpreters can also compile defined
words into machine code, resulting in a fast system.
FIRST is an incredibly small language which is sufficient for
defining the language THIRD, which is mostly like FORTH. There are
some differences, and THIRD is probably just enough like FORTH for
those differences to be disturbing to regular FORTH users.
The only existing FIRST interpreter is written in obfuscated C,
and rings in at under 800 bytes of source code, although through
deletion of whitespace and unobfuscation it can be brought to about
650 bytes.
This document FIRST defines the FIRST environment and primitives,
with relevent design decision explanations. It secondly documents
the general strategies we will use to implement THIRD. The THIRD
section demonstrates how the complete THIRD system is built up
using FIRST.
Section 1: FIRST
Environment
FIRST implements a virtual machine. The machine has three chunks
of memory: "main memory", "the stack", and "string storage". When
the virtual machine wishes to do random memory accesses, they come
out of main memory--it cannot access the stack or string storage.
The stack is simply a standard LIFO data structure that is used
implicitly by most of the FIRST primitives. The stack is made up
of ints, whatever size they are on the host machine.
String storage is used to store the names of built-in and defined
primitives. Separate storage is used for these because it allows
the C code to use C string operations, reducing C source code size.
Main memory is a large array of ints. When we speak of
addresses, we actually mean indices into main memory. Main memory
is used for two things, primarily: the return stack and the dictionary.
The return stack is a LIFO data structure, independent of
the abovementioned "the stack", which is used by FIRST to keep
track of function call return addresses.
The dictionary is a list of words. Each word contains a header
and a data field. In the header is the address of the previous word,
an index into the string storage indicating where the name of this
word is stored, and a "code pointer". The code pointer is simply
an integer which names which "machine-language-primitive" implements
this instruction. For example, for defined words the code pointer
names the "run some code" primitive, which pushes the current program
counter onto the return stack and sets the counter to the address of
the data field for this word.
There are several important pointers into main memory. There is
a pointer to the most recently defined word, which is used to start
searches back through memory when compiling words. There is a pointer
to the top of the return stack. There is a pointer to the current
end of the dictionary, used while compiling.
For the last two pointers, namely the return stack pointer and
the dictionary pointer, there is an important distinction: the pointers
themselves are stored in main memory (in FIRST's main memory). This
is critical, because it means FIRST programs can get at them without
any further primitives needing to be defined.
Instructions
There are two kinds of FIRST instructions, normal instructions and
immediate instructions. Immediate instructions do something significant
when they are used. Normal instructions compile a pointer to their
executable part onto the end of the dictionary. As we will see, this
means that by default FIRST simply compiles things.
Integer Operations
Symbol Name Function
- binary minus pop top 2 elements of stack, subtract, push
* multiply pop top 2 elements of stack, multiply, push
/ divide pop top 2 elements of stack, divide, push
<0 less than 0 pop top element of stack, push 1 if < 0 else 0
Note that we can synthesize addition and negation from binary minus,
but we cannot synthesize a time efficient divide or multiply from it.
<0 is synthesizable, but only nonportably.
Memory Operations
Symbol Name Function
@ fetch pop top of stack, treat as address to push contents of
! store top of stack is address, 2nd is value; store to memory
and pop both off the stack
Input/Output Operations
Name Function
echo output top of stack through C's putchar()
key push C's getchar() onto top of stack
_read read a space-delimited word, find it in the
dictionary, and compile a pointer to
that word's code pointer onto the
current end of the dictionary
Although _read could be synthesized from key, we need _read to be able
to compile words to be able to start any syntheses.
Execution Operations
Name Function
exit leave the current function: pop the return stack
into the program counter
Immediate (compilation) Operations
Symbol Name Function
: define read in the next space-delimited word, add it to
the end of our string storage, and generate
a header for the new word so that when it
is typed it compiles a pointer to itself
so that it can be executed.
immediate immediate when used immediately after a name following a ':',
makes the word being defined run whenever
it is typed.
: cannot be synthesized, because we could not synthesize anything.
immediate has to be an immediate operation, so it could not be
synthesized unless by default operations were immediate; but that
would preclude our being able to do any useful compilation.
Stack Operations
Name Function
pick pop top of stack, use as index into stack and copy up
that element
If the data stack were stored in main memory, we could synthesize pick;
but putting the stack and stack pointer in main memory would significantly
increase the C source code size.
There are three more primitives, but they are "internal only"--
they have no names and no dictionary entries. The first is
"pushint". It takes the next integer out of the instruction stream
and pushes it on the stack. This could be synthesized, but probably
not without using integer constants. It is generated by _read when
the input is not a known word. The second is "compile me". When
this instruction is executed, a pointer to the word's data field is
appended to the dictionary. The third is "run me"--the word's data
field is taken to be a stream of pointers to words, and is executed.
One last note about the environment: FIRST builds a very small
word internally that it executes as its main loop. This word calls
_read and then calls itself. Each time it calls itself, it uses
up a word on the return stack, so it will eventually trash things.
This is discussed some more in section 2.
Here's a handy summary of all the FIRST words:
- * / binary integer operations on the stack
<0 is top of stack less than 0?
@ ! read from or write to memory
echo key output or input one character
_read read a word from input and compile a pointer to it
exit stop running the current function
: compile the header of a definition
immediate modify the header to create an immediate word
Here is a sample FIRST program. I'm assuming you're using
the ASCII character set. FIRST does not depend upon ASCII, but
since FIRST has no syntax for character constants, one normally has
to use decimal values. This can be gotten around using getchar, though.
Oh. One other odd thing. FIRST initially builds its symbol table
by calling : several times, so it needs to get the names of the base
symbols as its first 13 words of input. You could even name them
differently if you wanted.
These FIRST programs have FORTH comments in them: they are contained
inside parentheses. FIRST programs cannot have FORTH comments; but I need
some device to indicate what's going on. (THIRD programs are an entirely
different subject.)
( Our first line gives the symbols for the built-ins )
: immediate _read @ ! - * / <0 exit echo key _pick
( now we define a simple word that will print out a couple characters )
: L ( define a word named 'L' )
108 echo ( output an ascii 'l' )
exit
: hello ( define a word named 'hello')
72 echo ( output an ascii 'H' )
101 echo ( output an ascii 'e' )
111 ( push ascii 'o' onto the stack )
L L ( output two ascii 'l's )
echo ( output the 'o' we pushed on the stack before )
10 echo ( print a newline )
exit ( stop running this routine )
: test immediate ( define a word named 'test' that runs whenever typed )
hello ( call hello )
exit
test
( The result of running this program should be:
Hello
)
Section 2: Motivating THIRD
What is missing from FIRST? There are a large number of
important primitives that aren't implemented, but which are
easy to implement. drop , which throws away the top of the
stack, can be implemented as { 0 * + } -- that is, multiply
the top of the stack by 0 (which turns the top of the stack
into a 0), and then add the top two elements of the stack.
dup , which copies the top of the stack, can be easily
implemented using temporary storage locations. Conveniently,
FIRST leaves memory locations 3, 4, and 5 unused. So we can
implement dup by writing the top of stack into 3, and then
reading it out twice: { 3 ! 3 @ 3 @ }.
we will never use the FIRST primitive 'pick' in building THIRD,
just to show that it can be done; 'pick' is only provided because
pick itself cannot be built out of the rest of FIRST's building
blocks.
So, instead of worrying about stack primitives and the
like, what else is missing from FIRST? We get recursion, but
no control flow--no conditional operations. We cannot at the
moment write a looping routine which terminates.
Another glaring dissimilarity between FIRST and FORTH is
that there is no "command mode"--you cannot be outside of a
: definition and issue some straight commands to be executed.
Also, as we noted above, we cannot do comments.
FORTH also provides a system for defining new data types,
using the words [in one version of FORTH] <builds and does> .
We would like to implement these words as well.
As the highest priority thing, we will build control flow
structures first. Once we have control structures, we can
write recursive routines that terminate, and we are ready to
tackle tasks like parsing, and the building of a command mode.
By the way, location 0 holds the dictionary pointer, location
1 holds the return stack pointer, and location 2 should always
be 0--it's a fake dictionary entry that means "pushint".
Section 3: Building THIRD
In this section, I'm going to keep my conversation
indented to this depth, rather than using fake comments--
because we'll have real comments eventually.
The first thing we have to do is give the symbols for our
built-ins.
: immediate _read @ ! - * / < exit echo key _pick
Next we want to be mildly self commenting, so we define
the word 'r' to push the *address of the return stack
pointer* onto the stack--NOT the value of the return
stack pointer. (In fact, when we run r, the value of
the return stack pointer is temporarily changed.)
: r 1 exit
Next, we're currently executing a short loop that contains
_read and recursion, which is slowly blowing up the return
stack. So let's define a new word, from which you can
never return. What it does is drops the top value off
the return stack, calls _read, then calls itself. Because
it kills the top of the return stack, it can recurse
indefinitely.
: ]
r @ Get the value of the return stack pointer
1 - Subtract one
r ! Store it back into the return stack pointer
_read Read and compile one word
] Start over
Notice that we don't need to exit, since we never come
back. Also, it's possible that an immediate word may
get run during _read, and that _read will never return!
Now let's get compile running.
: main immediate ]
main
Next off, I'm going to do this the easy but non-portable
way, and put some character constant definitions in.
I wanted them at the top of the file, but that would have
burned too much of the return stack.
: '"' 34 exit
: ')' 41 exit
: '\n' 10 exit
: 'space' 32 exit
: '0' 48 exit
: '-' 45 exit
: cr '\n' echo exit
Next, we want to define some temporary variables for
locations 3, 4, and 5, since this'll make our code look
clearer.
: _x 3 @ exit
: _x! 3 ! exit
: _y 4 @ exit
: _y! 4 ! exit
Ok. Now, we want to make THIRD look vaguely like FORTH,
so we're going to define ';'. What ; ought to do is
terminate a compilation, and turn control over to the
command-mode handler. We don't have one, so all we want
';' to do for now is compile 'exit' at the end of the
current word. To do this we'll need several other words.
Swap by writing out the top two elements into temps, and
then reading them back in the other order.
: swap _x! _y! _x _y exit
Take another look and make sure you see why that works,
since it LOOKS like I'm reading them back in the same
order--in fact, it not only looks like it, but I AM!
Addition might be nice to have. To add, we need to
negate the top element of the stack, and then subtract.
To negate, we subtract from 0.
: +
0 swap -
-
exit
Create a copy of the top of stack
: dup _x! _x _x exit
Get a mnemonic name for our dictionary pointer--we need
to compile stuff, so it goes through this.
: h 0 exit
We're going to need to advance that pointer, so let's
make a generic pointer-advancing function.
Given a pointer to a memory location, increment the value
at that memory location.
: inc
dup @ Get another copy of the address, and get the value
so now we have value, address on top of stack.
1 + Add one to the value
swap Swap to put the address on top of the stack
! exit Write it to memory
, is a standard FORTH word. It should write the top of
stack into the dictionary, and advance the pointer
: ,
h @ Get the value of the dictionary pointer
! Write the top of stack there
h inc And increment the dictionary pointer
exit
' is a standard FORTH word. It should push the address
of the word that follows it onto the stack. We could
do this by making ' immediate, but then it'd need to
parse the next word. Instead, we compile the next word
as normal. When ' is executed, the top of the return
stack will point into the instruction stream immediately
after the ' . We push the word there, and advance the
return stack pointer so that we don't execute it.
: '
r @ Get the address of the top of return stack
We currently have a pointer to the top of return stack
@ Get the value from there
We currently have a pointer to the instruction stream
dup Get another copy of it--the bottom copy will stick
around until the end of this word
1 + Increment the pointer, pointing to the NEXT instruction
r @ ! Write it back onto the top of the return stack
We currently have our first copy of the old pointer
to the instruction stream
@ Get the value there--the address of the "next word"
exit
Now we're set. ; should be an immediate word that pushes
the address of exit onto the stack, then writes it out.
: ; immediate
' exit Get the address of exit
, Compile it
exit And we should return
Now let's test out ; by defining a useful word:
: drop 0 * + ;
Since we have 'inc', we ought to make 'dec':
: dec dup @ 1 - swap ! ;
Our next goal, now that we have ;, is to implement
if-then. To do this, we'll need to play fast and
loose with the return stack, so let's make some
words to save us some effort.
First we want a word that pops off the top of the normal
stack and pushes it on top of the return stack. We'll
call this 'tor', for TO-Return-stack. It sounds easy,
but when tor is running, there's an extra value on the
return stack--tor's return address! So we have to pop
that off first... We better just bite the bullet and
code it out--but we can't really break it into smaller
words, because that'll trash the return stack.
: tor
r @ @ Get the value off the top of the return stack
swap Bring the value to be pushed to the top of stack
r @ ! Write it over the current top of return stack
r @ 1 + r ! Increment the return stack pointer--but can't use inc
r @ ! Store our return address back on the return stack
;
Next we want the opposite routine, which pops the top
of the return stack, and puts it on the normal stack.
: fromr
r @ @ Save old value
r @ 1 - r ! Decrement pointer
r @ @ Get value that we want off
swap Bring return address to top
r @ ! Store it and return
;
Now, if we have a routine that's recursing, and we
want to be polite about the return stack, right before
we recurse we can run { fromr drop } so the stack won't
blow up. This means, though, that the first time we
enter this recursive routine, we blow our *real* return
address--so when we're done, we'll return up two levels.
To save a little, we make 'tail' mean { fromr drop };
however, it's more complex since there's a new value on
top of the return stack.
: tail fromr fromr drop tor ;
Now, we want to do 'if'. To do this, we need to convert
values to boolean values. The next few words set this
up.
minus gives us unary negation.
: minus 0 swap - ;
If top of stack is boolean, bnot gives us inverse
: bnot 1 swap - ;
To compare two numbers, subtract and compare to 0.
: < - <0 ;
logical turns the top of stack into either 0 or 1.
: logical
dup Get two copies of it
0 < 1 if < 0, 0 otherwise
swap minus Swap number back up, and take negative
0 < 1 if original was > 0, 0 otherwise
+ Add them up--has to be 0 or 1!
;
not returns 1 if top of stack is 0, and 0 otherwise
: not logical bnot ;
We can test equality by subtracting and comparing to 0.
: = - not ;
Just to show how you compute a branch: Suppose you've
compiled a call to branch, and immediately after it is
an integer constant with the offset of how far to branch.
To branch, we use the return stack to read the offset, and
add that on to the top of the return stack, and return.
: branch
r @ Address of top of return stack
@ Our return address
@ Value from there: the branch offset
r @ @ Our return address again
+ The address we want to execute at
r @ ! Store it back onto the return stack
;
For conditional branches, we want to branch by a certain
amount if true, otherwise we want to skip over the branch
offset constant--that is, branch by one. Assuming that
the top of the stack is the branch offset, and the second
on the stack is 1 if we should branch, and 0 if not, the
following computes the correct branch offset.
: computebranch 1 - * 1 + ;
Branch if the value on top of the stack is 0.
: notbranch
not
r @ @ @ Get the branch offset
computebranch Adjust as necessary
r @ @ + Calculate the new address
r @ ! Store it
;
here is a standard FORTH word which returns a pointer to
the current dictionary address--that is, the value of
the dictionary pointer.
: here h @ ;
We're ALL SET to compile if...else...then constructs!
Here's what we do. When we get 'if', we compile a call
to notbranch, and then compile a dummy offset, because
we don't know where the 'then' will be. On the *stack*
we leave the address where we compiled the dummy offset.
'then' will calculate the offset and fill it in for us.
: if immediate
' notbranch , Compile notbranch
here Save the current dictionary address
0 , Compile a dummy value
;
then expects the address to fixup to be on the stack.
: then immediate
dup Make another copy of the address
here Find the current location, where to branch to
swap - Calculate the difference between them
swap ! Bring the address to the top, and store it.
;
Now that we can do if...then statements, we can do
some parsing! Let's introduce real FORTH comments.
find-) will scan the input until it finds a ), and
exit.
: find-)
key Read in a character
')' = Compare it to close parentheses
not if If it's not equal
tail find-) repeat (popping R stack)
then Otherwise branch here and exit
;
: ( immediate
find-)
;
( we should be able to do FORTH-style comments now )
( now that we've got comments, we can comment the rest of the code
in a legitimate [self parsing] fashion. Note that you can't
nest parentheses... )
: else immediate
' branch , ( compile a definite branch )
here ( push the backpatching address )
0 , ( compile a dummy offset for branch )
swap ( bring old backpatch address to top )
dup here swap - ( calculate the offset from old address )
swap ! ( put the address on top and store it )
;
: over _x! _y! _y _x _y ;
: add
_x! ( save the pointer in a temp variable )
_x @ ( get the value pointed to )
+ ( add the incremement from on top of the stack )
_x ! ( and save it )
;
: allot h add ;
: maybebranch
logical ( force the TOS to be 0 or 1 )
r @ @ @ ( load the branch offset )
computebranch ( calculate the condition offset [either TOS or 1])
r @ @ + ( add it to the return address )
r @ ! ( store it to our return address and return )
;
: mod _x! _y! ( get x then y off of stack )
_y _y _x / _x * ( y - y / x * x )
-
;
: printnum
dup
10 mod '0' +
swap 10 / dup
if
printnum
echo
else
drop
echo
then
;
: .
dup 0 <
if
'-' echo minus
then
printnum
'space' echo
;
: debugprint dup . cr ;
( the following routine takes a pointer to a string, and prints it,
except for the trailing quote. returns a pointer to the next word
after the trailing quote )
: _print
dup 1 +
swap @
dup '"' =
if
drop exit
then
echo
tail _print
;
: print _print ;
( print the next thing from the instruction stream )
: immprint
r @ @
print
r @ !
;
: find-"
key dup ,
'"' =
if
exit
then
tail find-"
;
: " immediate
key drop
' immprint ,
find-"
;
: do immediate
' swap , ( compile 'swap' to swap the limit and start )
' tor , ( compile to push the limit onto the return stack )
' tor , ( compile to push the start on the return stack )
here ( save this address so we can branch back to it )
;
: i r @ 1 - @ ;
: j r @ 3 - @ ;
: > swap < ;
: <= 1 + < ;
: >= swap <= ;
: inci
r @ 1 - ( get the pointer to i )
inc ( add one to it )
r @ 1 - @ ( find the value again )
r @ 2 - @ ( find the limit value )
<=
if
r @ @ @ r @ @ + r @ ! exit ( branch )
then
fromr 1 +
fromr drop
fromr drop
tor
;
: loop immediate ' inci @ here - , ;
: loopexit
fromr drop ( pop off our return address )
fromr drop ( pop off i )
fromr drop ( pop off the limit of i )
; ( and return to the caller's caller routine )
: execute
8 !
' exit 9 !
8 tor
;
: :: ; ( :: is going to be a word that does ':' at runtime )
: fix-:: immediate 3 ' :: ! ;
fix-::
( Override old definition of ':' with a new one that invokes ] )
: : immediate :: ] ;
: command
here 5 ! ( store dict pointer in temp variable )
_read ( compile a word )
( if we get control back: )
here 5 @
= if
tail command ( we didn't compile anything )
then
here 1 - h ! ( decrement the dictionary pointer )
here 5 @ ( get the original value )
= if
here @ ( get the word that was compiled )
execute ( and run it )
else
here @ ( else it was an integer constant, so push it )
here 1 - h ! ( and decrement the dictionary pointer again )
then
tail command
;
: make-immediate ( make a word just compiled immediate )
here 1 - ( back up a word in the dictionary )
dup dup ( save the pointer to here )
h ! ( store as the current dictionary pointer )
@ ( get the run-time code pointer )
swap ( get the dict pointer again )
1 - ( point to the compile-time code pointer )
! ( write run-time code pointer on compile-time pointer )
;
: <build immediate
make-immediate ( make the word compiled so far immediate )
' :: , ( compile '::', so we read next word )
2 , ( compile 'pushint' )
here 0 , ( write out a 0 but save address for does> )
' , , ( compile a push that address onto dictionary )
;
: does> immediate
' command , ( jump back into command mode at runtime )
here swap ! ( backpatch the build> to point to here )
2 , ( compile run-code primitive so we look like a word )
' fromr , ( compile fromr, which leaves var address on stack )
;
: _dump ( dump out the definition of a word, sort of )
dup " (" . " , "
dup @ ( save the pointer and get the contents )
dup ' exit
= if
" ;)" cr exit
then
. " ), "
1 +
tail _dump
;
: dump _dump ;
: # . cr ;
: var <build , does> ;
: constant <build , does> @ ;
: array <build allot does> + ;
: [ immediate command ;
: _welcome " Welcome to THIRD.
Ok.
" ;
: ; immediate ' exit , command exit
[
_welcome
+217
View File
@@ -0,0 +1,217 @@
Best Language Tool:
Sean Barrett
Software Construction Company
430 Southwest Parkway, #1906
College Station, TX 77840
USA
Judges' comments:
First:
make first
Second:
echo help | cat third help.th - | first
cat third demo5.th | first
Third:
cat third help.th - | first
Wait until Ok is printed and the type:
2 3 + . cr <-- yes you should really type the 2 letters: cr
Forth:
Sorry, this is third!
Selected notes from the author:
What it does:
first implements a relatively primitive stack machine. How
primitive? It supplies 13 visible primitives: 3 arithmetic,
1 comparison, 2 memory-access, 2 character I/O, 3 primitives
for defining new words, 1 tokenizing, and 1 special stack
operation. (There are also three internal operations for
the stack machine: 'push this integer', 'call this code',
and 'compile a call to this code'.)
It is very difficult to accomplish anything with this set
of primitives, but they do have an interesting property.
This--what this interesting property is, or in other words
what first is good for--is the major obfuscation; there are
also minor source obfuscations, as well as some design tricks
that are effectively obfuscations. Details on the obfuscations
are below, and the interesting property is discussed much
further down.
How to run it:
first expects you to first enter the names of the 13 primitives,
separated by whitespace--it doesn't care what you name them, but
if all the names aren't unique, you won't be able to use some of
them. After this you may type any sequence of valid first input.
Valid first input is defined as any sequence of whitespace-delimited
tokens which consist of primitives, new words you've defined, and
integers (as parsed by "%d"). Invalid input behaves unpredictably,
but gives no warning messages. A sample program, demo1.1st, is
included, but it only works on ASCII systems.
Do not expect to be able to do anything interesting with first.
To do something interesting, you need to feed first the file
third first. In unix, you can do
% cat third help.th - | first
to do this. Hopefully most operating systems will provide a
way to do this. It may take some time for this to complete
(I seem to remember it taking several minutes on an 8086 PC);
THIRD will prompt you when it is finished. The file third has
not been obfuscated, due to sheer kindness on the author's part.
For more information on what you can do once you've piped
THIRD into first, type 'help' and consult FORTH manuals for
further reference. Six sample THIRD programs are included
in the files demo[1-6].th. buzzard.2.README has more
information.
Keep in mind that you are still running first, and
are for the most part limited by first's tokenizer
(notably, unknown words will attempt to be parsed as
integers.) It is possible to build a new parser that
parses by hand, reading a single character at a time;
however, such a parser cannot easily use the existing
dictionary, and so would have to implement its own,
thus requiring reimplementing all of first and third
a second time--I did not care to tackle this project.
Compiling:
first is reasonably portable. You may need to adjust the
size of the buffers on smaller machines; m[] needs to be
at least 2000 long, though.
I say first is portable mainly because it uses native types.
Unlike FORTH, which traditionally allows byte and multi-byte
operations, all operations are performed on C 'int's. That
means first code is only as portable as the same code would
be in C. As in C, the result of dividing -1 by 2 is machine
(or rather compiler) dependent.
How is first obfuscated?
first is obfuscated in several ways. Some minor obfuscations
like &w[&m[1]][s] for s+m[w+1] were in the original source
but are no longer because, apparently, ANSI doesn't allow it
(gcc -ansi -pedantic doesn't mind it, though.)
Other related obfuscations are still present. The top of the
stack is cached in a variable, which increases performance
massively if the compiler can figure out to keep it in a register;
it also obfuscates the code. (Unfortunately, the top of stack
is a global variable and neither gcc nor most bundled compilers
seem to register allocate it.)
More significant are the design obfuscations. m[0] is the
"dictionary pointer", used when compiling words, and m[1] is
the return stack index. Both are used as integer offsets into
m. Both are kept in m, instead of as separate pointers,
because they are then accessible to first programs, which is a
crucial property of first. Similarly the way words are stored
in the dictionary is not obvious, so it can be difficult to
follow exactly what the compiler words are doing.
Assuming you've waded through all that, you still have
to penetrate the most significant obfuscation. Traditionally,
the question is whether a reader can answer the question "what
will this do when I run it". A reader who has deciphered first
to this point may think they know the answer to this question,
but they may not know the answer to the more important question,
"what will this program do when given the right input?" FORTH
afficianados, and especially FORTH implementors, may recognize
the similarity of the internal compiler format to many FORTH
interal representations, and, being aware that FORTH interpreters
can often by self-compiling, may be suspicious that this program
can compile FORTH, or a significant subset of it, or at least be
capable of doing so if fed the right input. Of course, the name
"THIRD" should be a dead giveaway, if the name "first" wasn't.
(These numbers were largely chosed because they were five letters
long, like "FORTH", and would not require truncation to five
letters, which would be a dead giveaway. Besides, THIRD represents
a step backwards, in more ways than one.)
What exactly is first, then?
first is a tiny interpreter which implements a sufficient
pseudo-subset of FORTH to allow it to bootstrap a relatively
complete version of FORTH (based loosely on forth79), which
I call THIRD. Complete relative to what, I'm not sure.
I believe first is close to the smallest amount of code possible
to get this effect *using forth-style primitives*, and still have
some efficiency (it is possible to get by without multiplication
if you have addition, obviously). In the design file, design,
I give a justification for why each primitive in first was included.
THIRD is sorta slow, because first has so few primitives that
many things that are primitives in FORTH (like swap) take a
significant amount of time in THIRD.
When you get the 'Ok.' message from third, try out some sample
FORTH code (first has no way of knowing if keyboard input is
waiting, so it can't actually prompt you in a normal way. It
only prints 'Ok.' after you define a word).
2 3 + . cr ( add 2 and 3, and print it and a newline.)
and THIRD responds
5
Now try:
: test 11 1 do i . loop cr ;
test
and THIRD responds
1 2 3 4 5 6 7 8 9 10
When in THIRD, you can see how much space you're currently
using by typing
here .
The number THIRD replies is the number of machine words (ints)
that the dictionary (the first code) takes up, plus the
512 ints for the return stack. If you compile the basic
THIRD system without the help word (strings take up one
int per character in the string!), you should find that
you're using around 1000 ints (plus the return stack).
Thus THIRD gives you a relatively complete FORTH system in
less than 700 chars of C source + about 1000 ints of
memory--and it's portable too (you could copy over the
THIRD memory dump to another machine, in theory). If the
above numbers seem to you to be mixing apples and oranges
(C source and compiled THIRD code), note that you should
in theory be able to stick the compiled THIRD code into
the C source.
Software Construction Company gets credit for rekindling
my interest in FORTH and thus indirectly inspiring me
to write this program.
Copyright (c) 1992, Landon Curt Noll & Larry Bassel.
All Rights Reserved. Permission for personal, educational or non-profit use is
granted provided this this copyright and notice are included in its entirety
and remains unaltered. All other uses must receive prior permission in writing
from both Landon Curt Noll and Larry Bassel.
+61
View File
@@ -0,0 +1,61 @@
#define c 0 [m] ++ [m] =
#define z;break;case
char s[5000];
int m[20000]={32},L=1,I,T[500],*S=T,t=64,w,f;
a(x)
{
c L;
L= *m-1;
c t;
c x;
scanf("%s",s+t);
t+=strlen(s+t)+1;
}
r(x)
{
switch(x++[m]){
z 5: for(w=scanf("%s",s)<1?exit(0):L;strcmp(s,&w[&m[1]][s]);w=m[w]);
w-1 ? r(w+2) : (c 2,c atoi(s))
z 12: I=1[m]--[m]
z 15: f=S[-f]
z 1: c x
z 9: f *=* S--
z 7: m[f]= *S--;
f= *S--
z 0: *++S=f;
f=I++[m]
z 8: f= *S --- f
z 2: m[++1[m]]=I;
I=x
z 11: f=0>f
z 4: *m-=2;c 2
z 6: f=f[m]
z 10: f= *S--/f
z 3: a(1);
c 2
z 13: putchar(f);
f= *S--
z 14: *++S=f;
f=getchar();
}
}
main()
{
a(3);
a(4);
a(1);
w= *m;
c 5;
c 2;
I= *m;
c w;
c I-1;
for(w=6;w<16;)
a(1),c w++;
m[1]= *m;
for(*m+=512;;r(m[I++]));
}
+12
View File
@@ -0,0 +1,12 @@
: immediate _read @ ! - * / <0 exit echo key _pick
: show echo echo echo echo exit
: all show show show show echo exit
: doit immediate
10 33 100 108 114 111 87
32 111 108 108 101 72
all
exit
doit
+4
View File
@@ -0,0 +1,4 @@
: demo1 " Hello world!
" ;
demo1
+10
View File
@@ -0,0 +1,10 @@
: demo2
10 0 ( iterate from 0 stopping before 10 )
do
i . ( print the loop counter )
loop
cr ( add a newline )
;
demo2
+15
View File
@@ -0,0 +1,15 @@
: printfour
dup ( save the number on top of the stack )
4 = ( compare it to four )
if
" forth " ( output a string for it )
drop ( and delete the saved value )
else
.
endif
;
: demo3 10 0 do i printfour loop cr ;
demo3
+30
View File
@@ -0,0 +1,30 @@
( compute factorial recursively )
( take x as input, return x! and x as output )
: fact-help
dup if
1 - ( leave x-1 on top )
fact-help ( leave x-1, [x-1]! )
1 + ( leave x, [x-1]!, x )
swap over swap ( leave [x-1]!, x, x )
* ( into x!, x )
swap ( into x, x! )
else
1 swap
then
;
: fact
fact-help
drop
;
: demo4
" 4 factorial is: " 4 fact . cr
" 6 factorial is: " 6 fact . cr
;
demo4
+27
View File
@@ -0,0 +1,27 @@
( recursive factorial. given x on top, followed by )
( an "accumulator" containing the product except for x! )
: fact-help2
dup if
swap over swap
*
swap 1 -
fact-help2
then
;
: fact
1 swap
fact-help2
drop
;
: demo5
" The factorial of 3 is: " 3 fact . cr
" The factorial of 5 is: " 5 fact . cr
;
demo5
+18
View File
@@ -0,0 +1,18 @@
: foobar
2
[ 2 , ( '[' turns the compiler off, allowing us to execute code )
1 1 1 + + , ( and we compile in-line a 2 and a three )
( the '2' means 'push the number following this' )
]
+ . cr
;
foobar
: 'foobar ' foobar ; ( ' can only be run inside the compiler )
( ' leaves the address of the following word
on the stack )
'foobar . cr
'foobar dump
+45
View File
@@ -0,0 +1,45 @@
#include <stdio.h>
long a
[4],b[
4],c[4]
,d[0400],e=1;
typedef struct f{long g
,h,i[4] ,j;struct f*k;}f;f g,*
l[4096 ]; char h[256],*m,k=3;
long n (o, p,q)long*o,*p,*q;{
long r =4,s,i=0;for(;r--;s=i^
*o^*p, i=i&*p|(i|*p)&~*o++,*q
++=s,p ++);return i;}t(i,p)long*p
;{*c=d [i],n(a,c,b),n(p,b,p);}u(j)f*j;{j->h
=(j->g =j->i[0]|j->i[1]|j->i[2]|j->i[3])&4095;}v(
j,s)f* j; {int i; for(j->k->k&&v(j->k, ' '),fseek(
stdin, j->j, 0);i=getchar(),putchar(i-'\n'?i:s),i-
'\n';);}w(o,r,j,x,p)f*o,*j;long p;{f q;int
s,i=o->h;q.k=o;r>i?j=l[r=i]:r<i&&
(s=r&~i)?(s|=s>>1, s|=s
>>2,s|=s>>4,s
|=s>>8
,j=l[r
=((r&i
|s)&~(s>>1))-1&i]):0;--x;for
(;x&&!(p&i);p>>=1);for(;!x&&j;n(o->i,j->i,q.
i),u(&q),q.g||(q.j=j->j,v(&q,'\n')),j=j->k);for(;x;j=x
?j->k:0){for(;!j&&((r=(r&i)-1&i)-i&&(r&p)?2:(x=0));j=l[r]);!
x||(j->g&~o->g)||n (o->i,j->i,q.i)||(
u(&q), q.j=j ->j,q.g?w(&q
,r,j->k,x ,p):v(&q,
'\n')); }}y(){f
j;char *z,*p;
for(;m ? j.j=
ftell( stdin)
,7,(m= gets(m ))||w(
&g,315 *13,l[ 4095]
,k,64* 64)&0: 0;n(g
.i,j.i, b)||(u (&j),j.
k=l[j.h],l[j.h]= &j,y())){for(z= p=h;*z&&(
d[*z++]||(p=0)););for(z=p?n(j.i ,j.i,j.i)+h:"";
*z;t(*z++,j.i));}}main(o,p)char** p; {for(;m = *++p;)for(;*m-
'-'?*m:(k= -atoi(m))&0;d[*m]||(d[*m ]=e,e<<=1),t(*m++,g.i)); u(&
g),m=h
,y();}
+235
View File
@@ -0,0 +1,235 @@
Most Humorous Output:
Andreas Gustafsson
Helsinki University of Technology
Arentikuja 1 D 305 (home address)
00410 Helsinki
FINLAND
Judges' comments:
To make:
make ag
Determine where your system dictionary is located. You may find
it located in one of the following places:
/usr/dict/words
/usr/share/lib/spell/words
/usr/ucblib/dict/words
/dev/null <-- for machines with nothing to say
Then using the proper dictionary:
ag free software foundation < /usr/dict/words
ag obfuscated c contest < /usr/dict/words
ag unix international < /usr/dict/words
ag george bush < /usr/dict/words
ag bill clinton < /usr/dict/words
ag ross perot < /usr/dict/words
ag paul e tsongas < /usr/dict/words
Recently some newspapers printed amusing anagrams of one of the
names listed above. Run this program to find the anagrams they
weren't allowed to print!
Selected notes from the author:
The name of the game:
AG is short for either Anagram Generator or simply AnaGram.
It might also be construed to mean Alphabet Game, and by pure
coincidence it happens to be the author's initials.
What it does:
AG takes one or more words as arguments, and tries to find
anagrams of those words, i.e. words or sentences containing
exactly the same letters.
How to use it:
To run AG, you need a dictionary file consisting of distinct words
in the natural language of your choice, one word on each line. If
your machine doesn't have one already, you can make your own
dictionary by concatenating a few hundred of your favourite Usenet
articles and piping them through the following obfuscated shell
script:
#!/bin/sh
z=a-z];tr [A-Z\] \[$z|sed s/[\^$z[\^$z*/_/g|tr _ \\012|grep ..|sort -u
Using articles from alt.folklore.computers is likely to make
a more professional-looking dictionary than rec.arts.erotica.
AG must be run with the dictionary file as standard input.
Because anagrams consisting of just a few words are generally more
meaningful than those consisting of dozens of very short words, the
number of words in the anagrams is limited to 3 by default. This
limit can be changed using a numeric command line option, as in
"ag -4 international obfuscated c code contest </usr/dict/words".
Bugs:
- There is no error checking
- Standard input must be seekable, so you can't pipe the dictionary
into AG.
- The input sentence and each line in the dictionary may contain
at most 32 distinct letters, and each letter may occur at most 15
times.
- Words in the dictionary may be at most 255 bytes long
- AG cannot handle characters that sign-extend to negative values
- Although AG works on both 16-bit and 32-bit machines,
the size of the problems it can solve is severely limited
on machines that limit the stack size to 64k or less.
Obfuscatory notes:
As you can see, AG takes advantage of the new '92 whitespace rules to
achieve a clear, readable, self-documenting layout. The identifiers
have been chosen in a way appropriate for an alphabet game, and common
sources of bugs such as goto statements and malloc/free have been
eliminated. As AG also refrains from abusing the preprocessor, it
doesn't really have much to offer in terms of "surface obfuscation".
Instead, it tries to achieve both its speed and its obscurity through a
careful choice of algorithms. Some of the finer points of those
algorithms are outlined in the rot-13 encoded spoiler below.
How it works: (ROT13 to read)
Urer sbyybjf n qrfpevcgvba bs fbzr bs gur qngn fgehpgherf naq
nytbevguzf hfrq ol NT. Vg vf ol ab zrnaf pbzcyrgr, ohg vg znl uryc
lbh trg na vqrn nobhg gur trareny cevapvcyrf.
--
Vagreanyyl, NT ercerfragf jbeqf naq fragraprf nf neenlf bs 32
4-ovg vagrtre ryrzragf. Rnpu ryrzrag ercerfragf gur ahzore bs
gvzrf n yrggre bpphef va gur jbeq/fragrapr. Gurer ner 32 ryrzragf
orpnhfr 32 vf n pbairavrag cbjre bs gjb ynetre guna gur ahzore bs
yrggref va zbfg jrfgrea nycunorgf, naq gur ryrzragf ner 4 ovgf
rnpu orpnhfr gur fnzr yrggre vf hayvxryl gb bpphe zber guna 15
gvzrf va n cenpgvpny nantenz trarengvba ceboyrz.
Gurfr 32*4-ovg neenlf ner npghnyyl fgberq va zrzbel va n
"ovg-genafcbfrq" sbezng, nf neenlf bs sbhe "ybat" inyhrf. Vg vf
nffhzrq gung n "ybat" vf ng yrnfg 32 ovgf. Gur svefg 4-ovg yrggre
pbhag vf sbezrq ol gur yrnfg fvtavsvpnag (2^0) ovg va rnpu bs gur
sbhe ybatf, gur arkg bar vf sbezrq ol gur 2^1 ovgf, rgp.
Guvf fgbentr sbezng znxrf vg cbffvoyr gb nqq be fhogenpg gjb fhpu
irpgbef bs 32 4-ovg inyhrf va cnenyyry ol fvzhyngvat n frg bs 32
ovanel shyy nqqref va fbsgjner hfvat ovgjvfr ybtvpny bcrengvbaf.
R.t., nyy gur YFO:f bs gur erfhyg ner sbezrq va cnenyyry ol gnxvat
gur rkpyhfvir BE bs gur YFO:f va rnpu fhzznaq, naq 32 pneel ovgf
ner sbezrq va cnenyyry va n fvzvyne jnl hfvat n ybtvpny NAQ.
Guhf, 32 vaqrcraqrag 4-ovg nqqvgvbaf pna or cresbezrq ol whfg sbhe
vgrengvbaf bs n ybbc pbagnvavat fbzr 32-ovg ovgjvfr ybtvpny
bcrengvbaf, ohg ab nevguzrgvp bcrengvbaf bgure guna gubfr vzcyvrq
ol neenl vaqrkvat.
Fhogenpgvba jbexf fvzvyneyl, naq va snpg NT bayl vzcyrzragf
fhogenpgvba qverpgyl, unaqyvat nqqvgvba ol zrnaf bs gur vqragvgl
n+o = n-(0-o).
Va nqqvgvba gb guvf 32*4-ovg ercerfragngvba, NT nyfb sbezf n fb-pnyyrq
"fvtangher" gung vf gur ovgjvfr BE bs gur sbhe ybatf, juvpu vf
rdhvinyrag gb fnlvat gung gur fvtangher bs n jbeq pbagnvaf n ybtvpny 1
va gur ovg cbfvgvbaf pbeerfcbaqvat gb yrggref bppheevat ng yrnfg bapr
va gung jbeq.
Gur svefg guvat NT qbrf vf gb pbafgehpg n ybbxhc gnoyr bs 256
ybatf, bar sbe rnpu 8-ovg punenpgre inyhr. Gur ragel sbe n
punenpgre jvyy or mreb vs gung punenpgre qbrfa'g nccrne va gur
fragrapr tvira ba gur pbzznaq yvar, be vg jvyy unir n fvatyr ovg
frg vs gur punenpgre qbrf nccrne va gur fragrapr. Ol nqqvat
gbtrgure gur ovg znfxf sbe nyy gur yrggref va gur vachg fragrapr
hfvat gur genafcbfr nqqvgvba zrgubq qrfpevorq nobir, NT sbezf gur
32*4 ovg neenl ercerfragngvba bs gur vachg fragrapr.
Gur arkg npgvba cresbezrq vf ernqvat gur qvpgvbanel. Gubfr jbeqf gung
pbagnva yrggref abg va gur vachg fragrapr ner vzzrqvngryl qvfpneqrq.
Jbeqf pbagnvavat gur evtug yrggref ohg va rkprffvir ahzoref ner
ryvzvangrq va n frcnengr purpx vaibyivat gur 32*4 ovg neenl.
Gur erznvavat jbeqf, juvpu jvyy or ersreerq gb nf "pnaqvqngr jbeqf",
ner fgberq va 32*4-ovg ercerfragngvba, gbtrgure jvgu gurve fvtangherf
naq bssfrgf vagb gur qvpgvbanel svyr fb gung gur cynva-grkg irefvba bs
n jbeq pna yngre or sbhaq sbe cevagvat. Guvf vasbezngvba vf xrcg va n
ybpny "fgehpg" va gur qvpgvbanel-ernqvat shapgvba, naq zrzbel vf
nyybpngrq sbe rnpu pnaqvqngr jbeq fvzcyl ol znxvat nabgure erphefvir
pnyy gb gung shapgvba.
Rnpu fgehpg fb nyybpngrq vf yvaxrq vagb n svkrq-fvmr unfu gnoyr bs
4096 ragevrf vaqrkrq ol gur 12 ybj ovgf bs gur jbeq'f fvtangher.
Jura gur qvpgvbanel-ernqvat shapgvba rapbhagref raq-bs-svyr, nyy gur
pnaqvqngr jbeqf unir orra fgberq va arfgrq npgvingvba erpbeqf ba gur
fgnpx, npprffvoyr guebhtu gur unfu gnoyr.
Trarengvat gur nantenzf vf gura qbar ol genirefvat gur unfu gnoyr naq
fhogenpgvat gur yrggref bs rnpu jbeq va gur unfu gnoyr sebz gur
"pheerag fragrapr", juvpu vavgvnyyl vf gur fragrapr tvira ba gur
pbzznaq yvar.
Gur fhogenpgvba vf cresbezrq va cnenyyry ba gur 4-ovg yrggre pbhagf
nf qrfpevorq nobir, naq vs nyy 32 erfhygf ner mreb, na nantenz unf
orra sbhaq. Vs gur erfhyg vf artngvir sbe bar be zber bs gur yrggref
(nf vaqvpngrq ol bar be zber "1" va n irpgbe bs 32 obeebj ovgf
erghearq ol gur fhogenpgvba ebhgvar), gur jbeq qvq abg zngpu gur
pheerag fragrapr naq vf vtaberq. Svanyyl, vs gur erfhyg pbagnvarq
bayl abaartngvir yrggre pbhagf, jr unir sbhaq n cnegvny nantenz:
n jbeq pbagnvavat fbzr, ohg abg nyy, bs gur yrggref va gur pheerag
fragrapr. Va guvf pnfr jr erphefviryl gel gb svaq na nantenz bs gur
erznvavat yrggref. Gur qrcgu bs gur erphefvba vf yvzvgrq gb gur
znkvzhz ahzore bs jbeqf va gur nantenz, nf fcrpvsvrq ol gur hfre.
Jura gur qrrcrfg erphefvba yriry unf orra ernpurq, na bcgvzvmngvba pna
or nccyvrq: orpnhfr ab shegure erphefvba jvyy or qbar, gurer vf ab
arrq gb ybbx sbe cnegvny nantenzf, naq gurersber NT bayl arrqf gb
purpx sbe jbeqf gung pbagnva rknpgyl gur fnzr yrggref nf gur pheerag
fragrapr. Gubfr jbeqf pna or sbhaq fvzcyl ol vaqrkvat gur unfu gnoyr
jvgu gur fvtangher bs gur pheerag fragrapr.
Rira jura abg ba gur qrrcrfg erphefvba yriry, NT trarenyyl nibvqf
rknzvavat nyy gur ragevrf bs gur unfu gnoyr. Gur vqrn vf gung jr ner
abg vagrerfgrq va unfu ohpxrgf jubfr jbeqf pbagnva nal yrggref abg
va gur pheerag fragrapr; gurfr ohpxrgf ner rknpgyl gubfr jubfr vaqrk
unf n ybtvpny bar va n ovg cbfvgvba jurer gur fvtangher bs gur pheerag
fragrapr unf n mreb. Chg nabgure jnl, jr jnag gb ybbc guebhtu bayl
gubfr unfu ohpxrg vaqvprf "v" gung pbagnva mrebrf va nyy gur ovg
cbfvgvbaf jurer gur fvtangher "f" bs gur pheerag fragrapr pbagnvaf
n mreb; guvf pna or rkcerffrq va P nf (v & ~f == 0).
Vg vf cbffvoyr gb ybbc guebhtu nyy fhpu ahzoref va na rssvpvrag jnl ol
gnxvat nqinagntr bs pregnva cebcregvrf bs ovanel nevguzrgvp: ol
sbepvat gur ovgf pbeerfcbaqvat gb mrebrf va "f" gb barf, jr pna znxr
gur pneevrf trarengrq va vaperzragvat "v" cebcntngr fgenvtug npebff
gubfr ovgf gung fubhyq erznva mreb. Sbe rknzcyr, gur sbyybjvat
cebtenz cevagf nyy gubfr 16-ovg vagrtref gung pbagnva mrebrf va nyy
rira ovg cbfvgvbaf:
znva(){vag v=0,f=0kNNNN;qb{cevags("%04k\g",v);}juvyr(v=((v|~f)+1)&f);}
NT hfrf n fvzvyne zrgubq ohg jbexf va gur bccbfvgr qverpgvba, svaqvat
gur arkg ybjre inyhr jvgu mrebrf va tvira ovg cbfvgvbaf ol cebcntngvat
obeebjf npebff gubfr ovgf. Fbzr nqqvgvbany nqwhfgzragf ner znqr
gb gur unfu gnoyr vaqrk jura vavgvngvat n erphefvir frnepu, hfvat
fvzvyne ovg-gjvqqyvat grpuavdhrf.
Jurarire na nantenz unf orra sbhaq, vg vf cevagrq ol genirefvat n
yvaxrq yvfg sbezrq ol fgehpgf va gur npgvingvba erpbeqf bs gur
erphefvir vaibpngvbaf bs gur frnepu shapgvba, frrxvat gb gur ortvaavat
bs gur jbeq zngpurq ol gung vaibpngvba, naq pbclvat gur punenpgref bs
gur jbeq qverpgyl sebz fgnaqneq vachg gb fgnaqneq bhgchg.
Copyright (c) 1992, Landon Curt Noll & Larry Bassel.
All Rights Reserved. Permission for personal, educational or non-profit use is
granted provided this this copyright and notice are included in its entirety
and remains unaltered. All other uses must receive prior permission in writing
from both Landon Curt Noll and Larry Bassel.
+531
View File
@@ -0,0 +1,531 @@
9th International Obfuscated C Code Contest Guidelines, Hints and Comments
Copyright (c) 1992, Landon Curt Noll & Larry Bassel.
All Rights Reserved. Permission for personal, educational or non-profit use is
granted provided this this copyright and notice are included in its entirety
and remains unaltered. All other uses must receive prior permission in writing
from both Landon Curt Noll and Larry Bassel.
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.
WHAT IS NEW IN 1992:
The size rules are different this year. There is a more relaxed
rule to encourage formatting styles beyond rectangular blobs of C
code. The build file (how to compile) has been expanded as well.
See the rules, and OUR LIKES AND DISLIKES for details.
The entry format is better (for us anyway). The program mkentry.c
provides a convenient way to form an entry. See ENTRY FORMAT.
The original entry source, build and resulting binary should be
treated as read-only. There is a provision to allow entries to
modify these files indirectly. See ENTRY FORMAT.
This year, we are experimenting with a new category of programs:
X clients. X client entries should be as portable as possible.
See OUR LIKES AND DISLIKES.
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
* If it is ANSI, convert 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
* lint it
* compile it
* 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 do well under all, or in most 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.
If you do plan to abuse the rules, we suggest that you let us know
in the remarks section. Please note that an invitation to abuse
is not an invitation to break. We are strict when it comes to the
3217 byte size limit. Also, abusing the entry format tends to
annoy more than amuse.
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.
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
int i;
j; <-- don't use such implicit type declarations
int k;
We suggest that you use ANSI C compilers if possible. If you must
use non-ANSI C, such as K&R C, try to avoid areas that give ANSI C
compilers problems.
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 for one liners
in our books.
We tend to dislike programs that:
* are very hardware specific
* are very OS or Un*x 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 under both BSD or SYS V Un*x
* abusing 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 :-)
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.
We allowed whitespace, and in certain cases ; { or } do not impact
your program size (up to a certain point), because we want to get
away from source that is simply a compact blob of characters.
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'
program. We are amazed at the many different sizes that claim
to be the smallest. There is nothing wrong with self-replicating
programs. In fact, a number of winners have been self-replicating.
You might want to avoid the claim of 'smallest', lest we (or others)
know of a smaller one!
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 ask that such X client
entries restrict themselves to only the low level Xlib and the
Athena widget set (libX11.a, libXaw.a, libXmu.a and libXt.a).
Don't use M*tif, Xv*ew, or OpenL*ok toolkits, since not everyone
has them. Avoid depending on a particular window manager. Not
everyone has X11r5, and some people are stuck back in X11r3 (or
earlier), so try to target X11r4 without requiring X11r4. Better
yet, try to make your entry run on all version 11 X Window Systems.
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. Better yet, give an xrdb -merge
command as part of the build.
We like programs that:
* are as concise and small as they need to be
* do something at least quasi-interesting
* pass lint without complaint (not a requirement, but it is nice)
* are portable
* are unique or novel in their obfuscation style
* MAKE USE OF A NUMBER OF DIFFERENT TYPES OF OBFUSCATION
* make us laugh and/or throw up :-)
Some types of programs can't excel in some areas. Of course, your
program doesn't have to excel in all areas, but doing well in several
areas really does help.
We freely admit that interesting, creative or humorous comments in
the ---remark--- section helps your chance of winning. If you had to
read of many twisted entries, you too would enjoy a good laugh or two.
We think the readers of the contest winners do as well.
Be creative!
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.
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:
---entry---
rule: 1992
title: chonglab
entry: 0
date: Mon Feb 17 13:58:57 1992
host: Un*x v6, pdp11/45
2.9BSD, pdp11/70
---remark---
This is a non-obfuscated obfuscated C program.
It is likely not to win a prize. But what do you expect from
a short example! (yes, Hello world progs have become old too)
---author---
name: Landon Curt Noll
org: IOCCC Judging Group
addr: Toad Hall
San Francisco, CA 94101
USA
email: {chongo,noll}@{toad,sgi}.com
anon: n
---author---
name: Larry Bassel
org: IOCCC Judging Group
addr: Toad Hall
San Francisco, CA 94101
USA
email: hoptoad!sun!lab
lab@sun.com
anon: n
---info---
begin 444 info.file
M2&$A("!792!G;W0@>6]U('1O(&QO;VLA"@I4:&%T('1H870@:7,L(&ES+@I4
M:&%T('1H870@:7,@;F]T+`H@("`@:7,@;F]T('1H870@=&AA="!N;W0@:7,N
M"E1H870@:7,L('1H870@=&AA="!I<R!N;W0L(&ES(0H*"0DM+2!C:&]N9V\@
%,3DW-`H@
`
end
---build---
begin 444 build
28V,@<')O9RYC("UO('!R;V<*
`
end
---program---
begin 444 prog.c
C;6%I;B@I>W!R:6YT9B@B2&5L;&\L('=O<FQD(5QN(BD[?0H`
`
end
---end---
Where build uudecodes into:
cc prog.c -o prog
and prog.c uudecodes into:
main(){printf("Hello, world!\n");}
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.
If the above entry somehow won the 'least likely to win' award,
we would use chonglab.c and chonglab.
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 need special binary
or rm -f special_src.c need special source
cp prog.c special_src.c
cc special_src.c -o special_name
or rm -f special_build need 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 ---data--- 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.
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
lengthly 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.
JUDGING PROCESS:
Entries are judged by Larry Bassel and Landon Curt Noll.
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 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 Usenix 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, 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
shipping over any #include files
* performing a number of C beautify/cleanup edits on the source
* passing the beautified source thru the C pre-processor
shipping over any #include files
In later rounds, other actions are performed:
* linting the source
* compiling/building the source
* running the program
* performing misc 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 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 entry that failed to win on a
previous year. There have been winners that lost in a previous
year. Of course, in those cases, improving on the entry made
the difference!
More often that 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 entry. More often, the
'best' is picked because it does well in a number of categories.
ANNOUNCEMENT OF WINNERS:
The first announcement, occurs at a Summer Usenix conference. By
tradition, this is done during the latter part of the UUNET/IOCCC BOF.
Winning entries will be posted in late July/Aug to the following groups:
comp.lang.c comp.unix.wizards alt.sources
In addition, pointers to these postings are posted to the following
comp.sources.d alt.sources.d misc.misc
comp.sources.misc
Winning entries will be deposited into the uunet archives. See
below for details.
Often, winning entries are published in magazines such as "The C Users
Journal". Winners have appeared in books ("The New Hackers Dictionary")
and on various 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:
...!{apple,pyramid,sun,uunet}!hoptoad!judges (not the address for
judges@toad.com submitting entries)
Questions and comments about the contest are welcome.
One may obtain a copy of the current rules, guidelines or mkentry
program may be obtained from the judges using the Email address above.
See the official IOCCC web site:
http://www.ioccc.org
for more updated information.
chongo <Landon Curt Noll> /\cc/\ {chongo,noll}@{toad,sgi}.com
Larry Bassel {uunet,ucbvax,cbosgd}|sun!lab
+54
View File
@@ -0,0 +1,54 @@
: help key ( flush the carriage return form the input buffer )
" The following are the standard known words; words marked with (*) are
immediate words, which cannot be used from command mode, but only in
word definitions. Words marked by (**) declare new words, so are always
followed by the new word.
! @ fetch, store
+ - * / mod standard arithmetic operations
= < > <= >= standard comparison operations
not boolean not of top of stack
logical turn top of stack into 0 or 1
dup over duplicate the top of stack or second of stack
swap drop reverse top two elements or drop topmost
inc dec increment/decrement the value at address from stack
add add a value from 2nd of stack into address from top
echo key output character from, or input to, top of stack
. # print out number on top of stack without/with cr
cr print a carriage return
[more]" key
" (**) var declare variable with initial value taken from stack
(**) constant declare constant with initial value taken from stack
(**) array declare an array with size taken from stack
(*) if...else...then FORTH branching construct
(*) do...loop FORTH looping construct
i j loop values (not variables)
print print the string pointed to on screen
(*)(**) : declare a new THIRD word
(*) <build does> declare a data types compile-time and run-time
(*) ; terminate a word definition
[more]" key
" Advanced words:
here current location in dictionary
h pointer into dictionary
r pointer to return stack
fromr tor pop a value from or to the return stack
, write the top of stack to dictionary
' store the address of the following word on the stack
allot leave space on the dictionary
:: compile a ':' header
[ switch into command mode
] continue doing : definitions
" ;
+55
View File
@@ -0,0 +1,55 @@
#include <stdio.h>
#include <malloc.h>
#define ext(a) (exit(a),0)
#define I " .:\';+<?F7RQ&%#*"
#define a "%s?\n"
#define n "0?\n"
#define C double
#define o char
#define l long
#define L sscanf
#define i stderr
#define e stdout
#define r ext (1)
#define s(O,B) L(++J,O,&B)!=1&&c>++q&&L(v[q],O,&B)!=1&&--q
#define F(U,S,C,A) t=0,*++J&&(t=L(J,U,&C,&A)),(!t&&c>++q&&!(t=L(v[q],U,\
&C,&A)))?--q:(t<2&&c>++q&&!(t=L(v[q],S,&A))&&--q
#define T(E) (s("%d",E),E||(fputs(n,i),r))
#define d(C,c) (F("%lg,%lg","%lg",C,c)))
#define O (F("%d,%d","%d",N,U),(N&&U)||(fputs(n,i),r)))
#define D (s("%lg",f))
#define E putc
C
G=0,
R
=0,Q,H
,M,P,z,S
=0,x=0
, f=0;l b,j=0, k
=128,K=1,V,B=0,Y,m=128,p=0,N
=768,U=768,h[]={0x59A66A95,256
,192,1,6912,1,0,0},t,A=0,W=0,Z=63,X=23
;o*J,_;main(c,v)l c;o**v;{l q=1;for(;;q<
c ?(((J=v[q])[0]&&J[0]<48&&J++,((_= *J)<99||
_/2== '2'||(_-1)/3=='\"'||_==107||_/05*2==','||_
>0x074)?( fprintf(i,a,v[q]),r):_>0152?(_/4>27?(_&1?(
O,Z=N,X=U): (W++,N=Z,U=X)):_&1?T(K):T(k)):_>103?(d(G,
R ),j=1):_&1? d(S,x):D,q++),q--,main(c-q,v+q)):A==0?(A=
1,f||(f=N/4.),b=(((N-1)&017)<8),q=(((N+7)>>3)+b)*U,(J=malloc(q)
)||(perror("malloc"),r),S-=(N/2)/f,x+=(U/2)/f):A==1?(B<U?(A=2,V
= 0,Q=x-B/f,j ||(R=Q),W&&E('\n',e),E(46,i)):(W&&E('\n',
e),E('\n',i ),h[1]=N,h[2]=U,h[4]=q,W||(fwrite(h,1,32,
e),fwrite (J,1,q,e)),free(J),ext(0))):A==2?(V<N?(j?
(H=V/f +S,M=Q):(G=V/f+S,H=M=0),Y=0,A=03):((m&0x80
) ||(m=0x80,p++),b&&(J[p++]=0),A=1,B++)):((Y
<k&&(P=H*H)+(z=M*M)<4.)?(M=2*H*M+R,H=P-z
+G,Y++):(W&&E(I[0x0f*(Y&K)/K],e),Y&K?J
[p]&=~m:(J[p]|=m),(m>>=1)||/*/
(m=128,u--),A==6?ext(1):B<u
. e=3,l=2*c*/( m
=0x80,
p++),V++
,A=0x2
)
));
}
+133
View File
@@ -0,0 +1,133 @@
Best Output:
Ian Collier
Oxford University
The Queen's College
High Street
OXFORD
OX1 4AW
ENGLAND
Judges' comments:
Make and run.
The program is more interesting to run on workstations that can
make use of a Sun raster file. Others can make use of the -text
flag for character oriented output.
Of course, the source (layout) is self-documenting! :-)
NOTE: The original winning source imc.orig.c assumed that
exit returned a value which cause problems for some
systems where exit returned a void. The file imc.c
avoids this problem.
Selected notes from the author:
Portability
This program depends upon the ASCII character set, and makes certain
assumptions about the architecture. It naughtily declares the first
argument to main as a long, and passes a pointer to long instead of char
to fwrite, giving a length value of 32 bytes for an array of 8 longs. I
guess that makes this program OK on most flavours of unix, but not on
PCs.
About the program
This program has several parameters; each of them has a default, so the
program runs happily without any parameters. If you supply an incorrect
parameter, an obfuscated error message results! :-) Should you want to
run the program without knowing what it does, then supplying the single
letter t as a parameter is a good move. Otherwise, direct the output
into a file. The resulting file is most useful on Sun OS, where the
"file" command will tell you what to do with it. For best results with
the t option, you may want to change the definition of the I macro :-)
Details appear later, though the formatting of the code is a large clue.
All the code in this program appears between the ";" and ")" in
"for(;;)". That isn't because I want to win the best one-liner, but
merely because it makes the code so much more impenetrable :-) In fact
running a pretty printer on the code hardly improves it at all. This
program has the obligatory macros with unmatched parentheses, and the
cleverly arranged macro names and parameters to spell out "Ian Colliers
Obfuscated C Code". If you expand macros, bear in mind that the more
complex ones are best left as macros, because they have well-defined and
nontrivial (IMHO) functions. These macros help to give the program's
parameter format its flexibility. The parameters are sorted out in a
unique way (based on an idea by Pete Bevin) which hides very effectively
their identities (and I think that using a variable called _ adds a nice
touch to the illegibility of the code). In this section of the code, the
data types of the numbers checked against is varied, and just because
you see a ',' doesn't mean it has anything to do with commas! So I hope
you will agree that this program is more than a little obfuscated...
This is a Mandelbrot/Julia drawer. Normally it produces a monochrome
Sun-format raster file. The version of xloadimage we have is able to
view such files, and so is Sun's screenload command. [Note: the header
contains eight 4-byte integers, the byte order in which depends upon the
machine. On Sun workstations they are stored MSB first].
The program may be asked to produce text output instead of a raster
file. Then the characters defined in the I macro will be used to create
up to 16 different shades of grey. Quite a respectable picture can be
gained by printing a 130x110 output on a dot matrix 132 column printer
with the linefeed set to 7 points. Text output also gives a good picture
when used in an X window with small characters having a square aspect
ratio.
The options accepted by the program follow. Each option is a letter; it
may be preceded with a minus sign (or any character in [!-/]) and may be
followed by other letters, so for example
m -m mask *mail
all mean the same thing. Most options may be followed by one or two
numbers. These numbers may be separated from each other and from the
option by a space, or may be joined to each other with a comma, or may
be appended to the single-letter option, so
-s100,200 size 100,200 -size123 100 200 s100 200
all mean the same (note that in "-size123" all characters following the
initial s are ignored). Numbers need not be specified, as each has a
default value. In all cases except "j" and "t", and "s" whenever it
appears before "t", specifying an option without numbers has no effect.
(specifying "-s -t" has the effect of producing text with the default
raster size; not a good idea!). The options are:
-centre x y (float x,y) Centre the picture at x+iy in the complex
plane (default x=0 y=0)
-factor f (float f) Use f pixels per unit of the plane (default
f=x/4 where x is the width)
-julia x y (float x,y) Draw a julia set. Use x+iy as the constant
to add after squaring (default x=0 y=0)
-limit l (int l) Use l iterations maximum (default l=128)
-mask m (int m) Use m as a mask in deciding the colour of each
pixel (see below) (default m=1)
-size x y (int x,y) Produce an x-by-y output (default for raster
x=768 y=768; default for text x=63 y=23)
-text Produce text instead of raster.
The colour of each point is determined by taking the bit-and of the
number of iterations and the mask. For a raster, the point is black
(1-bit) if the result is zero, white otherwise. For text, the result of
the operation determines the grey-ness of the character produced, with a
blank for zero going up to a star for the maximum value. For a
four-colour picture, for example, use a mask with two bits set (e.g. 3),
and for a 16-colour picture use a mask with four bits set (e.g. 15). For
a picture with coarse detail, use a mask which ends with several zero
bits (e.g. 8).
While the program is creating your picture, it displays dots on the
standard error to indicate its progess (one dot per pixel line).
Here are a couple of good pictures to draw:
imc -s 512,512 -f 600000 -l 512 -m 16 -c.00805,.74274 > screen1.ras
imc -s512,512 -j-.523,-.535 > screen2.ras
Copyright (c) 1992, Landon Curt Noll & Larry Bassel.
All Rights Reserved. Permission for personal, educational or non-profit use is
granted provided this this copyright and notice are included in its entirety
and remains unaltered. All other uses must receive prior permission in writing
from both Landon Curt Noll and Larry Bassel.
+54
View File
@@ -0,0 +1,54 @@
#include <stdio.h>
#include <malloc.h>
#define I " .:\';+<?F7RQ&%#*"
#define a "%s?\n"
#define n "0?\n"
#define C double
#define o char
#define l long
#define L sscanf
#define i stderr
#define e stdout
#define r exit (1)
#define s(O,B) L(++J,O,&B)!=1&&c>++q&&L(v[q],O,&B)!=1&&--q
#define F(U,S,C,A) t=0,*++J&&(t=L(J,U,&C,&A)),(!t&&c>++q&&!(t=L(v[q],U,\
&C,&A)))?--q:(t<2&&c>++q&&!(t=L(v[q],S,&A))&&--q
#define T(E) (s("%d",E),E||(fputs(n,i),r))
#define d(C,c) (F("%lg,%lg","%lg",C,c)))
#define O (F("%d,%d","%d",N,U),(N&&U)||(fputs(n,i),r)))
#define D (s("%lg",f))
#define E putc
C
G=0,
R
=0,Q,H
,M,P,z,S
=0,x=0
, f=0;l b,j=0, k
=128,K=1,V,B=0,Y,m=128,p=0,N
=768,U=768,h[]={0x59A66A95,256
,192,1,6912,1,0,0},t,A=0,W=0,Z=63,X=23
;o*J,_;main(c,v)l c;o**v;{l q=1;for(;;q<
c ?(((J=v[q])[0]&&J[0]<48&&J++,((_= *J)<99||
_/2== '2'||(_-1)/3=='\"'||_==107||_/05*2==','||_
>0x074)?( fprintf(i,a,v[q]),r):_>0152?(_/4>27?(_&1?(
O,Z=N,X=U): (W++,N=Z,U=X)):_&1?T(K):T(k)):_>103?(d(G,
R ),j=1):_&1? d(S,x):D,q++),q--,main(c-q,v+q)):A==0?(A=
1,f||(f=N/4.),b=(((N-1)&017)<8),q=(((N+7)>>3)+b)*U,(J=malloc(q)
)||(perror("malloc"),r),S-=(N/2)/f,x+=(U/2)/f):A==1?(B<U?(A=2,V
= 0,Q=x-B/f,j ||(R=Q),W&&E('\n',e),E(46,i)):(W&&E('\n',
e),E('\n',i ),h[1]=N,h[2]=U,h[4]=q,W||(fwrite(h,1,32,
e),fwrite (J,1,q,e)),free(J),exit(0))):A==2?(V<N?(j?
(H=V/f +S,M=Q):(G=V/f+S,H=M=0),Y=0,A=03):((m&0x80
) ||(m=0x80,p++),b&&(J[p++]=0),A=1,B++)):((Y
<k&&(P=H*H)+(z=M*M)<4.)?(M=2*H*M+R,H=P-z
+G,Y++):(W&&E(I[0x0f*(Y&K)/K],e),Y&K?J
[p]&=~m:(J[p]|=m),(m>>=1)||/*/
(m=128,u--),A==6?exit(1):B<u
. e=3,l=2*c*/( m
=0x80,
p++),V++
,A=0x2
)
));
}
+39
View File
@@ -0,0 +1,39 @@
#include <X11/Xlib.h>
#define ext(a) (exit(a),0)
# define X( x,v,y) XMoveWindow(d,s[x],(v)*z,(y)*z)
# define _ ButtonPressMask|ButtonReleaseMask
# define I( x,y) XSelectInput(d,s[x],y)
# define N( v) (XMapWindow(d,s[v]),v)
# define V VisibilityChangeMask
# define A XCreateSimpleWindow
# define D DefaultScreen(d)
# define E r.xbutton.button
# define R BlackPixel(d,D)
# define S r.xvisibility
int main(a)int a;{Window s[53];int w,u,i,c,y,l=0
,q,e=32,t,k,j=~0,z=(a+1)/2,x=a&1,v=z&1;XEvent r;Display*
d=XOpenDisplay("");s[0]=A(d,DefaultRootWindow(d),200,200,(x&
v?330:120)*z,215*z,2,R,R);I(N(c=0),_);for(;c<(x?32:52);c++){s[
c+1]=A(d,s[0],x ?c*20*z:(c-1)%10 *12*z,x?-20*z:(
c-1)/10*12*z,x ?z*(c^31?10: 2):z*10*(c?1:2
), x& v?z*10: (c &&!x?10:1+ x) *z,k =q=1, R,
WhitePixel(d ,D));I (N(c+1), V);}X( N(1),y=(x&v)
*115+50,x*70+ 60 ); X(N(c-- )+ 1,x?-10:(i=y)
,u=!x*130-20); while(c &&e< 160){if(x){if(
v){l=!(e &32)*9; for(w=30; w--;){ if(s[w+2]){ k=w%
10;l=e&32?k>l?k:l:k<l?k:l;X(w+2,10+k *20+q,(w/10)*20+e);}}l*=20;
e&31?e++:e&32?(q++,(q+l>300?e++:0)):(q--,q+l<10?e++:0); } u>140?
ext(c):u>-20?X(32,i,u-=(v?5:-1 )) :(!v?(u =5,srandom(time(0)),i=
random()%88+6):0); } else{k>0?i+=(i>105?k= -k:k):(i+=(i<1?k= -k:
k)); j>0?u +=(u>140?ext(++c):j):(u+=(u <1?j= -j:j
)); X( 52,i,u);}XSync(d,0); while(
XCheckMaskEvent(d ,_|V,&r))if(!(r. type==ButtonPress
?(E&1||!x||!v?t=E*4-8 :u<0?i=y+4,u=122:1):r
.type==ButtonRelease&&E?t=0,1:r.type^VisibilityNotify|S.state^1)
)for(x&v?(u= -15),w++:(w=0);++w <52-x*20;)if
(s[w] ==S.window)x&&v|| w ^1?
XUnmapWindow (d,s[w]) ,s[w]=0,c--:
0,l=1; if(!x&&l)j= -j,l=0; if(l&x&&!v
)u=~19,c--,l=0;t=(!x||!v) &&(y<5&&t<0||y>95&&t>0)?0
:t;s[1]?X(1,y+=x&v?t:t/(x+1),130):ext(++c);};return(c);}
+103
View File
@@ -0,0 +1,103 @@
Best X Program:
Tero Kivinen
Helsinki University of Technology
Klovinrinne 6b
02180 Espoo
Finland
Judges' comments:
If your machine support the X Window System, Version 11:
make kivinen
The type of entertainment depends on number of arguments
you have with the program. :-)
NOTE: Some systems do not need (or have) -lsocket -lresolv -lnsl.
Such systems should compile using -lX11.
NOTE: The original winning source kivinen.orig.c assumed that
exit returned a value which cause problems for some
systems where exit returned a void. The file kivinen.c
avoids this problem.
Selected notes from the author:
X Entertainment Kit
This kit includes three games from the early of video games for
The X Window System Version 11 Release 5. It should work with
earlier releases, though.
Space Invaders
The classic game of shooting aliens from outer space, trying to
exterminate all life on earth. The game ends when the first line
of aliens touches the ground, or destroy you. To win the game you
must destroy all the aliens. If you evade out from the screen you
lose.
Controls:
Button 1 = Move left
Button 2 = Fire missile
Button 3 = Move right
Breakout
Break all the bricks with the ball, using your paddle. If you miss
the ball the game ends.
Controls:
Button 1 = Move left
Button 3 = Move right
Dropout
Catch all the falling pieces, before they reach the ground. If you
miss it, game ends. To win you must catch all 30 pieces.
Controls:
Button 1 = Move left
Button 3 = Move right
Starting the game
The type of the game is determined by the number of arguments
given to the program.
no arguments = Space Invaders
1 argument = Breakout
2 arguments = Dropout
3 arguments = double sized Breakout
4 arguments = triple sized Space Invaders
5 arguments = triple sized Breakout
6 arguments = double sized Dropout
7 arguments = quadruple sized Breakout
and so on...
Scores
The exit value of the game is your score. The smaller the score
the better it is. The exit value of zero means you have won.
Features
The game has a cheat system, which can be found after examining the
event loop at the end of program. It is not a bug, it's a feature!
Copyright (c) 1992, Landon Curt Noll & Larry Bassel.
All Rights Reserved. Permission for personal, educational or non-profit use is
granted provided this this copyright and notice are included in its entirety
and remains unaltered. All other uses must receive prior permission in writing
from both Landon Curt Noll and Larry Bassel.
+38
View File
@@ -0,0 +1,38 @@
#include <X11/Xlib.h>
# define X( x,v,y) XMoveWindow(d,s[x],(v)*z,(y)*z)
# define _ ButtonPressMask|ButtonReleaseMask
# define I( x,y) XSelectInput(d,s[x],y)
# define N( v) (XMapWindow(d,s[v]),v)
# define V VisibilityChangeMask
# define A XCreateSimpleWindow
# define D DefaultScreen(d)
# define E r.xbutton.button
# define R BlackPixel(d,D)
# define S r.xvisibility
int main(a)int a;{Window s[53];int w,u,i,c,y,l=0
,q,e=32,t,k,j=~0,z=(a+1)/2,x=a&1,v=z&1;XEvent r;Display*
d=XOpenDisplay("");s[0]=A(d,DefaultRootWindow(d),200,200,(x&
v?330:120)*z,215*z,2,R,R);I(N(c=0),_);for(;c<(x?32:52);c++){s[
c+1]=A(d,s[0],x ?c*20*z:(c-1)%10 *12*z,x?-20*z:(
c-1)/10*12*z,x ?z*(c^31?10: 2):z*10*(c?1:2
), x& v?z*10: (c &&!x?10:1+ x) *z,k =q=1, R,
WhitePixel(d ,D));I (N(c+1), V);}X( N(1),y=(x&v)
*115+50,x*70+ 60 ); X(N(c-- )+ 1,x?-10:(i=y)
,u=!x*130-20); while(c &&e< 160){if(x){if(
v){l=!(e &32)*9; for(w=30; w--;){ if(s[w+2]){ k=w%
10;l=e&32?k>l?k:l:k<l?k:l;X(w+2,10+k *20+q,(w/10)*20+e);}}l*=20;
e&31?e++:e&32?(q++,(q+l>300?e++:0)):(q--,q+l<10?e++:0); } u>140?
exit(c):u>-20?X(32,i,u-=(v?5:-1)):(!v?(u =5,srandom(time(0)),i=
random()%88+6):0); } else{k>0?i+=(i>105?k= -k:k):(i+=(i<1?k= -k:
k)); j>0?u +=(u>140?exit(++c):j):(u+=(u <1?j= -j:j
)); X( 52,i,u);}XSync(d,0); while(
XCheckMaskEvent(d ,_|V,&r))if(!(r. type==ButtonPress
?(E&1||!x||!v?t=E*4-8 :u<0?i=y+4,u=122:1):r
.type==ButtonRelease&&E?t=0,1:r.type^VisibilityNotify|S.state^1)
)for(x&v?(u= -15),w++:(w=0);++w <52-x*20;)if
(s[w] ==S.window)x&&v|| w ^1?
XUnmapWindow (d,s[w]) ,s[w]=0,c--:
0,l=1; if(!x&&l)j= -j,l=0; if(l&x&&!v
)u=~19,c--,l=0;t=(!x||!v) &&(y<5&&t<0||y>95&&t>0)?0
:t;s[1]?X(1,y+=x&v?t:t/(x+1),130):exit(++c);};return(c);}
+167
View File
@@ -0,0 +1,167 @@
#define f 000:
char
*s,*
t,v;
char
_ [
999]
,x [
999]
,*p=
x ;
char
*av[
]= {
"W",
"H",
"o",
"l",
"N",
"e",
" ",
"r",
"d",
".",
"m",
"s",
"g",
"!",
"*",
"\n"
} ;
int
n= 0
;int
__ =
0,i=
000;
main
() {
#define f 001:
#define F 042:
#define f 100:
_[i--
#define f 126:
#define f 132:
#define f 103:
#define f 202:
#define f 666:
#define f 77::
#define f 101:
]=0
#define f 232:
#define f 151:
;if(
#define f 256:
!i){
puts
("I"
"BM"
" S"
"UX"
);;;
;;;}
;for
( ;
gets
(_);
) {
for(
#define f 301:
t=_,
#define f 700:
#define f 999:
s=t,
#define f 77 :
#define f 300:
s=t;
#define f s=t;
#define f 123:
#define f 127:
*t&&
!(!(
*t <
'0'
||*t
>'9'
)&&!
((t[
1] ^
':')
&&(t
[1]^
'.')
)) ;
t++)
#define f 137:
#define f 133:
;if(
#define f 111:
#define f 220:
v^*t
&&*t
){v=
*t;;
n=n*
2+(1
&*t)
;__=
(__+
1)&3
; __
||((
n<15
&&(*
p= *
av[n
] ),
#define f 2+2:
p++)
,n=0
);}}
#define f ==4:
;*p=
'\0'
;;;;
#define f puts
puts
(x);
s=t;
#define f s=5;
s=t;
#define f s=5:
s=t;
#define f 445:
#define f 113:
#define f 900:
s=t;
#define f n22:
#define f n40:
s=t;
#define f nn6:
s=t;
#define f nn1:
#define f 0:--
s=t;
#define f 19:-
#define f x2:x
s=t;
#define f x1:x
s=t;
#define f y2:x
#define f y7:y
s=t;
#define f 1:::
s=t;
#define f @3:@
#define f 10:0
#define f x+1:
s=t;
#define f 2:::
#define f 3:::
#define x 7:::
#define y 3:::
#define z 990:
#define Z 47::
;;;}
+34
View File
@@ -0,0 +1,34 @@
Worst Abuse of the C Preprocessor:
Ed Luke
Mississippi State University
P.O. Box 6176
Mississippi State, MS 39762, USA
Judges' comments:
To setup:
make lush
Try:
make lush.again 2>&1 | lush (sh or ksh users)
or:
make lush.again |& lush (csh users)
The program uses error messages issued by the C Proproessor to
generate its message to the world. One program's error is another
program's data!
Selected notes from the author:
This program is yet another "Hello World." program with a twist. The
string Hello World has been encoded in the error messages the compiler
generates when compiling the source.
Copyright (c) 1992, Landon Curt Noll & Larry Bassel.
All Rights Reserved. Permission for personal, educational or non-profit use is
granted provided this this copyright and notice are included in its entirety
and remains unaltered. All other uses must receive prior permission in writing
from both Landon Curt Noll and Larry Bassel.
+167
View File
@@ -0,0 +1,167 @@
#define f 000:
char
*s,*
t,v;
char
_ [
999]
,x [
999]
,*p=
x ;
char
*av[
]= {
"W",
"H",
"o",
"l",
"N",
"e",
" ",
"r",
"d",
".",
"m",
"s",
"g",
"!",
"*",
"\n"
} ;
int
n= 0
;int
__ =
0,i=
000;
main
() {
#define f 001:
#define F 042:
#define f 100:
i--[
#define f 126:
#define f 132:
#define f 103:
#define f 202:
#define f 666:
#define f 77::
#define f 101:
_]=0
#define f 232:
#define f 151:
;if(
#define f 256:
!i){
puts
("I"
"BM"
" S"
"UX"
);;;
;;;}
;for
( ;
gets
(_);
) {
for(
#define f 301:
t=_,
#define f 700:
#define f 999:
s=t,
#define f 77 :
#define f 300:
s=t;
#define f s=t;
#define f 123:
#define f 127:
*t&&
!(!(
*t <
'0'
||*t
>'9'
)&&!
((t[
1] ^
':')
&&(t
[1]^
'.')
)) ;
t++)
#define f 137:
#define f 133:
;if(
#define f 111:
#define f 220:
v^*t
&&*t
){v=
*t;;
n=n*
2+(1
&*t)
;__=
(__+
1)&3
; __
||((
n<15
&&(*
p= *
av[n
] ),
#define f 2+2:
p++)
,n=0
);}}
#define f ==4:
;*p=
'\0'
;;;;
#define f puts
puts
(x);
s=t;
#define f s=5;
s=t;
#define f s=5:
s=t;
#define f 445:
#define f 113:
#define f 900:
s=t;
#define f n22:
#define f n40:
s=t;
#define f nn6:
s=t;
#define f nn1:
#define f 0:--
s=t;
#define f 19:-
#define f x2:x
s=t;
#define f x1:x
s=t;
#define f y2:x
#define f y7:y
s=t;
#define f 1:::
s=t;
#define f @3:@
#define f 10:0
#define f x+1:
s=t;
#define f 2:::
#define f 3:::
#define x 7:::
#define y 3:::
#define z 990:
#define Z 47::
;;;}
+78
View File
@@ -0,0 +1,78 @@
#include <stdio.h>
#include <curses.h>
#define ST strchr
#define SRD srand48
#define RD lrand48
#define ext(a) (exit(a),0)
#define Q return
#define W wrefresh(r)
typedef int i;
#define Z(d,a) (RD()%((a)-(d)+1)+(d))
i f[3][3] = {15,52,36,20,-39,48,60,0,-25};
char z[6][6];
#define Y(x) (4*(x)+3)
#define X(x) (2*(x)+1)
#define I for
WINDOW *r=NULL;
#define K endwin()
char *g ="\
Use l-h-k-j for move.\nUse + for increment. Use - for decrement.\nUse Q to quit.";
i (*d())();
nt()
{
long time();
SRD(time((i *)0));
memset(z,5,36);
initscr();
cbreak();
noecho();
nonl();
if (COLS<80||LINES<24)
K,ext(1);
if (!(r=newwin(X(6),Y(6),
(LINES-X(6))/2,(COLS-Y(6))/2)))
K,ext(1);
mvaddstr(LINES-5,0,g);
refresh();
}
i ci()
{
i x,y=0;
I (;y<6;++y)
I(x=0;x<6;++x)
mvwaddch(r,X(y),Y(x),z[x][y]+'0'); Q(0);
}
void main()
{
char *ST();
i a=0,b=0,c,q,t,s,x,sc=0;
i(*(*p)())()=(nt(),d);
I(x=0 ; x++<20; )d(Z(0,5),Z(0,5),Z(1,2));
I(t=Z(0,2),q=s=0; q<3; s+=f[q][t]*f[q++][t]);
I(box(r,'|','-'),ci(),wmove(r,X(a),Y(b)),
W; (ST ("+-Qlkjh",(char)(c=wgetch(r))))&&
((i)((i)(q^=s%=Y(q),s/=2)!=(i)(s^=q)&&c&64&&(!(c&7|0)&&--b<0&&
(b=q^s)&0|| c&4&&++b==6&&c&4<(~b&23?q^=s,b^=b
:b&12?b=3:b|2)||c&2&&~c&1&&++a==++q/2+1&&c&16>(
!a|12?a=7,a&=~a:a|4?a=2:a&2)||~c&4&&c&
1&&--a<0&&(a+=6)&0)||~c&64&&(**p(b,a,~c))()||
c&16)?K,ext(0):1)||c; sc==36?ci(),W,K,ext(0):wmove(r,X(a),Y(b)),
W)
I(t=Z(0,2),q=s=0; q<3; s+=f[q][t]*f[q++][t])
I(sc=0; sc<36&&*((char *)z+sc++)==5; );
}
i (*d(a,b,c))()i a,b,c;
{
i x,y;
I(x=a>0?a-1:0; x<=(a<5?a+1:5); ++x)
I(y=b>0?b-1:0; y<=(b<5?b+1:5); ++y)
if(x==a&&y==b&&z[x][y]==(c&2?1:9)||z[x][y]==(c&2?9:1)&&(x!=a||y!=b))Q(ci);
I(x=a>0?a-1:0; x<=(a<5?a+1:5); x++)
I(y=b>0?b-1:0; y<=(b<5?b+1:5)&&(x==a&&y==b&&(z[x][y]+=(c&2?-1:1))||(z[x][y]+=(c&2?1:-1))); y++); Q(ci);
}
+40
View File
@@ -0,0 +1,40 @@
Best Game:
Marangoni Andrea
Department of Computer Science at Milano
Via Pausula, 72
62014 Corridonia (MC)
Italy
Judges' comments:
Make and run.
The object is to refill the table with 5's, by incrementing
or decrementing numbers as needed. It is the side effects
that get you into trouble. If you are not careful, you may
find things "at 6's and 7's". :-)
NOTE: Some compilers have had trouble optimizing this entry.
NOTE: Some systems need to compile with -ltermcap as well as -lcurses.
NOTE: The original winning source marangon.orig.c assumed that
exit returned a value which cause problems for some
systems where exit returned a void. The file marangon.c
avoids this problem.
Selected notes from the author:
It starts off by creating a table with number 5 in all places. The
CPU melts the numbers and you must return them in original state.
When you increase a number, all the other eight numbers next to it
decrease and vice-versa.
Copyright (c) 1992, Landon Curt Noll & Larry Bassel.
All Rights Reserved. Permission for personal, educational or non-profit use is
granted provided this this copyright and notice are included in its entirety
and remains unaltered. All other uses must receive prior permission in writing
from both Landon Curt Noll and Larry Bassel.
+77
View File
@@ -0,0 +1,77 @@
#include <stdio.h>
#include <curses.h>
#define ST strchr
#define SRD srand48
#define RD lrand48
#define Q return
#define W wrefresh(r)
typedef int i;
#define Z(d,a) (RD()%((a)-(d)+1)+(d))
i f[3][3] = {15,52,36,20,-39,48,60,0,-25};
char z[6][6];
#define Y(x) (4*(x)+3)
#define X(x) (2*(x)+1)
#define I for
WINDOW *r=NULL;
#define K endwin()
char *g ="\
Use l-h-k-j for move.\nUse + for increment. Use - for decrement.\nUse Q to quit.";
i (*d())();
nt()
{
long time();
SRD(time((i *)0));
memset(z,5,36);
initscr();
cbreak();
noecho();
nonl();
if (COLS<80||LINES<24)
K,exit(1);
if (!(r=newwin(X(6),Y(6),
(LINES-X(6))/2,(COLS-Y(6))/2)))
K,exit(1);
mvaddstr(LINES-5,0,g);
refresh();
}
i ci()
{
i x,y=0;
I (;y<6;++y)
I(x=0;x<6;++x)
mvwaddch(r,X(y),Y(x),z[x][y]+'0'); Q(0);
}
void main()
{
char *ST();
i a=0,b=0,c,q,t,s,x,sc=0;
i(*(*p)())()=(nt(),d);
I(x=0 ; x++<20; )d(Z(0,5),Z(0,5),Z(1,2));
I(t=Z(0,2),q=s=0; q<3; s+=f[q][t]*f[q++][t]);
I(box(r,'|','-'),ci(),wmove(r,X(a),Y(b)),
W; (ST ("+-Qlkjh",(char)(c=wgetch(r))))&&
((i)((i)(q^=s%=Y(q),s/=2)!=(i)(s^=q)&&c&64&&(!(c&7|0)&&--b<0&&
(b=q^s)&0|| c&4&&++b==6&&c&4<(~b&23?q^=s,b^=b
:b&12?b=3:b|2)||c&2&&~c&1&&++a==++q/2+1&&c&16>(
!a|12?a=7,a&=~a:a|4?a=2:a&2)||~c&4&&c&
1&&--a<0&&(a+=6)&0)||~c&64&&(**p(b,a,~c))()||
c&16)?K,exit(0):1)||c; sc==36?ci(),W,K,exit(0):wmove(r,X(a),Y(b)),
W)
I(t=Z(0,2),q=s=0; q<3; s+=f[q][t]*f[q++][t])
I(sc=0; sc<36&&*((char *)z+sc++)==5; );
}
i (*d(a,b,c))()i a,b,c;
{
i x,y;
I(x=a>0?a-1:0; x<=(a<5?a+1:5); ++x)
I(y=b>0?b-1:0; y<=(b<5?b+1:5); ++y)
if(x==a&&y==b&&z[x][y]==(c&2?1:9)||z[x][y]==(c&2?9:1)&&(x!=a||y!=b))Q(ci);
I(x=a>0?a-1:0; x<=(a<5?a+1:5); x++)
I(y=b>0?b-1:0; y<=(b<5?b+1:5)&&(x==a&&y==b&&(z[x][y]+=(c&2?-1:1))||(z[x][y]+=(c&2?1:-1))); y++); Q(ci);
}
+1188
View File
File diff suppressed because it is too large. Load diff
+26
View File
@@ -0,0 +1,26 @@
#include <stdio.h>
static char *text[] =
{
"Export of this program from the USA is governed by the US",
"Munitions List from the ITAR (International Traffic in Arms",
"Regulations). This list gives the specific categories of",
"restricted exports and includes cryptographic exports. Traffic",
"entirely external to, entirely internal to, or into the USA is",
"not restricted.",
"To obtain a copy of the program, email to nathan@inmos.co.uk",
"with a subject \"IOCCC request\". If you know that your 'From'",
"line is incorrect, add a single line",
"\"replyto you@your.correct.address\" to the body of the message.",
"A deamon will autoreply.",
"WARNING: You must not re-export this out of the USA, or else",
"the men in black might get you.",
NULL
};
int main()
{
char **ptr;
for(ptr = text; *ptr; ptr++)
printf("%s\n", *ptr);
return 0;
}
+118
View File
@@ -0,0 +1,118 @@
Worst Abuse of the Rules:
Nathan Sidwell
Inmos UK
1000 Aztec West
Almondsbury
Bristol
UK BS12 4SQ
Judges' comments:
The US International Traffic in Arms Regulations controls certain
exportations going out of the United States. The U.S. Munitions
List gives the specific categories of restricted exports. Because
this entry appears to fall under this restricted catagory, the
judges may not be able to distribute winners outside of the USA.
Nathan Sidwell has stated that he is willing to distribute the
winning source. To read HIS instructions of how to obtain his
winning program:
make nathan
nathan
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-=-= The text below assumes that you have the winning source =-=-=
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
To use:
make nathan
Try:
nathan obfuscate < nathan.c > foobarf.c
nathan - obfuscate < foobarf.c > barfoof.c
diff nathan.c barfoof.c
WARNING:
The judges' make no claim as to the strength or security
of this program. It is likely to be nil, or the next
best thing to it. Still, you might consider installing
it in /usr/games/nathan. :-)
NOTE:
The 'winning' catagory is also open to question. One could say
that it is a 'file obfuscator'. One could also say that it
unintentionally adbused the intent of rule #7 (that programs
should be freely redistributable). We suspect that the author
may not have intended to do this, but that is the way things go
sometimes.
BTW, 'abuse of the rules' entries do not violate the rules.
Entries that violate the rules are disqualified. Abuse of the
rules entries are ones that tend to 'streach' the limits and
take the contest into unexpected territory.
Personal note from chongo:
I think this situation shows just how ridiculous US crypto
regulations really are. Certain US federal officials can get away
with shipping arms to certain nations in apparent violation of US
laws, but I personally can't re-distribute a program contest winner
to the network!
Selected notes from the author:
PROGRAM USE
This program is a hello world text encrypter/decrypter. It uses an
enigma (I think) style encryption algorithm, where the encryption
key character is modified by a value, determined from the previous
character. Non-printable characters (those with ASCII values < ' '
or > 0x7e) are passed unaltered, thus any kind of file may be
successfully procesed, but if the original is printable, the
processed file will be too. The input is read from stdin, and the
output presented to stdout. The key, a text string, is presented as
a command argument. This is optional, and if ommitted, the file is
self-{de,en}crypted. To specify decryption, a "-" should be given
before the key. (Actually encryption and dycryption proper inverse
operations, so you can use decrypt to scramble and encrypt to
descramble, if you're perverse.)
PORTABILITY (A little knowledge is a dangerous thing)
Its written in ANSI C, and doesn't even assume an ASCII character
set, (it has an array of the characters to convert), so should be
portable across many platforms. It passes gcc -ansi -pedantic -O
-Wall with no warnings (You may get assignment in conditional
warnings on other platforms though). Because I've heard that
conditional jumps slow down fast processors, I've eliminated all
the ifs from the code, indeed, as its only one statement, it should
compile to one instruction an a suitably designed CISC machine. To
speed compilation, there is only one statement in the loop, so that
another scoping level does not need to be opened.
Being an encrypter/decrypter, you probably want the source code to
be obfuscated, to hide the algorithm.
OBFUSCATION
Inspite of the fact that it looks like a nice friendly hello world
program, it isn't (as documented above). (Short lines have been padded,
as you'll find if you look at an encrypted copy of the source.)
I've also named some of the macros from commonly used functions,
just to keep things muddy. Of course, all the variables are
misnamed. The program is kept simply (one for statement), by
serious overuse of , and ? :. These are really confusing when used
together, nested or put in argument lists (is that a comma
operator, or argument separator?)
Copyright (c) 1992, Landon Curt Noll & Larry Bassel.
All Rights Reserved. Permission for personal, educational or non-profit use is
granted provided this this copyright and notice are included in its entirety
and remains unaltered. All other uses must receive prior permission in writing
from both Landon Curt Noll and Larry Bassel.
+176
View File
@@ -0,0 +1,176 @@
9th International Obfuscated C Code Contest Rules
Copyright (c) 1992, Landon Curt Noll & Larry Bassel.
All Rights Reserved. Permission for personal, educational or non-profit use is
granted provided this this copyright and notice are included in its entirety
and remains unaltered. All other uses must receive prior permission in writing
from both Landon Curt Noll and Larry Bassel.
Obfuscate: tr.v. -cated, -cating, -cates. 1. a. To render obscure.
b. To darken. 2. To confuse: Their emotions obfuscated their
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. :-)
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) Your entry must be <= 3217 bytes in length. The number of characters
excluding whitespace (tab, space, newline), and excluding any ; { or }
followed by either whitespace or end of file, must be <= 1536.
3) Your entry must be submitted in the following format:
---entry---
rule: 1992
title: title of entry (see comments below)
entry: Entry number from 0 to 7 inclusive
date: Date/time of submission (use the format of the date command)
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 ok.
---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.
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 if 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 255 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 expression: [a-zA-Z0-9_+=,][a-zA-Z0-9_+=,.-]*
and must be 1 to 10 characters in length.
It is suggested, but not required, that the title should
incorporate your username; in the case of multiple authors,
consider using parts of the usernames of the authors.
* All text outside of the above format will be kept confidential,
unless otherwise stated. Notes about an author of a winning entry
will be published unless 'y' was given to that 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 entry's remarks should include:
- 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 ---data--- files
- why you think the program is obfuscated
- note if this entry is a re-submission of a previous entry.
- any other remarks (humorous or otherwise)
* 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.
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) Your entry must be written in C. Use of ANSI C is preferred. Use
of common C (K&R + extensions) is permitted, as long as it does not
cause major problems for ANSI C compilers.
7) The program must be of original work. All programs must be in the
public domain. All copyrighted programs will be rejected.
8) Entries must be received prior to 09-May-92 0:00 UTC. (UTC is
essentially equivalent to Greenwich Mean Time) Email your entries to:
...!{apple,pyramid,sun,uunet}!hoptoad!obfuscate
obfuscate@toad.com
We request that your message use the subject 'ioccc entry'.
If possible, we request that you hold off on Emailing your entries
until 1-Mar-92 0:00 UTC. Early entries will be accepted, however.
We will attempt to email a confirmation to the the first author for
all entries received after 1-Mar-92 0:00 UTC.
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.
Compiling an entry produce a file (or files) which may be executed.
FOR MORE INFORMATION:
The Judging will be done by Landon Noll and Larry Bassel. Please send
questions or comments (but not entries) about the contest, to:
...!{apple,pyramid,sun,uunet}!hoptoad!judges
judges@toad.com
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. The IOCCC rules, guidelines and mkentry
program may be obtained from the judges using the Email address above.
See the official IOCCC web site:
http://www.ioccc.org
for more updated information.
chongo <Landon Curt Noll> /\cc/\ hoptoad!chongo
Larry Bassel {uunet,ucbvax,cbosgd}|sun!lab
+367
View File
@@ -0,0 +1,367 @@
: immediate _read @ ! - * / <0 exit echo key _pick
: debug immediate 1 5 ! exit
: r 1 exit
: ] r @ 1 - r ! _read ]
: _main immediate r @ 7 ! ]
_main
: _x 3 @ exit
: _y 4 @ exit
: _x! 3 ! exit
: _y! 4 ! exit
: swap _x! _y! _x _y exit
: + 0 swap - - exit
: dup _x! _x _x exit
: inc dup @ 1 + swap ! exit
: h 0 exit
: , h @ ! h inc exit
: ' r @ @ dup 1 + r @ ! @ exit
: ; immediate ' exit , exit
: drop 0 * + ;
: dec dup @ 1 - swap ! ;
: tor r @ @ swap r @ ! r @ 1 + r ! r @ ! ;
: fromr r @ @ r @ 1 - r ! r @ @ swap r @ ! ;
: tail fromr fromr drop tor ;
: minus 0 swap - ;
: bnot 1 swap - ;
: < - <0 ;
: logical dup 0 < swap minus 0 < + ;
: not logical bnot ;
: = - not ;
: branch r @ @ @ r @ @ + r @ ! ;
: computebranch 1 - * 1 + ;
: notbranch
not
r @ @ @
computebranch
r @ @ +
r @ !
;
: here h @ ;
: if immediate ' notbranch , here 0 , ;
: then immediate dup here swap - swap ! ;
: ')' 0 ;
: _fix key drop key swap 2 + ! ;
: fix-')' immediate ' ')' _fix ;
fix-')' )
: find-) key ')' = not if tail find-) then ;
: ( immediate find-) ;
( we should be able to do FORTH-style comments now )
( this works as follows: ( is an immediate word, so it gets
control during compilation. Then it simply reads in characters
until it sees a close parenthesis. once it does, it exits.
if not, it pops off the return stack--manual tail recursion. )
( now that we've got comments, we can comment the rest of the code! )
: else immediate
' branch , ( compile a definite branch )
here ( push the backpatching address )
0 , ( compile a dummy offset for branch )
swap ( bring old backpatch address to top )
dup here swap - ( calculate the offset from old address )
swap ! ( put the address on top and store it )
;
: over _x! _y! _y _x _y ;
: add
_x! ( save the pointer in a temp variable )
_x @ ( get the value pointed to )
+ ( add the incremement from on top of the stack )
_x ! ( and save it )
;
: allot h add ;
: maybebranch
logical ( force the TOS to be 0 or 1 )
r @ @ @ ( load the branch offset )
computebranch ( calculate the condition offset [either TOS or 1])
r @ @ + ( add it to the return address )
r @ ! ( store it to our return address and return )
;
: mod _x! _y! ( get x then y off of stack )
_y
_y _x / _x * ( y - y / x * x )
-
;
: '\n' 0 ;
: '"' 0 ;
: '0' 0 ;
: 'space' 0 ;
: fix-'\n' immediate ' '\n' _fix ;
: fix-'"' immediate ' '"' _fix ;
: fix-'0' immediate ' '0' _fix ;
: fix-'space' immediate ' 'space' _fix ;
fix-'0' 0 fix-'space' fix-'"' "
fix-'\n'
: cr '\n' echo exit
: printnum
dup
10 mod '0' +
swap 10 / dup
if
printnum 0
then
drop echo
;
: .
dup 0 <
if
45 echo minus
then
printnum
'space' echo
;
: debugprint dup . cr ;
( the following routine takes a pointer to a string, and prints it,
except for the trailing quote. returns a pointer to the next word
after the trailing quote )
: _print
dup 1 +
swap @
dup '"' =
if
drop exit
then
echo
tail _print
;
: print _print ;
( print the next thing from the instruction stream )
: immprint
r @ @
print
r @ !
;
: find-"
key dup ,
'"' =
if
exit
then
tail find-"
;
: " immediate
key drop
' immprint ,
find-"
;
: do immediate
' swap , ( compile 'swap' to swap the limit and start )
' tor , ( compile to push the limit onto the return stack )
' tor , ( compile to push the start on the return stack )
here ( save this address so we can branch back to it )
;
: i r @ 1 - @ ;
: j r @ 3 - @ ;
: > swap < ;
: <= 1 + < ;
: >= swap <= ;
: inci
r @ 1 - ( get the pointer to i )
inc ( add one to it )
r @ 1 - @ ( find the value again )
r @ 2 - @ ( find the limit value )
<
if
r @ @ @ r @ @ + r @ ! exit ( branch )
then
fromr 1 +
fromr drop
fromr drop
tor
;
: loop immediate ' inci , here - , ;
: loopexit
fromr drop ( pop off our return address )
fromr drop ( pop off i )
fromr drop ( pop off the limit of i )
; ( and return to the caller's caller routine )
: isprime
dup 2 = if
exit
then
dup 2 / 2 ( loop from 2 to n/2 )
do
dup ( value we're checking if it's prime )
i mod ( mod it by divisor )
not if
drop 0 loopexit ( exit from routine from inside loop )
then
loop
;
: primes
" The primes from "
dup .
" to "
over .
" are:"
cr
do
i isprime
if
i . 'space' echo
then
loop
cr
;
: execute
8 !
' exit 9 !
8 tor
;
: :: ; ( :: is going to be a word that does ':' at runtime )
: fix-:: immediate 3 ' :: ! ;
fix-::
( Override old definition of ':' with a new one that invokes ] )
: : immediate :: ] ;
: command
here 5 ! ( store dict pointer in temp variable )
_read ( compile a word )
( if we get control back: )
here 5 @
= if
tail command ( we didn't compile anything )
then
here 1 - h ! ( decrement the dictionary pointer )
here 5 @ ( get the original value )
= if
here @ ( get the word that was compiled )
execute ( and run it )
else
here @ ( else it was an integer constant, so push it )
here 1 - h ! ( and decrement the dictionary pointer again )
then
tail command
;
: make-immediate ( make a word just compiled immediate )
here 1 - ( back up a word in the dictionary )
dup dup ( save the pointer to here )
h ! ( store as the current dictionary pointer )
@ ( get the run-time code pointer )
swap ( get the dict pointer again )
1 - ( point to the compile-time code pointer )
! ( write run-time code pointer on compile-time pointer )
;
: <build immediate
make-immediate ( make the word compiled so far immediate )
' :: , ( compile '::', so we read next word )
2 , ( compile 'pushint' )
here 0 , ( write out a 0 but save address for does> )
' , , ( compile a push that address onto dictionary )
;
: does> immediate
' command , ( jump back into command mode at runtime )
here swap ! ( backpatch the build> to point to here )
2 , ( compile run-code primitive so we look like a word )
' fromr , ( compile fromr, which leaves var address on stack )
;
: _dump ( dump out the definition of a word, sort of )
dup " (" . " , "
dup @ ( save the pointer and get the contents )
dup ' exit
= if
" ;)" cr exit
then
. " ), "
1 +
tail _dump
;
: dump _dump ;
: # . cr ;
: var <build , does> ;
: constant <build , does> @ ;
: array <build allot does> + ;
: [ immediate command ;
: _welcome " Welcome to THIRD.
Ok.
" ;
: ; immediate ' exit , command exit
[
_welcome
+212
View File
@@ -0,0 +1,212 @@
#include <stdio.h>
; m(x)(x<0?-1:!!x)
; g tj()-J
; a(x)(x<0?-x:x)
; h(x)((x)<=K?x:N-(x))
; f 9999
; A return
; H printf{
; R double
; U int
; V for
; b else
; u while
; B if
U v,w,Y} -1,W,J,p,F,o} f,M,N,K,X,YY,_,P[f],s{ } ;
typedef U{ *L} { } ;
L q[f];
tj{ } {
U S} m{ v} +{ m{ w} <<K} ;
B{ !S} A J;
V{ v} W+S; v!} J&&!q[v]; v+} S} ;
A v;
}
k{ } {
_} K;
A v?a{ v} >1||w-Y||!q[J]:{ w-Y&&{ w-Y*2||q[W+Y*{ N+1} ]||
{ J>>K} -K+{ Y-1} / 2} } ||q[J];
}
z{ } {
_} 5;
A v*w||g;
}
e{ } {
_} -2;
A{ v*v*v-v||w*w*w-w} &&{ J-W-2||{ W&N} -4||{ W>>K!} { Y-1?N:0} } ||
q[W+1]||q[W+2]||q[W+K]!} z||P[W+K]*Y<0} ;
}
R VR{ } {
int PZ} 0x7fff;
A{ R} { rand{ } &PZ} /{ R} PZ;
}
l{ } {
_} K+1;
A{ v*w&&a{ v} -a{ w} } ||g;
}
R UC{ } {
R { } 0,d;
u{ { { +} d} VR{ } } <1.0} ;
A d;
}
c{ } {
_} -11;
A a{ v} -a{ w} ||g;
}
I{ ur,n,x} {
W} ur;
J} n;
B{ P[W]!} Y||P[J]} } Y} A J+1;
v} { J&N} -{ W&N} ;
w} { J>>K} -{ W>>K} ;
A q[W]{ } ||{ x&&QL{ W,J,s} } ;
}
TT{ W} {
v} w} 0;
A q[W]{ } +K;
}
s{ } {
U j} -1,{ ;
Y} -Y;
V{ { } 0; { <M; ++{ } {
B{ j<0&&P[{ ]} } -Y&&TT{ { } &&_} } -2}
{
j} { ;
{ } -1;
}
b B{ j>} 0&&!I{ { ,j,0} } A Y} -Y;
}
A!{ Y} -Y} ;
}
bb{ } {
_} 1;
A a{ v*w} -2;
}
uv{ } {
V{ v} 0; v<f; ++v} {
B{ h{ v>>K} } } 0} {
U S} h{ v&N} ;
q[v]} !S?z:{ S} } 1?bb:{ S} } 2?c:{ v&N>K?l:e} } } ;
}
b B{ h{ v>>K} } } 1} q[v]} k;
b q[v]} 0;
P[v]} !!q[v]*{ 28-v} ;
}
}
y{ } {
U G} Y,{ ;
J} 0;
V{ { } 0; { <M; ++{ } {
{ %8||H"\n%4o ",{ } ;
B{ { Y} P[{ ]} m{ P[{ ]} } &&
TT{ { } } H"%c ",_+93+Y*16} ;
b H"- "} ;
}
H"\n "} ;
do
H"%2d",{ ++&N} ;
u{ { &N} ;
Y} G;
H"\n"} ;
}
O{ W,J} {
B{ { q[J]} q[W]} } } k&&h{ J>>K} } } 0} q[J]} l;
B{ q[W]} } e} B{ J-W} } 2} O{ J+1,J-1} ;
b B{ W-J} } 2} O{ W-1,W+1} ;
P[J]} P[W];
q[W]} 0;
P[W]} 0;
}
QL{ W,J,D} L D;
{
U HQ} P[J],YX;
L AJ} q[J],XY} q[W];
O{ W,J} ;
YX} D{ } ;
O{ J,W} ;
q[J]} AJ;
q[W]} XY;
P[J]} HQ;
A YX;
}
C{ } {
U { ,j,BZ} 0;
V{ { } 0; { <M; ++{ } {
L Z} q[{ ];
B{ Z} {
U r} h{ { >>K} +h{ { &N} ,G} Y,
S} Z} } z?88:{ Z} } k?11
+r+{ P[{ ]<0?N-{ { >>K} :{ { >>K} } :
{ Z} } l?124-{ { YY<8&&{ { { &N} !} K||
{ { >>K} !} { P[{ ]>0?0:N} } } ?M:0} :
{ Z} } c?41+r:{ Z} } e?f-r-r:36+r+r} } } } ;
Y} P[{ ];
V{ j} 0; j<M; ++j} B{ !I{ { ,j,0} } S+} { P[j]?5:1} ;
BZ+} G} } Y?S:-S;
Y} G;
}
}
B{ !{ ++X&M-1} } write{ 1,".",1} ;
A BZ;
}
PX{ } {
U { ,Q} 0,XP} 0,JZ} M*M,E} -f,t,S} o;
B{ !F--} A++F+C{ } ;
V{ { } 0; { <JZ; ++{ } B{ !I{ { >>K+K,{ &M-1,1} } {
Y} -Y;
o} -E;
t} -QL{ { >>K+K,{ &M-1,PX} ;
Y} -Y;
B{ t>E} {
++XP;
Q} { ;
E} t;
B{ E>} S}
A++F,E;
}
}
B{ !XP} E} s{ } ?-f+1:0;
p} Q;
A++F,E;
}
RZ{ } {
U { ,j,T} 0;
V{ ; ; } {
y{ } ;
o} f;
do{
H"\n%d %d %d %s ",X,T,C{ } ,s{ } ?"!":">"} ;
fflush{ stdout} ;
}
u{ scanf{ "%o%o",&{ ,&j} !} 2||I{ { ,j,1} } ;
O{ { ,j} ;
y{ } ;
X} 0;
++YY;
Y} -Y;
T} PX{ } ;
{ } p>>{ K<<1} ;
j} p&{ M-1} ;
B{ I{ { ,j,1} } {
H"Rats!\n"} ;
A;
}
O{ { ,j} ;
Y} -Y;
B{ T>M*M} H"\nHar har.\n"} ;
}
}
main{ ac,av} char**av;
{
long time{ } ,j} time{ &j} ;
R { } 0;
srand{ { U} j} ;
V{ M} 0; M<} f; ++M} { +} UC{ } ;
M} { /100;
B{ M&3} ++M;
B{ M&1} --M;
V{ N} 1; N*N<M; ++N} ;
K} --N/2;
F} ac>1?atoi{ av[1]} :2;
uv{ } ;
RZ{ } ;
}
+144
View File
@@ -0,0 +1,144 @@
Best of Show:
Vern Paxson
Lawrence Berkeley Laboratory
Computer Systems Engineering
Bldg. 46A, Room 1123
Lawrence Berkeley Laboratory
1 Cyclotron Rd.
Berkeley, CA 94720 USA
Judges' comments:
Try:
make vern
vern 3 <-- default is 2
You might start off by giving the following input:
63 43
76 55
71 52
67 57 (this may take a while)
The judges assume no responsibility for the obfuscated opening
suggested above. :-)
For a real quick game try:
vern
65 55
66 46
NOTE: Move values must be restricted to the range 00 to 77.
NOTE: Because some mailers have problems with the original winning source,
a slightly modified version with shorter lines has been provided.
Selected notes from the author:
This program plays chess. You play the white pieces and the program
the black pieces. Moves are entered as a two-digit number specifying
the coordinates of the piece to be moved followed by another two-digit
number specifying the coordinates of where to move it. Rows and
columns are numbered starting with (0,0) for the upper-lefthand corner
(black's queen's rook) and going to (7,7) for the lower-righthand
corner (white's king's rook). For example, the PK4 opening for white
is indicated as "64 44". Moves are read using scanf() so care should
be taken to not enter the wrong number of fields.
If the move you enter is illegal then you are just prompted again to
move. If the move is legal then the new position is displayed and the
program starts computing its response. For every 64 board positions it
examines a "." is printed. Once it has chosen its move it simply
displays the board updated to reflect the move.
Your move is prompted for using a string like "1351 9 2 >". The first
number is how many board positions the program examined when computing
its previous response. The second number is its anticipated value for
the move it just made (with larger numbers meaning an ultimately better
board position for it), and the third number is the evaluation it
assigns to the your current position (larger numbers meaning better
positions for you). A ">" indicates that you are not in check; for
check it is changed to "!".
There are a few limitations on play:
o castling can only be done on the king's side;
o prohibitions against castling out of or through check are
not enforced;
o prohibitions against castling if the king or rook have moved
are not enforced;
o pawns are always promoted to queens;
o en passant is not allowed;
o the board-position-repeated-three-times and fifty-moves
stalemates are not recognized;
If you checkmate the computer it prints "Rats!" and exits. If your own
checkmate is imminent it prints "Har har." but doesn't exit so it can
rub your nose in defeat (which may be a move or two away if you're
playing at a high "ply" - see the next paragraph). Stalemates are not
recognized per se, but when selecting its move the program assigns a
stalemate position a value of 0 so it will try for a stalemate if its
other options are worse.
The program takes one optional argument indicating the ply (lookahead)
it should use. The default is 2, which is enough to keep it from
making flaming blunders. The higher the ply, the better the play, and
the longer you have to wait. For example, at a ply of 2, a response to
the PK4 opening takes about 1.8 CPU seconds on a SPARC ELC when
compiled -O with Sun cc. A ply of 3 takes 13 CPU seconds (and results
in a different response to PK4) and a ply of 4 takes a little under 4
CPU minutes (and for PK4 comes up with the same response as a ply of
3). A ply of 3 is in general good enough to avoid not only flaming
blunders but also immediately stupid moves altogether. A ply of 4
will find all mate-in-two's.
This program is obfuscated in a number of ways. First, it abuses the
contest rule regarding ';', '{', and '}' in the source not counting
against the non-whitespace character limit if followed by whitespace.
As can be seen from the build file, certain combinations of these
characters followed by a particular whitespace character are expanded
at build time into much-needed text. Without this hack the program
wouldn't pass the character limit. A nice side effect is that the
initial source is gloriously difficult to peruse.
Second, the rather ho-hum step has been taking of naming each variable
with a one or two letter identifier to render it meaningless (and save
space). This tactic is rather effective in a complex program.
Third, the board is represented not as an array of pieces but rather as
an array of function pointers (with a separate array representing
whether a piece is white or black). This obfuscates the program's
central data structure. There is one function per type of piece; when
called they return 1 if the current move is illegal for that piece and
0 if it is legal. The functions also as a side effect set a global
indicating the type of the piece (though the type can also be determined
by comparing the function pointer with the function itself).
Fourth, there are no independent routines for generating potential
moves. Instead, the program generates its moves by brute force: for
every piece it controls on the board, it attempts to move it to every
square on the board. Those moves that are legal it then explores to
see their effects (using alpha-beta search). This tactic somewhat
obfuscates the algorithm used by the program.
Finally, there are three key constants that occur throughout the
program: 64, 8, and 3 (lg 8). Rather than making these available at
compile-time, which provides a hint as to what the program is up to,
they are computed probabilistically at run-time. An instance of the
"Inspection Paradox" is used which happens to produce a value that on
average is close to .64. 10000 instances of this value are computed,
added up, and then divided by 100. Sometimes the value produced will
be 63 or 65 instead of 64 (but I've never observed any other values),
so the result is then rounded to the nearest multiple of 4, and then
the other constants are derived from it.
Copyright (c) 1992, Landon Curt Noll & Larry Bassel.
All Rights Reserved. Permission for personal, educational or non-profit use is
granted provided this this copyright and notice are included in its entirety
and remains unaltered. All other uses must receive prior permission in writing
from both Landon Curt Noll and Larry Bassel.
+210
View File
@@ -0,0 +1,210 @@
#include <stdio.h>
; m(x)(x<0?-1:!!x)
; g tj()-J
; a(x)(x<0?-x:x)
; h(x)((x)<=K?x:N-(x))
; f 9999
; A return
; H printf{
; R double
; U int
; V for
; b else
; u while
; B if
U v,w,Y} -1,W,J,p,F,o} f,M,N,K,X,YY,_,P[f],s{ } ;
typedef U{ *L} { } ;
L q[f];
tj{ } {
U S} m{ v} +{ m{ w} <<K} ;
B{ !S} A J;
V{ v} W+S; v!} J&&!q[v]; v+} S} ;
A v;
}
k{ } {
_} K;
A v?a{ v} >1||w-Y||!q[J]:{ w-Y&&{ w-Y*2||q[W+Y*{ N+1} ]||
{ J>>K} -K+{ Y-1} / 2} } ||q[J];
}
z{ } {
_} 5;
A v*w||g;
}
e{ } {
_} -2;
A{ v*v*v-v||w*w*w-w} &&{ J-W-2||{ W&N} -4||{ W>>K!} { Y-1?N:0} } ||
q[W+1]||q[W+2]||q[W+K]!} z||P[W+K]*Y<0} ;
}
R VR{ } {
int PZ} 0x7fff;
A{ R} { rand{ } &PZ} /{ R} PZ;
}
l{ } {
_} K+1;
A{ v*w&&a{ v} -a{ w} } ||g;
}
R UC{ } {
R { } 0,d;
u{ { { +} d} VR{ } } <1.0} ;
A d;
}
c{ } {
_} -11;
A a{ v} -a{ w} ||g;
}
I{ ur,n,x} {
W} ur;
J} n;
B{ P[W]!} Y||P[J]} } Y} A J+1;
v} { J&N} -{ W&N} ;
w} { J>>K} -{ W>>K} ;
A q[W]{ } ||{ x&&QL{ W,J,s} } ;
}
TT{ W} {
v} w} 0;
A q[W]{ } +K;
}
s{ } {
U j} -1,{ ;
Y} -Y;
V{ { } 0; { <M; ++{ } {
B{ j<0&&P[{ ]} } -Y&&TT{ { } &&_} } -2}
{
j} { ;
{ } -1;
}
b B{ j>} 0&&!I{ { ,j,0} } A Y} -Y;
}
A!{ Y} -Y} ;
}
bb{ } {
_} 1;
A a{ v*w} -2;
}
uv{ } {
V{ v} 0; v<f; ++v} {
B{ h{ v>>K} } } 0} {
U S} h{ v&N} ;
q[v]} !S?z:{ S} } 1?bb:{ S} } 2?c:{ v&N>K?l:e} } } ;
}
b B{ h{ v>>K} } } 1} q[v]} k;
b q[v]} 0;
P[v]} !!q[v]*{ 28-v} ;
}
}
y{ } {
U G} Y,{ ;
J} 0;
V{ { } 0; { <M; ++{ } {
{ %8||H"\n%4o ",{ } ;
B{ { Y} P[{ ]} m{ P[{ ]} } &&TT{ { } } H"%c ",_+93+Y*16} ;
b H"- "} ;
}
H"\n "} ;
do
H"%2d",{ ++&N} ;
u{ { &N} ;
Y} G;
H"\n"} ;
}
O{ W,J} {
B{ { q[J]} q[W]} } } k&&h{ J>>K} } } 0} q[J]} l;
B{ q[W]} } e} B{ J-W} } 2} O{ J+1,J-1} ;
b B{ W-J} } 2} O{ W-1,W+1} ;
P[J]} P[W];
q[W]} 0;
P[W]} 0;
}
QL{ W,J,D} L D;
{
U HQ} P[J],YX;
L AJ} q[J],XY} q[W];
O{ W,J} ;
YX} D{ } ;
O{ J,W} ;
q[J]} AJ;
q[W]} XY;
P[J]} HQ;
A YX;
}
C{ } {
U { ,j,BZ} 0;
V{ { } 0; { <M; ++{ } {
L Z} q[{ ];
B{ Z} {
U r} h{ { >>K} +h{ { &N} ,G} Y,
S} Z} } z?88:{ Z} } k?11+r+{ P[{ ]<0?N-{ { >>K} :{ { >>K} } :
{ Z} } l?124-{ { YY<8&&{ { { &N} !} K||
{ { >>K} !} { P[{ ]>0?0:N} } } ?M:0} :
{ Z} } c?41+r:{ Z} } e?f-r-r:36+r+r} } } } ;
Y} P[{ ];
V{ j} 0; j<M; ++j} B{ !I{ { ,j,0} } S+} { P[j]?5:1} ;
BZ+} G} } Y?S:-S;
Y} G;
}
}
B{ !{ ++X&M-1} } write{ 1,".",1} ;
A BZ;
}
PX{ } {
U { ,Q} 0,XP} 0,JZ} M*M,E} -f,t,S} o;
B{ !F--} A++F+C{ } ;
V{ { } 0; { <JZ; ++{ } B{ !I{ { >>K+K,{ &M-1,1} } {
Y} -Y;
o} -E;
t} -QL{ { >>K+K,{ &M-1,PX} ;
Y} -Y;
B{ t>E} {
++XP;
Q} { ;
E} t;
B{ E>} S}
A++F,E;
}
}
B{ !XP} E} s{ } ?-f+1:0;
p} Q;
A++F,E;
}
RZ{ } {
U { ,j,T} 0;
V{ ; ; } {
y{ } ;
o} f;
do{
H"\n%d %d %d %s ",X,T,C{ } ,s{ } ?"!":">"} ;
fflush{ stdout} ;
}
u{ scanf{ "%o%o",&{ ,&j} !} 2||I{ { ,j,1} } ;
O{ { ,j} ;
y{ } ;
X} 0;
++YY;
Y} -Y;
T} PX{ } ;
{ } p>>{ K<<1} ;
j} p&{ M-1} ;
B{ I{ { ,j,1} } {
H"Rats!\n"} ;
A;
}
O{ { ,j} ;
Y} -Y;
B{ T>M*M} H"\nHar har.\n"} ;
}
}
main{ ac,av} char**av;
{
long time{ } ,j} time{ &j} ;
R { } 0;
srand{ { U} j} ;
V{ M} 0; M<} f; ++M} { +} UC{ } ;
M} { /100;
B{ M&3} ++M;
B{ M&1} --M;
V{ N} 1; N*N<M; ++N} ;
K} --N/2;
F} ac>1?atoi{ av[1]} :2;
uv{ } ;
RZ{ } ;
}
+12
View File
@@ -0,0 +1,12 @@
main(l
,a,n,d)char**a;{
for(d=atoi(a[1])/10*80-
atoi(a[2])/5-596;n="@NKA\
CLCCGZAAQBEAADAFaISADJABBA^\
SNLGAQABDAXIMBAACTBATAHDBAN\
ZcEMMCCCCAAhEIJFAEAAABAfHJE\
TBdFLDAANEfDNBPHdBcBBBEA_AL\
H E L L O, W O R L D! "
[l++-3];)for(;n-->64;)
putchar(!d+++33^
l&1);}
+112
View File
@@ -0,0 +1,112 @@
Best Small Program:
Brian Westley (aka Merlyn LeRoy)
Digi International
1026 Blair Ave.
St. Paul, MN 55104
USA
Judges' comments:
If lost:
make whereami
Then run:
whereami lat long
Where lat and long correspond to your latitude and longitude.
To find the approximate place where this entry was judged, type:
whereami 37 -122 (- means west of meridian)
Selected notes from the author:
Run the program with your latitude & longitude as integer
arguments; it will produce a map made up of '!' with the given
position marked with either a '"' (if the position is over a '!')
or a '#' (if the position is over a space). Southern latitudes
and western longitudes are entered as negative numbers. For
example, to find San Francisco, run with "prog 38 -122". The
resolution of the map is five degrees horizontally, ten degrees
vertically. The map is a Mercator projection with equal spacing
of the latitudes, so the areas near the poles are very distorted.
Latitudes near the poles and Antarctica are not shown.
The program requires the ASCII character set, putchar(), atoi(),
and a display that auto-wraps at 80 characters(!). If your display
does not work this way, you will have to massage the output;
for example, you can pipe it to a file and edit it with vi,
which will do autowrap for you.
Lint complains that main() returns a random value and I'm not
checking the value that putchar() returns. Scandalous!
If you run it with fewer than 2 arguments, it will likely
give you an exception, as it will access arguments that
don't exist and characters before a string constant.
How it works:
The map is printed as one long string of ' ' and '!' characters,
with the autowrap used to stack up slices of 80. The map data is
a string; the first character is how many '!'s are printed
('A'=1, 'B'=2, etc), the second character is how many ' 's, the
third is how many '!'s, etc. ASCII characters less than 'A'
print no characters but still change the polarity, so any map
of ' 's and '!'s is possible. This is done in the putchar()
argument as "33^l&1", where l is the character position+4; if
l is odd, ' ' is printed, if l is even, '!' is printed.
The position of latitude & longitude is changed into a single
character position within the one long string via the first
expression "d = latitude/10*80 - longitude/5 - offset" The
latitude is divided by ten because the vertical resolution is
ten degrees, then multiplied by 80 because of the 80 character
wrap (i.e. each ten degrees moves the position up or down one
entire row). The longitude is divided by five and added, because
five degrees of change moves the location one character. The signs
are opposite because latitude is decreasing and longitude is
increasing as you go from upper left to lower right. The offset
is where the origin (latitude=0, longitude=0) is found.
The position counting down to zero changes the putchar() from
printing ('!' or ' ') to printing ('"' or '#').
The "H E L L O, W O R L D!" string inside the data string
prints the line of blanks past Tierra del Fuego and the last
blank line. It's just for show, really.
Since the resolution is coarse, a few costal cities are shown to
be just off the map; this is an unavoidable artifact. The map
is reasonably accurate.
Here are some cities you might like to try:
New York 41 -74 Los Angeles 34 -118
London 52 0 Paris 45 2
Moscow 56 38 Beijing 40 116
New Delhi 29 77 Rio de Janeiro -23 -43
Sydney -34 151 Tokyo 36 140
For a domestic (USA) version with higher resolution, try:
---cut---
main(l,a,n,d)char**a;{for(d=atoi(a[1])/2*80-atoi(a[2])-2043;
n="bnaBCOCXdBBHGYdAP[A M E R I C A].AqandkmavX|ELC}BOCd"
[l++-3];)for(;n-->64;)putchar(!d+++33^l&1);}
---cut---
The code will test the 80-column wrap and document itself if it is
joined together as one 160-character line and listed. You should see:
main(l,a,n,d)...
[A M E R I C A]...
...going down the left edge if your terminal autowraps at 80 characters.
Copyright (c) 1992, Landon Curt Noll & Larry Bassel.
All Rights Reserved. Permission for personal, educational or non-profit use is
granted provided this this copyright and notice are included in its entirety
and remains unaltered. All other uses must receive prior permission in writing
from both Landon Curt Noll and Larry Bassel.