Add 2019/dogon/try.sh, update bugs.md, README.md

Updated Makefile so one can easily change the 'Z' macro by doing:

    make clobber MEMORY=... all

This is not usually useful but there are occasions where it is. As the
README.md points out this value must be a power of two!

The try.sh script runs the program on a number of the mc files, first
showing the input keys as a reminder (it also reminds one to keep in
mind the focus of windows).

The bugs.md is updated to note that it uses gets(3).

Format/typo check README.md file.

I changed the number of years ago that microorganisms appeared on Earth
as the number was off: there are those wondrous hydrothermal vents that
spewed mineral rich waters. Fun fact on the history of the Earth: did
you know that as of 2013 the number of years since the dinosaurs were
wiped out is not 65m years but actually 66m? That means that if you were
born before 2013 and you didn't die right before the revision that
you're in a rare group of people who have had a major historical update
as far as the dinosaurs go. But don't let it get to your head too much!
It also means you're ancient, possibly even a dinosaur, and you're
headed their way. :-) That's the price we must pay for being in that
group.
This commit is contained in:
Cody Boone Ferguson committed 2023-12-16 09:33:17 -08:00
1 parent 5906389fa8
commit 01dd7bdee7
7 files changed
+187 -94

No files matched your search

+1
View File
@@ -6,4 +6,5 @@ indent
indent.c indent.c
indent.o indent.o
prog prog
prog.alt
prog.orig prog.orig
+7 -3
View File
@@ -59,9 +59,13 @@ CSTD= -std=gnu17
# #
ARCH= ARCH=
# Variable to simplify changing memory usage
#
MEMORY= 0x20000000
# Defines that are needed to compile # Defines that are needed to compile
# #
CDEFINE= -DX=1280l -DY=1024l -DZ=0x20000000 CDEFINE= -DX=1280l -DY=1024l -DZ=${MEMORY}
# Include files that are needed to compile # Include files that are needed to compile
# #
@@ -121,8 +125,8 @@ DATA= glider.mc gotts-dots.mc infinite.mc infinite_10cell.mc infinite_5x5.mc \
metapixel-parity64.mc mosquito5.mc unlimited-novelty.mc metapixel-parity64.mc mosquito5.mc unlimited-novelty.mc
TARGET= ${PROG} apholife TARGET= ${PROG} apholife
# #
ALT_OBJ= ALT_OBJ= ${PROG}.alt.o
ALT_TARGET= ALT_TARGET= ${PROG}.alt
################# #################
+76 -54
View File
@@ -5,6 +5,17 @@ make
``` ```
### Bugs and (Mis)features:
The current status of this entry is:
```
STATUS: uses gets() - change to fgets() if possible
```
For more detailed information see [2019 dogon in bugs.md](/bugs.md#2019-dogon).
## To use: ## To use:
```sh ```sh
@@ -15,24 +26,19 @@ make
### Try: ### Try:
```sh ```sh
./prog < glider.mc ./try.sh
./prog < infinite_5x5.mc
./prog < mosquito5.mc
# Press the minus key a few times until you see white specks,
# then press space, and the ] key a few times.
./prog < message.mc
``` ```
Make sure that you keep focus of windows in mind when going back and forth to
the program and the script.
## Judges' remarks: ## Judges' remarks:
[1991/davidguy](http://ioccc.org/years.html#1991_davidguy), [1991/davidguy](http://ioccc.org/years.html#1991_davidguy),
[2011/blakely](http://ioccc.org/years.html#2011_blakely), ... [2011/blakely](http://ioccc.org/years.html#2011_blakely), ...
...This entry likely concludes the IOCCC category "Cellular automata simulators", ...This entry likely concludes the IOCCC category "Cellular automata simulators";
it would be very hard to beat it on its field. it would be very hard to beat it on its field.
FYI: The `.mc` extension stands for `Golly macrocell` format. FYI: The `.mc` extension stands for `Golly macrocell` format.
@@ -43,49 +49,58 @@ We truly have not much more to add, except two things:
you are much more likely to see a blank board rather than the loaded configuration, you are much more likely to see a blank board rather than the loaded configuration,
and to see it, you may need to zoom out a few times. and to see it, you may need to zoom out a few times.
* if you're using a virtual machine with less than 4 Gb of available * If you're using a virtual machine with less than 4 Gb of available
model RAM, you'd want to reduce the value of the Z define in the Makefile model RAM, you'd want to reduce the value of the Z define in the Makefile
to 0x10000000, otherwise the entry will promptly crash. to `0x10000000`, otherwise the entry will promptly crash. To do this you can do:
make clobber MEMORY=0x10000000 all
Notice that that value must be a power of two!
In the interest of saving lives, this entry was not fuzzed. In the interest of saving lives, this entry was not fuzzed.
## Author's remarks: ## Author's remarks:
### What is it? ### What is it?
Just run with no arguments on an X11-compatible system using one of the supplied Just run with no arguments on an X11-compatible system using one of the supplied
input `.mc` files as standard input. Press '-' several time to zoom out if input `.mc` files as standard input. Press `-` several time to zoom out if
necessary, then press space. For acceleration press ']' several times. That's necessary, then press space. For acceleration press `]` several times. That's
rather quick don't you think? rather quick don't you think?
### Historical Timeline.
* 3.5 Billion years ago: Microorganism life appears on earth. ### Historical Timeline
* Circa 3.77 - 4.28 Billion years ago: Microorganisms appear on Earth.
* 3000 BC: Ankh symbol is used in Egyptian hieroglyph to represent life. * 3000 BC: Ankh symbol is used in Egyptian hieroglyph to represent life.
* 1940s: John Von Neumann and Stanislav Ulam are interested in artificial life * 1940s: John Von Neumann and Stanislav Ulam are interested in artificial life
eventually kick starting research on Cellular Automata. eventually kick starting research on Cellular Automata.
* 1970: J.H. Conway's research discovers a rather minimal set of rules that * 1970: J.H. Conway's research discovers a rather minimal set of rules that
seems quite interesting. Conway's game of life gets published in Martin seems quite interesting. [Conway's Game of
Gardner's Scientific American column. Life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life) gets published in
* 1970's: According to Knuth, a significant portion of computer time in the [Martin Gardner's Scientific American
column](https://web.stanford.edu/class/sts145/Library/life.pdf).
* 1970s: According to Knuth, a significant portion of computer time in the
world is spent simulating GOL, mostly without the awareness of the people world is spent simulating GOL, mostly without the awareness of the people
footing the bill. footing the bill.
* 1984: Bill Gosper invents the * 1984: Bill Gosper invents the
[Hashlife](https://en.wikipedia.org/wiki/Hashlife) algorithm. His [Hashlife](https://en.wikipedia.org/wiki/Hashlife) algorithm. His
implementation runs on Symbolics Lisp Machines. Unrelated to that, but in a implementation runs on Symbolics Lisp Machines. Unrelated to that, but in a
cosmic coincidence the first IOCCC is run! cosmic coincidence the [first IOCCC](/years.html#1984) is run!
* December 2000: Tom Rokicki has a breakthrough implementing * December 2000: Tom Rokicki has a breakthrough implementing
[Hashlife](https://en.wikipedia.org/wiki/Hashlife) in C, efficient, stable and [Hashlife](https://en.wikipedia.org/wiki/Hashlife) in C, efficient, stable and
production ready for modern machines. production ready for modern machines.
* 2006: First version of Golly by Andrew Trevorrow and Tomas Rokicki. Brings * 2006: First version of Golly by Andrew Trevorrow and Tomas Rokicki. Brings
the delights of [hashlife](https://en.wikipedia.org/wiki/Hashlife) to the masses. the delights of [hashlife](https://en.wikipedia.org/wiki/Hashlife) to the masses.
\
Which brings us to the present moment in time. Which brings us to the present moment in time.
### Full documentation and keys UI.
Yes, this program is Conway's Game of Life graphic simulator implementing Bill ### Full documentation and keys UI
Yes, this program is a Conway's Game of Life graphic simulator implementing Bill
Gosper's hashlife algorithm. The entry's UI is rather terse and somewhat Gosper's hashlife algorithm. The entry's UI is rather terse and somewhat
obfuscated, as it should be. Also, when you, accidentally or not, press any of obfuscated, as it should be. Also, when you, accidentally or not, press any of
the keys not specified below, some stuff will happen or not, there is no the keys not specified below, some stuff will happen or not, there is no
@@ -108,20 +123,21 @@ the header comment of each.
* `]`: Increase speed (time step) by a factor of 2. * `]`: Increase speed (time step) by a factor of 2.
* `[`: Decrease speed (time step) by a factor of 2. * `[`: Decrease speed (time step) by a factor of 2.
Notice that when going backward in time we ignore current time step setting and Notice that when going backward in time we ignore the current time step setting
just jump by the amount that was specified before. However going forward is and just jump by the amount that was specified before. However going forward is
always using the current time step. always using the current time step.
There is a minimal text printout by the program, so you can know what Generation There is a minimal text printout by the program, so you can know what Generation
your are in (G:), Internal memory allocated till now (M:), and then which Level your are in (`G:`), Internal memory allocated till now (`M:`), and then which Level
is the current macrocell (L) and which zoom Scale you are watching (S). is the current macrocell (`L`) and which zoom Scale you are watching (`S`).
### Portability issues.
### Portability issues
This entry is quite portable hopefully on most modern platforms. It assumes X This entry is quite portable hopefully on most modern platforms. It assumes X
Window support of course. More than 2GBytes memory is recommended. Configuration Window support of course. More than 2GB of memory is recommended. Configuration
through [Makefile](Makefile) is provided for the display windows size and for through [Makefile](Makefile) is provided for the display windows size and for
the memory usage. The Makefile provided configuration (Z=0x20000000) will need a the memory usage. The Makefile provided configuration (`Z=0x20000000`) will need a
system with 4GB DRAM to run nicely. There are several other salient assumptions system with 4GB DRAM to run nicely. There are several other salient assumptions
though: though:
@@ -131,10 +147,11 @@ pointers which are 64 bits these days, in order to save space. On machines with
* The entry assumes the X11 displays default visual has 24 bit depth (RGB). * The entry assumes the X11 displays default visual has 24 bit depth (RGB).
* The entry assumes little endianness (in only one place though! If you have * The entry assumes little endianness (in only one place though! If you have
PowerPC you can try and find that place to make it work), but more than this it PowerPC you can try and find that place to make it work), but more than this it
assumes unaligned loads of 64 bits longs are supported, i.e. it assumes that a assumes unaligned loads of 64 bits `long`s are supported, i.e. it assumes that a
long can be loaded from any address that could hold an int otherwise. On non `long` can be loaded from any address that could hold an `int` otherwise. On non
antiquated X86 you'll be fine. antiquated X86 you'll be fine.
* The entry heavily relies on bit complement arithmetic (you don't say!). * The entry heavily relies on bitwise arithmetic (you don't say!).
### Limitations: ### Limitations:
@@ -150,29 +167,30 @@ that is not too much. It does not do any garbage collection, so sooner or later
memory will run out, resulting, surprise, surprise, in a core dump. On the plus memory will run out, resulting, surprise, surprise, in a core dump. On the plus
side, this enables the nice time reversal feature... Anyway the amount of memory side, this enables the nice time reversal feature... Anyway the amount of memory
used can be controlled by the Makefile `-DZ=...` argument. With the default `Z`, used can be controlled by the Makefile `-DZ=...` argument. With the default `Z`,
the program will support in total about 240 million 64bit longs for the internal the program will support in total about 240 million 64bit `long`s for the internal
memory, which should be sufficient for about 100 million nodes+leafs, as each memory, which should be sufficient for about 100 million nodes+leafs, as each
node is 3 longs and each leaf is 2. node is 3 `long`s and each leaf is 2.
*Important:* Makefile Z define must be a power of two! *Important:* Makefile `Z` define must be a power of two!
Zooming out past about S58 scale will enter a buggy twilight zone as only long Zooming out past about S58 scale will enter a buggy twilight zone as only `long`
integers are used in the drawing code. Reverting to doubles could have remedied integers are used in the drawing code. Reverting to `double`s could have remedied
that, but then I'd need to use a lot of `ldexp()`s which would take the program that, but then I'd need to use a lot of `ldexp()`s which would take the program
over the size limit. Also the program will crash once the universe goes past over the size limit. Also the program will crash once the universe goes past
level 64, though this is simply fixed by modifying a single constant in the level 64, though this is simply fixed by modifying a single constant in the
program, can you find it ? Anyway 2^58 squared is quite a big enough universe program, can you find it ? Anyway `2^58` squared is quite a big enough universe
for such a tiny program to simulate, no ? for such a tiny program to simulate, no ?
In case cell memory did not run out, or your pattern did not grow too big, and In case cell memory did not run out, or your pattern did not grow too big, and
you have had patience enough and did not increase speed too much, you can run you have had patience enough and did not increase speed too much, you can run
out of the history buffer after 33333 steps. out of the history buffer after `33333` steps.
If all of the above did not happen and result in the expected core dump, you If all of the above did not happen and result in the expected core dump, you
will encounter the final limitation, which is the absence of an escape key. Just will encounter the final limitation, which is the absence of an escape key. Just
close the window or use ^C to exit .... close the window or use `^C`/intr to exit ....
### Warnings.
### Warnings
Oh don't get me started on the torrent of litanies gcc emits when used with Oh don't get me started on the torrent of litanies gcc emits when used with
`-Wall`! Does it think I have not memorized by heart C's precious operator `-Wall`! Does it think I have not memorized by heart C's precious operator
@@ -181,30 +199,33 @@ extra parentheses that would take the program over the limit ? And what if I do
not use a variable here or there, do I have to pay extra tax for every orphaned not use a variable here or there, do I have to pay extra tax for every orphaned
variable? variable?
There is the reasonable warning about some longs printed as ints but its OK too, There is the reasonable warning about some `long`s printed as `int`s but its OK too,
trust me. trust me.
Then there's the warning about 'gets' being unsafe, which is indeed the only one Then there's the warning about `gets(3)` being unsafe, which is indeed the only one
that appears by default in some versions of gcc linker. Yes Virginia, I know it that appears by default in some versions of gcc linker. Yes Virginia, I know it
is unsafe, and I would not recommend anyone using this entry as part of a web is unsafe, and I would not recommend anyone using this entry as part of a web
daemon, or a spaceship, no, seriously don' do that. daemon, or a spaceship, no, seriously don' do that.
### Obfuscations.
### Obfuscations:
Well almost none of the obfuscations are done on purpose, but mostly out of Well almost none of the obfuscations are done on purpose, but mostly out of
necessity, so all identifiers possible to be one character, are, and they are necessity, so all identifiers possible to be one character, are, and they are
mercilessly reused. In the main there's even a nice little identifier first used mercilessly reused. In the `main()` function there's even a nice little
as a global and then reused (shadowed) in the *same* scope, and this did not identifier first used as a global and then reused (shadowed) in the *same*
produce even a little squeak of a warning from the compiler! Macro compression is scope, and this did not produce even a little squeak of a warning from the
rather sparingly used, however magic numbers abound everywhere, and bit twiddling compiler! Macro compression is rather sparingly used, however magic numbers
is magical too. Do you know for example why we have unsigned F=-1 ? (No warning abound everywhere, and bit twiddling is magical too. Do you know for example why
there of course :) Hint: Later in the program you have F/=17. Did that make any we have `unsigned F=-1` ? (No warning there of course :) Hint: Later in the
sense? Further hint: print the resulting F in hexadecimal... program you have `F/=17`. Did that make any sense? Further hint: print the
resulting `F` in hexadecimal...
And yes, the layout hint involves a mix of the most trendy typographical And yes, the layout hint involves a mix of the most trendy typographical
character juxtaposed against a very ancient one, Not to mention the program character juxtaposed against a very ancient one, not to mention the program
includes some famous name dropping and documents itself as usual. includes some famous name dropping and documents itself as usual.
### Further spoilers, engineering, and obfuscation galore: ### Further spoilers, engineering, and obfuscation galore:
Those wait for you, curious and intrepid reader, in the attached Those wait for you, curious and intrepid reader, in the attached
@@ -216,7 +237,8 @@ bigger constants, so it can zoom up to level 1024 if memory allows, and it tries
its best to avoid dumping core on the poor user when its memory runs out, rather its best to avoid dumping core on the poor user when its memory runs out, rather
it enters freeze mode where you can still travel in calculated frozen it enters freeze mode where you can still travel in calculated frozen
space-time. Well, it's not nice and tame, it even has an escape key, usage space-time. Well, it's not nice and tame, it even has an escape key, usage
message, and to top it all it even avoids gets! message, and to top it all it even avoids `gets(3)`!
### Special thanks: ### Special thanks:
+37 -37
View File
@@ -1,13 +1,13 @@
// APOHLIFE : Annotated Partially Obfuscated 64-bit Hash Life program. // APOHLIFE : Annotated Partially Obfuscated 64-bit Hash Life program.
// This program assumes sizeof(long)==8 (64 bits) and little endianess. // This program assumes sizeof(long)==8 (64 bits) and little endianness.
// Also unaligned (mod 8) long loads support. // Also unaligned (mod 8) long loads support.
// Xlib is evidently used . Should be runnable almost everywhere // Xlib is evidently used . Should be runnable almost everywhere
// with gcc command such as: // with gcc command such as:
// gcc -O3 -std=c99 apholife.c -lX11 -lm // gcc -O3 -std=c99 apholife.c -lX11 -lm
// //
// If you want to understand Hashlife The clearest description with diagrams of the recursion I found was in: // If you want to understand Hashlife The clearest description with diagrams of the recursion I found was in:
// https://jennyhasahat.github.io/hashlife.html // https://web.archive.org/web/20191224211844/https://jennyhasahat.github.io/hashlife.html
// You can also read Tom Rokicki article appearing in DrDobbs // You can also read Tom Rokicki article appearing in DrDobbs
// http://www.drdobbs.com/jvm/an-algorithm-for-compressing-space-and-t/184406478 // http://www.drdobbs.com/jvm/an-algorithm-for-compressing-space-and-t/184406478
// And of course look it up in wikipedia, etc ... // And of course look it up in wikipedia, etc ...
// //
@@ -22,7 +22,7 @@
#define MAXLEV 1024 // Maximal level supported by our universe. #define MAXLEV 1024 // Maximal level supported by our universe.
#define W (32*40l) // Display window size #define W (32*40l) // Display window size
#define H (32*40l) #define H (32*40l)
#define HBITS 29 // This wil determine our memory usage (hash + cells) #define HBITS 29 // This will determine our memory usage (hash + cells)
#define HSIZE (1ll<<HBITS) #define HSIZE (1ll<<HBITS)
#define HMASK (HSIZE -1) #define HMASK (HSIZE -1)
@@ -38,18 +38,18 @@ const unsigned mh=0xf0f0f0f; // This is the mask for the lower nibble in every
// Crucially, whenever we need to encode a quarter-leaf (4*4) such as a result here, we do it using lower 4 // Crucially, whenever we need to encode a quarter-leaf (4*4) such as a result here, we do it using lower 4
// nibbles of an unsigned int, rather rhan a 16 bit short. Remember this when trying to understand all following code! // nibbles of an unsigned int, rather rhan a 16 bit short. Remember this when trying to understand all following code!
// This routine makes heaviest and nicest use of bit twiddling hackers delight like stuff. // This routine makes heaviest and nicest use of bit twiddling hackers delight like stuff.
// If you've read chapter 7.1.3 of Knuths 4A you should be OK with that... // If you've read chapter 7.1.3 of Knuth's 4A you should be OK with that...
ulong q8x8(ulong in) ulong q8x8(ulong in)
{ {
const ulong m4=0x1111111111111111; // We will work doing 16 ops at a time on the sixteen nibbles in a long. const ulong m4=0x1111111111111111; // We will work doing 16 ops at a time on the sixteen nibbles in a long.
for(int j=0;j<2-!g_step;j++){ //We Normaly count to 2 generations here except when g_step=0. for(int j=0;j<2-!g_step;j++){ //We normally count to 2 generations here except when g_step=0.
ulong res=0; ulong res=0;
for(int i=0;i<4;i++) { for(int i=0;i<4;i++) {
ulong o=in>>i & m4; ulong o=in>>i & m4;
o+= in*2>>i & m4; o+= in*2>>i & m4;
o+= in/2>>i & m4; o+= in/2>>i & m4;
o+=(o << 8)+(o >> 8); // And now we have in 'o' nibbles 16 sums each of a 3*3 neighborhood. o+=(o << 8)+(o >> 8); // And now we have in 'o' nibbles 16 sums each of a 3*3 neighborhood.
// This line, implementing Conways GOL rule, is left as an exercise for the reader. Muhahaha... // This line, implementing Conway's GOL rule, is left as an exercise for the reader. Muhahaha...
res |= (((o+m4 & m4*6 ^ 3*m4)+m4 >> 3) & (in >> i | o) & m4) << i; res |= (((o+m4 & m4*6 ^ 3*m4)+m4 >> 3) & (in >> i | o) & m4) << i;
} }
in=res; in=res;
@@ -59,8 +59,8 @@ ulong q8x8(ulong in)
// //
// We have the following tricky but efficient way to encode node and leaf data in the same array of longs in // We have the following tricky but efficient way to encode node and leaf data in the same array of longs in
// an econmoical and aligned manner. We use 32bit indices into the array in lieu of pointers which occupy 64bit // an economical and aligned manner. We use 32bit indices into the array in lieu of pointers which occupy 64bit
// nowdays. This results in almost factor of 2 compression of memory usage. // nowadays. This results in almost factor of 2 compression of memory usage.
// //
// A node at ptr i will be encoded using three longs as follows: // A node at ptr i will be encoded using three longs as follows:
// g_lmem[i] : Two upper quads ptrs (each 32 bits of course). // g_lmem[i] : Two upper quads ptrs (each 32 bits of course).
@@ -78,10 +78,10 @@ ulong q8x8(ulong in)
ulong *g_lmem; ulong *g_lmem;
unsigned *g_hash; unsigned *g_hash;
// //
// The following functions/Macros are heavily used in the hashlife algorithm which is essentialy all about // The following functions/Macros are heavily used in the hashlife algorithm which is essentially all about
// splitting cells into four quadrants, and then creating new cells by joining four quadrants. // splitting cells into four quadrants, and then creating new cells by joining four quadrants.
// We use the term cell to denote *both* leafs and nodes which are stored of course in the same hash. // We use the term cell to denote *both* leafs and nodes which are stored of course in the same hash.
// Quads are always stored in an array conviently called q, with an implicit assumption // Quads are always stored in an array conveniently called q, with an implicit assumption
// that q is 2D with stride *Four*. I.e. to move vertically in q we need to add/sub 4 ... // that q is 2D with stride *Four*. I.e. to move vertically in q we need to add/sub 4 ...
// This way we naturally have a 4*4 array structure on a q[16] vector needed for hashlife recursion. // This way we naturally have a 4*4 array structure on a q[16] vector needed for hashlife recursion.
// We call the quads of each quad subquads. So we can say in q there are four quads and sixteen subquads. // We call the quads of each quad subquads. So we can say in q there are four quads and sixteen subquads.
@@ -90,8 +90,8 @@ unsigned *g_hash;
#define QUADLOOP(x) {int j; for(int i=0;i<4;i++) {j=i+(i&2); x;} } // j is quad index in q. #define QUADLOOP(x) {int j; for(int i=0;i<4;i++) {j=i+(i&2); x;} } // j is quad index in q.
// Get a quad (indexed by i) from a cell pointer. // Get a quad (indexed by i) from a cell pointer.
// The main complication here is the case of leaves that gets splitted to quarters-leaves differenty. // The main complication here is the case of leaves that gets split to quarters-leaves differently.
// Notice that here is the single place we actualy assume little endianity, as it affects the expression // Notice that here is the single place we actually assume little endianness, as it affects the expression
// to get two 32bit words out of each long. // to get two 32bit words out of each long.
unsigned getquad(unsigned cell,int i){ unsigned getquad(unsigned cell,int i){
return g_lmem[cell+1]&8192 ? g_lmem[cell+(i&2)] >> i%2*32 : g_lmem[cell] >> i%2*4+16*(i&2)&mh ; return g_lmem[cell+1]&8192 ? g_lmem[cell+(i&2)] >> i%2*32 : g_lmem[cell] >> i%2*4+16*(i&2)&mh ;
@@ -121,12 +121,12 @@ unsigned hget(unsigned* qi, int level)
{ {
ulong leaf,lh,ll; ulong leaf,lh,ll;
int lv=level>>2; int lv=level>>2;
unsigned hind=0; // Wil be used to calculate hash function unsigned hind=0; // Will be used to calculate hash function
unsigned cell; unsigned cell;
ulong *data=(ulong *)qi; // Here we seem to use little endianity but in fact we dont. as we store ulong *data=(ulong *)qi; // Here we seem to use little endian but in fact we don't. As we store
// and compare the q unsigned array contents to the g_lmem long array. // and compare the q unsigned array contents to the g_lmem long array.
// What we do use is tha fact longs can be loaded and stored from *unaligned* // What we do use is the fact longs can be loaded and stored from *unaligned*
// addresses. So we break pointer punning. // addresses. So we break pointer punning.
if(lv>0) { if(lv>0) {
if(level&1) { if(level&1) {
@@ -152,8 +152,8 @@ unsigned hget(unsigned* qi, int level)
// The last condition above is to avoid a very rare and subtle bug that can happen, for example // The last condition above is to avoid a very rare and subtle bug that can happen, for example
// when searching a leaf, we might find a node instead whose lower data is identical to the leaf's bits // when searching a leaf, we might find a node instead whose lower data is identical to the leaf's bits
// *and* its hash is also similar/close. This is possible but the probablity is very low indeed. // *and* its hash is also similar/close. This is possible but the probability is very low indeed.
// The probablity of encountering this bug is so low that the actual obfuscated entry has not got // The probability of encountering this bug is so low that the actual obfuscated entry has not got
// the fix above but the bug does not seem to happen on the supplied patterns. // the fix above but the bug does not seem to happen on the supplied patterns.
int res_step= lv+1; // res_step is the maximal timestep we can get result for. int res_step= lv+1; // res_step is the maximal timestep we can get result for.
@@ -174,15 +174,15 @@ unsigned hget(unsigned* qi, int level)
unsigned g_ptr=2; // skip the 0 which is null ptr in the hash. Start from 2 in order to leave space unsigned g_ptr=2; // skip the 0 which is null ptr in the hash. Start from 2 in order to leave space
// at zero used by the getin leaf reading code. // at zero used by the getin leaf reading code.
// //
// Finaly we reached the most intersting part of result calculation / hashlife recursion. // Finally we reached the most interesting part of result calculation / hashlife recursion.
// After all the ground work we've layed before, it becomes surprsingly short, heck the // After all the ground work we've laid before, it becomes surprisingly short, heck the
// comments are longer than the code ! // comments are longer than the code !
// //
unsigned calc_result(unsigned cell,ulong leaf,ulong lh,unsigned *qi,int level,int res_step) unsigned calc_result(unsigned cell,ulong leaf,ulong lh,unsigned *qi,int level,int res_step)
{ {
if(!cell) { // Create a new one ... if(!cell) { // Create a new one ...
g_lmem[cell=g_ptr]=leaf; g_lmem[cell=g_ptr]=leaf;
g_lmem[g_ptr+=2]=lh; // This will write some junk in case of leaf but we dont care g_lmem[g_ptr+=2]=lh; // This will write some junk in case of leaf but we don't care
g_ptr+= level>0; g_ptr+= level>0;
} }
if(!level) { if(!level) {
@@ -191,19 +191,19 @@ unsigned calc_result(unsigned cell,ulong leaf,ulong lh,unsigned *qi,int level,in
else { else {
int j; int j;
unsigned q[16]; unsigned q[16];
// Finaly we have reached Hashlifes glorious recusion: make new node from four quadrants and calculate its result. // Finally we have reached Hashlife's glorious recursion: make new node from four quadrants and calculate its result.
// A neat obfuscation/compression trick here is that q can be updated in-place shrinking from 4*4 to 3*3 to 2*2, // A neat obfuscation/compression trick here is that q can be updated in-place shrinking from 4*4 to 3*3 to 2*2,
// all during the sub-steps in the hashlife recursion calculation. Its recommended looking at the link above for // all during the sub-steps in the hashlife recursion calculation. Its recommended looking at the link above for
// some diagrams describing this recursion. // some diagrams describing this recursion.
// 'hr' flag will indicates half recursion. All it does is, that in the second sub-step the 4 recursive calls just join // 'hr' flag will indicates half recursion. All it does is, that in the second sub-step the 4 recursive calls just join
// cells to calculate middle cell, rather then calculate result forward in time. // cells to calculate middle cell, rather then calculate result forward in time.
// //
// This QUADLOOP wil create the 16 subquads data in q. // This QUADLOOP will create the 16 subquads data in q.
// Notice that rather conveniently 2*j here is just 0,2,8,10 which are indices of the quads we want inside the 4*4 q. // Notice that rather conveniently 2*j here is just 0,2,8,10 which are indices of the quads we want inside the 4*4 q.
QUADLOOP(mq(qi[j],q+2*j)); QUADLOOP(mq(qi[j],q+2*j));
unsigned hr = level>g_step-1; unsigned hr = level>g_step-1;
// The whole recursion stuff just becomes the two innocently looking loops below, and hopefuly gcc is decent // The whole recursion stuff just becomes the two innocently looking loops below, and hopefully gcc is decent
// enough to unroll them under -O3 so its also rather efficient as well... // enough to unroll them under -O3 so its also rather efficient as well...
for(int i=0;i<11;i++) if((i+1)&3) q[i]=GQ(i,level-1,0); // Neatly do the first step. 9 recursive calls. for(int i=0;i<11;i++) if((i+1)&3) q[i]=GQ(i,level-1,0); // Neatly do the first step. 9 recursive calls.
QUADLOOP(q[j]=GQ(j, level-1, hr)); //Second step. four recursive calls, and QUADLOOP can be used.... QUADLOOP(q[j]=GQ(j, level-1, hr)); //Second step. four recursive calls, and QUADLOOP can be used....
@@ -215,7 +215,7 @@ unsigned calc_result(unsigned cell,ulong leaf,ulong lh,unsigned *qi,int level,in
return cell; return cell;
} }
// Create the empty space cells/empty universe. Must happen before getin. // Create the empty space cells/empty universe. Must happen before getin().
void init_empty_space(int maxlev) void init_empty_space(int maxlev)
{ {
unsigned q[16]; unsigned q[16];
@@ -230,13 +230,13 @@ void init_empty_space(int maxlev)
} }
// We will use this variable to freeze the state whenever we run out of memory, // We will use this variable to freeze the state whenever we run out of memory,
// So as to avoind core dumps, etc ... // So as to avoid core dumps, etc ...
int g_freeze=0; int g_freeze=0;
// //
// This will advance in time the given cell at the given level by current 2^g_step generations. // This will advance in time the given cell at the given level by current 2^g_step generations.
// the trick here is first expanding enough so the time step will be just looking at the expanded result // the trick here is first expanding enough so the time step will be just looking at the expanded result
// and then shrinking back if neccessary. // and then shrinking back if necessary.
// //
unsigned adv(unsigned cell,int *ilevel) unsigned adv(unsigned cell,int *ilevel)
{ {
@@ -261,7 +261,7 @@ unsigned adv(unsigned cell,int *ilevel)
cell= GQ(0,++level,2); // Then join them to get expanded cell. cell= GQ(0,++level,2); // Then join them to get expanded cell.
} while (level < target); } while (level < target);
cell=g_lmem[cell+1]>>32; // Thats the expanded cell's result which does the actual timestep! cell=g_lmem[cell+1]>>32; // That's the expanded cell's result which does the actual timestep!
// //
// Now we need to see if the result can be shrunk (i.e. is at a too high level). // Now we need to see if the result can be shrunk (i.e. is at a too high level).
// //
@@ -277,13 +277,13 @@ unsigned adv(unsigned cell,int *ilevel)
#define MAXMOVES 500000 #define MAXMOVES 500000
unsigned g_cells[MAXMOVES]; // Will be use to hold input cells and then later to hold moves history unsigned g_cells[MAXMOVES]; // Will be use to hold input cells and then later to hold moves history
double g_gens[MAXMOVES]; // Will be use to hold gens history double g_gens[MAXMOVES]; // Will be use to hold gen's history
// We even have some minimal error handling here :) // We even have some minimal error handling here :)
void error(char *s) {printf("%s\n",s);exit(1);} void error(char *s) {printf("%s\n",s);exit(1);}
// //
// This is our input routine, reading marocell (.mc) golly format. // This is our input routine, reading marocell (.mc) golly format.
// Its quite pedantic but hopefuly does not dump cores on bad input :) // Its quite pedantic but hopefully does not dump cores on bad input :)
// //
int getin(FILE *f,int *lv) int getin(FILE *f,int *lv)
{ {
@@ -321,7 +321,7 @@ int getin(FILE *f,int *lv)
return cell; return cell;
} }
// Thats our output image pixmap. We allocate it with some convenient bundaries. // That's our output image pixmap. We allocate it with some convenient boundaries.
unsigned g_area[(16*16+H)*(16*8+W)+16*8]; unsigned g_area[(16*16+H)*(16*8+W)+16*8];
unsigned *g_out=g_area+16*8*(W+16*8); unsigned *g_out=g_area+16*8*(W+16*8);
unsigned g_stride=W+16*8; unsigned g_stride=W+16*8;
@@ -332,7 +332,7 @@ unsigned g_stride=W+16*8;
double g_mx,g_my; double g_mx,g_my;
int g_pscale; int g_pscale;
// //
// Output support : draw our cells/universe in the output array viewportr. // Output support : draw our cells/universe in the output array viewport.
// Here we use the fact that the array has a padding of 8*16 pixles between lines and 8*16 lines before and after // Here we use the fact that the array has a padding of 8*16 pixles between lines and 8*16 lines before and after
// so that 8x8 leaf drawing becomes simpler (and more importantly shorter!) as there is no clipping check needed... // so that 8x8 leaf drawing becomes simpler (and more importantly shorter!) as there is no clipping check needed...
// sx and sy are just the coordinates of the top left of the cell. cx and cy are used to get the nice // sx and sy are just the coordinates of the top left of the cell. cx and cy are used to get the nice
@@ -340,8 +340,8 @@ int g_pscale;
void draw(unsigned cell,int level,double sx, double sy,int cx,int cy) void draw(unsigned cell,int level,double sx, double sy,int cx,int cy)
{ {
double sz=ldexp(8,level); double sz=ldexp(8,level);
// The if below checks for empty space however we dont return if we // The if below checks for empty space however we don't return if we
// are in small enough scale so as to draw the colored backgroud... // are in small enough scale so as to draw the colored background...
if(cell<MAXLEV*3+2 && g_pscale > 6) return; if(cell<MAXLEV*3+2 && g_pscale > 6) return;
double width2=ldexp(W,g_pscale-5); double width2=ldexp(W,g_pscale-5);
double height2=ldexp(H,g_pscale-5); double height2=ldexp(H,g_pscale-5);
@@ -356,7 +356,7 @@ void draw(unsigned cell,int level,double sx, double sy,int cx,int cy)
} }
if(level) { if(level) {
level--; sz*=0.5; level--; sz*=0.5;
// Notice QUADLOOP macro is also usefull for this quadrants draw loop recursion. // Notice QUADLOOP macro is also useful for this quadrants draw loop recursion.
unsigned q[6]; unsigned q[6];
mq(cell,q); mq(cell,q);
QUADLOOP(draw(q[j],level,sx+i%2*sz,sy+i/2*sz,cx*2+i%2,cy*2+i/2)); QUADLOOP(draw(q[j],level,sx+i%2*sz,sy+i/2*sz,cx*2+i%2,cy*2+i/2));
@@ -369,7 +369,7 @@ void draw(unsigned cell,int level,double sx, double sy,int cx,int cy)
} }
// Generate color background pattern, another nice? coding riddle.. // Generate color background pattern, another nice? coding riddle..
cx^=cy; unsigned background=0x22<<(cx&8?8:cx&64?16:24); cx^=cy; unsigned background=0x22<<(cx&8?8:cx&64?16:24);
// Leaf drawing here supports both positive zoom of upto 4 and negative ofcourse. // Leaf drawing here supports both positive zoom of up to 4 and negative of course.
ulong in=g_lmem[cell]; ulong in=g_lmem[cell];
for(int i=0;i<8<<z;i++) { for(int i=0;i<8<<z;i++) {
for (int j=0;j<8<<z;j++) { for (int j=0;j<8<<z;j++) {
+47
View File
@@ -0,0 +1,47 @@
#!/usr/bin/env bash
#
# try.sh - demonstrate IOCCC winner 2019/dogon
#
# make sure CC is set so that when we do make CC="$CC" it isn't empty. Doing it
# this way allows us to have the user specify a different compiler in an easy
# way.
if [[ -z "$CC" ]]; then
CC="cc"
fi
make CC="$CC" all >/dev/null || exit 1
# clear screen after compilation so that only the entry is shown
clear
show_controls()
{
printf -- "Arrow keys\timage navigation.\n"
printf -- "+\t\tzoom in.\n"
printf -- "-\t\tzoom out.\n"
printf -- "Space\t\ttoggle start/stop.\n"
printf -- "0 (zero)\ttoggle single step/free run mode.\n"
printf -- "Backspace\ttoggle direction for the arrow of time.\n"
printf -- "]\t\tincrease speed (time step) by a factor of 2.\n"
printf -- "[\t\tdecrease speed (time step) by a factor of 2.\n"
echo 1>&2
}
for i in glider.mc infinite_5x5.mc mosquito5.mc message.mc; do
echo "$ ./prog < $i" 1>&2
show_controls
echo "You might wish to press the minus key a few times, wait until you see" 1>&2
echo "white specks and then press space and then the ] a few times." 1>&2
echo "Or you might wish to play with it in other ways. Exit the program to" 1>&2
echo "move on to the next one, if there is another one to view." 1>&2
echo 1>&2
echo "Don't forget to bring the window into focus!" 1>&2
echo 1>&2
read -r -n 1 -p "Press any key to continue (q = quit): "
echo 1>&2
if [[ "$REPLY" == "q" || "$REPLY" == "Q" ]]; then
exit 0
fi
./prog < "$i" 2>/dev/null
done
+9
View File
@@ -3313,6 +3313,15 @@ in the de.sh/de.alt.sh scripts:
# reason that so many words have them. # reason that so many words have them.
``` ```
## 2019 dogon
### STATUS: uses gets() - change to fgets() if possible
### Source code: [2019/dogon/prog.c](2019/dogon/prog.c)
### Information: [2019/dogon/README.md](2019/dogon/README.md)
The author does not it uses `gets()` and one will get warnings but it would be
ideal if this was not the case.
## 2019 duble ## 2019 duble
+10
View File
@@ -4168,6 +4168,16 @@ own sha512sum value.
He also fixed the Makefile so that it compiles with clang in Linux. He also fixed the Makefile so that it compiles with clang in Linux.
He also added the [try.sh](/2019/dogon/try.sh) script.
He also made it possible to easily redefine the memory macro `Z` at compilation
time by modifying the Makefile.
He fixed a link in the spoiler source code. As a spoiler it felt more important
that this was done (some typos were fixed as well but only some - the purpose
was to only correct spelling and only some, not to change wording or anything
else).
## <a name="2019_endoh"></a>[2019/endoh](/2019/endoh/prog.c) ([README.md](/2019/endoh/README.md])) ## <a name="2019_endoh"></a>[2019/endoh](/2019/endoh/prog.c) ([README.md](/2019/endoh/README.md]))