Format fix + unrot13 text in 1992/gson/README.md
This commit is contained in:
1 parent
102675d4dd
commit
6ac877dba9
1 file changed
+136
-135
+136
-135
@@ -1,9 +1,6 @@
|
|||||||
# Most Humorous Output
|
# Most Humorous Output
|
||||||
|
|
||||||
Andreas Gustafsson\
|
Andreas Gustafsson\
|
||||||
Helsinki University of Technology\
|
|
||||||
Arentikuja 1 D 305\
|
|
||||||
00410 Helsinki\
|
|
||||||
Finland
|
Finland
|
||||||
|
|
||||||
|
|
||||||
@@ -69,16 +66,16 @@ The name of the game:
|
|||||||
AG is short for either Anagram Generator or simply AnaGram. It might also be
|
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
|
construed to mean Alphabet Game, and by pure coincidence it happens to be the
|
||||||
author's initials.
|
author's initials.
|
||||||
\
|
|
||||||
\
|
|
||||||
### What it does
|
### What it does
|
||||||
\
|
|
||||||
AG takes one or more words as arguments, and tries to find anagrams of those
|
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.
|
words, i.e. words or sentences containing exactly the same letters.
|
||||||
|
|
||||||
|
|
||||||
### How to use it
|
### How to use it
|
||||||
\
|
|
||||||
To run AG, you need a dictionary file consisting of distinct words in the
|
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
|
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
|
have one already, you can make your own dictionary by concatenating a few
|
||||||
@@ -102,7 +99,7 @@ limit can be changed using a numeric command line option, as in
|
|||||||
`./ag -4 international obfuscated c code contest </usr/dict/words`.
|
`./ag -4 international obfuscated c code contest </usr/dict/words`.
|
||||||
|
|
||||||
### Bugs
|
### Bugs
|
||||||
\
|
|
||||||
- There is no error checking.
|
- There is no error checking.
|
||||||
- Standard input must be seekable, so you can't pipe the dictionary into AG.
|
- 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
|
- The input sentence and each line in the dictionary may contain at most 32
|
||||||
@@ -115,8 +112,8 @@ less.
|
|||||||
|
|
||||||
|
|
||||||
### Obfuscatory notes
|
### Obfuscatory notes
|
||||||
\
|
|
||||||
As you can see, AG takes advantage of the new '92 whitespace rules to
|
As you can see, AG takes advantage of the new '92 whitespace rules' to
|
||||||
achieve a clear, readable, self-documenting layout. The identifiers
|
achieve a clear, readable, self-documenting layout. The identifiers
|
||||||
have been chosen in a way appropriate for an alphabet game, and common
|
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
|
sources of bugs such as goto statements and malloc/free have been
|
||||||
@@ -124,135 +121,139 @@ eliminated. As AG also refrains from abusing the preprocessor, it
|
|||||||
doesn't really have much to offer in terms of "surface obfuscation".
|
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
|
Instead, it tries to achieve both its speed and its obscurity through a
|
||||||
careful choice of algorithms. Some of the finer points of those
|
careful choice of algorithms. Some of the finer points of those
|
||||||
algorithms are outlined in the rot-13 encoded spoiler below.
|
algorithms are outlined in the spoiler below.
|
||||||
|
|
||||||
### How it works: (ROT13 to read)
|
### How it works: (ROT13 to read)
|
||||||
|
|
||||||
|
Here follows a description of some of the data structures and
|
||||||
|
algorithms used by AG. It is by no means complete, but it may help
|
||||||
|
you get an idea about the general principles.
|
||||||
|
|
||||||
|
--
|
||||||
|
|
||||||
|
Internally, AG represents words and sentences as arrays of 32
|
||||||
|
4-bit integer elements. Each element represents the number of
|
||||||
|
times a letter occurs in the word/sentence. There are 32 elements
|
||||||
|
because 32 is a convenient power of two larger than the number of
|
||||||
|
letters in most western alphabets, and the elements are 4 bits
|
||||||
|
each because the same letter is unlikely to occur more than 15
|
||||||
|
times in a practical anagram generation problem.
|
||||||
|
|
||||||
|
These `32*4`-bit arrays are actually stored in memory in a
|
||||||
|
"bit-transposed" format, as arrays of four "long" values. It is
|
||||||
|
assumed that a "long" is at least 32 bits. The first 4-bit letter
|
||||||
|
count is formed by the least significant (2^0) bit in each of the
|
||||||
|
four longs, the next one is formed by the 2^1 bits, etc.
|
||||||
|
|
||||||
|
This storage format makes it possible to add or subtract two such
|
||||||
|
vectors of 32 4-bit values in parallel by simulating a set of 32
|
||||||
|
binary full adders in software using bitwise logical operations.
|
||||||
|
E.g., all the LSB:s of the result are formed in parallel by taking
|
||||||
|
the exclusive OR of the LSB:s in each summand, and 32 carry bits
|
||||||
|
are formed in parallel in a similar way using a logical AND.
|
||||||
|
Thus, 32 independent 4-bit additions can be performed by just four
|
||||||
|
iterations of a loop containing some 32-bit bitwise logical
|
||||||
|
operations, but no arithmetic operations other than those implied
|
||||||
|
by array indexing.
|
||||||
|
|
||||||
|
Subtraction works similarly, and in fact AG only implements
|
||||||
|
subtraction directly, handling addition by means of the identity
|
||||||
|
`a+b = a-(0-b)`.
|
||||||
|
|
||||||
|
In addition to this `32*4`-bit representation, AG also forms a so-called
|
||||||
|
"signature" that is the bitwise OR of the four longs, which is
|
||||||
|
equivalent to saying that the signature of a word contains a logical 1
|
||||||
|
in the bit positions corresponding to letters occurring at least once
|
||||||
|
in that word.
|
||||||
|
|
||||||
|
The first thing AG does is to construct a lookup table of 256
|
||||||
|
longs, one for each 8-bit character value. The entry for a
|
||||||
|
character will be zero if that character doesn't appear in the
|
||||||
|
sentence given on the command line, or it will have a single bit
|
||||||
|
set if the character does appear in the sentence. By adding
|
||||||
|
together the bit masks for all the letters in the input sentence
|
||||||
|
using the transpose addition method described above, AG forms the
|
||||||
|
`32*4` bit array representation of the input sentence.
|
||||||
|
|
||||||
|
The next action performed is reading the dictionary. Those words that
|
||||||
|
contain letters not in the input sentence are immediately discarded.
|
||||||
|
Words containing the right letters but in excessive numbers are
|
||||||
|
eliminated in a separate check involving the `32*4` bit array.
|
||||||
|
|
||||||
|
The remaining words, which will be referred to as "candidate words",
|
||||||
|
are stored in `32*4`-bit representation, together with their signatures\
|
||||||
|
and offsets into the dictionary file so that the plain-text version of
|
||||||
|
a word can later be found for printing. This information is kept in a
|
||||||
|
local "struct" in the dictionary-reading function, and memory is
|
||||||
|
allocated for each candidate word simply by making another recursive
|
||||||
|
call to that function.
|
||||||
|
|
||||||
|
Each struct so allocated is linked into a fixed-size hash table of
|
||||||
|
4096 entries indexed by the 12 low bits of the word's signature.\
|
||||||
|
When the dictionary-reading function encounters end-of-file, all the
|
||||||
|
candidate words have been stored in nested activation records on the
|
||||||
|
stack, accessible through the hash table.
|
||||||
|
|
||||||
|
Generating the anagrams is then done by traversing the hash table and
|
||||||
|
subtracting the letters of each word in the hash table from the
|
||||||
|
"current sentence", which initially is the sentence given on the
|
||||||
|
command line.
|
||||||
|
|
||||||
|
The subtraction is performed in parallel on the 4-bit letter counts
|
||||||
|
as described above, and if all 32 results are zero, an anagram has
|
||||||
|
been found. If the result is negative for one or more of the letters
|
||||||
|
(as indicated by one or more "1" in a vector of 32 borrow bits
|
||||||
|
returned by the subtraction routine), the word did not match the
|
||||||
|
current sentence and is ignored. Finally, if the result contained
|
||||||
|
only non-negative letter counts, we have found a partial anagram:\
|
||||||
|
a word containing some, but not all, of the letters in the current
|
||||||
|
sentence. In this case we recursively try to find an anagram of the
|
||||||
|
remaining letters. The depth of the recursion is limited to the
|
||||||
|
maximum number of words in the anagram, as specified by the user.
|
||||||
|
|
||||||
|
When the deepest recursion level has been reached, an optimization can
|
||||||
|
be applied: because no further recursion will be done, there is no
|
||||||
|
need to look for partial anagrams, and therefore AG only needs to
|
||||||
|
check for words that contain exactly the same letters as the current
|
||||||
|
sentence. Those words can be found simply by indexing the hash table
|
||||||
|
with the signature of the current sentence.
|
||||||
|
|
||||||
|
Even when not on the deepest recursion level, AG generally avoids
|
||||||
|
examining all the entries of the hash table. The idea is that we are
|
||||||
|
not interested in hash buckets whose words contain any letters not
|
||||||
|
in the current sentence; these buckets are exactly those whose index
|
||||||
|
has a logical one in a bit position where the signature of the current
|
||||||
|
sentence has a zero. Put another way, we want to loop through only
|
||||||
|
those hash bucket indices "i" that contain zeroes in all the bit
|
||||||
|
positions where the signature "s" of the current sentence contains
|
||||||
|
a zero; this can be expressed in C as (i & ~s == 0).
|
||||||
|
|
||||||
|
It is possible to loop through all such numbers in an efficient way by
|
||||||
|
taking advantage of certain properties of binary arithmetic: by
|
||||||
|
forcing the bits corresponding to zeroes in "s" to ones, we can make
|
||||||
|
the carries generated in incrementing "i" propagate straight across
|
||||||
|
those bits that should remain zero. For example, the following
|
||||||
|
program prints all those 16-bit integers that contain zeroes in all
|
||||||
|
even bit positions:
|
||||||
|
|
||||||
|
|
||||||
|
```c
|
||||||
|
main(){int i=0,s=0xAAAA;do{printf("%04x\t",i);}while(i=((i|~s)+1)&s);}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
AG uses a similar method but works in the opposite direction, finding
|
||||||
|
the next lower value with zeroes in given bit positions by propagating
|
||||||
|
borrows across those bits. Some additional adjustments are made
|
||||||
|
to the hash table index when initiating a recursive search, using
|
||||||
|
similar bit-twiddling techniques.
|
||||||
|
|
||||||
|
Whenever an anagram has been found, it is printed by traversing a
|
||||||
|
linked list formed by structs in the activation records of the
|
||||||
|
recursive invocations of the search function, seeking to the beginning
|
||||||
|
of the word matched by that invocation, and copying the characters of
|
||||||
|
the word directly from standard input to standard output.
|
||||||
|
|
||||||
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 and CC BY-SA 4.0 License:
|
## Copyright and CC BY-SA 4.0 License:
|
||||||
|
|||||||
Reference in new issue
Block a user