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:
1 parent
28efc67f5d
commit
c0663537cb
1683 files changed
+220064
No files matched your search
Binary file not shown.
+244
@@ -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
@@ -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
@@ -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"); }
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<q0> a <q1> The first state to appear is the start state
|
||||
<q1> b <q2>
|
||||
<q2> c [q3]
|
||||
[q3]
|
||||
@@ -0,0 +1,4 @@
|
||||
<q0> a <q1>
|
||||
<q1> b <q2>
|
||||
<q2> c [q3]
|
||||
[q3] . [q3]
|
||||
@@ -0,0 +1,4 @@
|
||||
<q0> a <q1> . <q0>
|
||||
<q1> b <q2> a <q1> . <q0>
|
||||
<q2> c [q3] a <q1> . <q0>
|
||||
[q3] . <q1>
|
||||
@@ -0,0 +1,3 @@
|
||||
[q0] a <q1>
|
||||
<q1> b <q2>
|
||||
<q2> c [q0]
|
||||
@@ -0,0 +1,4 @@
|
||||
<q0> ab <q1>
|
||||
<q1> cd <q2>
|
||||
<q2> ef [q3]
|
||||
[q3]
|
||||
@@ -0,0 +1,8 @@
|
||||
<q0> F <q1>
|
||||
<q1> r <q2>
|
||||
<q2> o <q3>
|
||||
<q3> m <q4>
|
||||
<q4> : <q5> . [q6]
|
||||
<q5> . <q5>
|
||||
[q6] . [q6]
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<q0> t <q1> . <q0>
|
||||
<q1> hc <q2> t <q1> . <q0>
|
||||
<q2> eh [q3] t <q1> . <q0>
|
||||
[q3] . <q1>
|
||||
@@ -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.
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -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.*
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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'.
|
||||
@@ -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++]));
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
@@ -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++]));
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,4 @@
|
||||
: demo1 " Hello world!
|
||||
" ;
|
||||
|
||||
demo1
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
@@ -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
|
||||
)
|
||||
));
|
||||
}
|
||||
@@ -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);}
|
||||
@@ -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.
|
||||
@@ -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
@@ -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::
|
||||
;;;}
|
||||
|
||||
@@ -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.
|
||||
@@ -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::
|
||||
;;;}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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.
|
||||
@@ -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
File diff suppressed because it is too large.
Load diff
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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.
|
||||
@@ -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{ } ;
|
||||
}
|
||||
@@ -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);}
|
||||
@@ -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.
|
||||
Reference in new issue
Block a user