Merge pull request #1717 from xexyl/dogon2019-try
This commit is contained in:
7 files changed
+187
-94
No files matched your search
@@ -6,4 +6,5 @@ indent
|
||||
indent.c
|
||||
indent.o
|
||||
prog
|
||||
prog.alt
|
||||
prog.orig
|
||||
+7
-3
@@ -59,9 +59,13 @@ CSTD= -std=gnu17
|
||||
#
|
||||
ARCH=
|
||||
|
||||
# Variable to simplify changing memory usage
|
||||
#
|
||||
MEMORY= 0x20000000
|
||||
|
||||
# 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
|
||||
#
|
||||
@@ -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
|
||||
TARGET= ${PROG} apholife
|
||||
#
|
||||
ALT_OBJ=
|
||||
ALT_TARGET=
|
||||
ALT_OBJ= ${PROG}.alt.o
|
||||
ALT_TARGET= ${PROG}.alt
|
||||
|
||||
|
||||
#################
|
||||
|
||||
+76
-54
@@ -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:
|
||||
|
||||
```sh
|
||||
@@ -15,24 +26,19 @@ make
|
||||
### Try:
|
||||
|
||||
```sh
|
||||
./prog < glider.mc
|
||||
|
||||
./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
|
||||
./try.sh
|
||||
```
|
||||
|
||||
Make sure that you keep focus of windows in mind when going back and forth to
|
||||
the program and the script.
|
||||
|
||||
|
||||
## Judges' remarks:
|
||||
|
||||
[1991/davidguy](http://ioccc.org/years.html#1991_davidguy),
|
||||
[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.
|
||||
|
||||
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,
|
||||
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
|
||||
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.
|
||||
|
||||
|
||||
## Author's remarks:
|
||||
|
||||
|
||||
### What is it?
|
||||
|
||||
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
|
||||
necessary, then press space. For acceleration press ']' several times. That's
|
||||
input `.mc` files as standard input. Press `-` several time to zoom out if
|
||||
necessary, then press space. For acceleration press `]` several times. That's
|
||||
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.
|
||||
* 1940s: John Von Neumann and Stanislav Ulam are interested in artificial life
|
||||
eventually kick starting research on Cellular Automata.
|
||||
* 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
|
||||
Gardner's Scientific American column.
|
||||
* 1970's: According to Knuth, a significant portion of computer time in the
|
||||
seems quite interesting. [Conway's Game of
|
||||
Life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life) gets published in
|
||||
[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
|
||||
footing the bill.
|
||||
* 1984: Bill Gosper invents the
|
||||
[Hashlife](https://en.wikipedia.org/wiki/Hashlife) algorithm. His
|
||||
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
|
||||
[Hashlife](https://en.wikipedia.org/wiki/Hashlife) in C, efficient, stable and
|
||||
production ready for modern machines.
|
||||
* 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.
|
||||
\
|
||||
|
||||
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
|
||||
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
|
||||
@@ -108,20 +123,21 @@ the header comment of each.
|
||||
* `]`: Increase 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
|
||||
just jump by the amount that was specified before. However going forward is
|
||||
Notice that when going backward in time we ignore the current time step setting
|
||||
and just jump by the amount that was specified before. However going forward is
|
||||
always using the current time step.
|
||||
|
||||
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
|
||||
is the current macrocell (L) and which zoom Scale you are watching (S).
|
||||
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`).
|
||||
|
||||
### Portability issues.
|
||||
|
||||
### Portability issues
|
||||
|
||||
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
|
||||
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
|
||||
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 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
|
||||
assumes unaligned loads of 64 bits longs are supported, i.e. it assumes that a
|
||||
long can be loaded from any address that could hold an int otherwise. On non
|
||||
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
|
||||
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:
|
||||
|
||||
@@ -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
|
||||
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`,
|
||||
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
|
||||
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
|
||||
integers are used in the drawing code. Reverting to doubles could have remedied
|
||||
Zooming out past about S58 scale will enter a buggy twilight zone as only `long`
|
||||
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
|
||||
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
|
||||
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 ?
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
`-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
|
||||
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.
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
### Obfuscations.
|
||||
|
||||
### Obfuscations:
|
||||
|
||||
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
|
||||
mercilessly reused. In the main there's even a nice little identifier first used
|
||||
as a global and then reused (shadowed) in the *same* scope, and this did not
|
||||
produce even a little squeak of a warning from the compiler! Macro compression is
|
||||
rather sparingly used, however magic numbers abound everywhere, and bit twiddling
|
||||
is magical too. Do you know for example why we have unsigned F=-1 ? (No warning
|
||||
there of course :) Hint: Later in the program you have F/=17. Did that make any
|
||||
sense? Further hint: print the resulting F in hexadecimal...
|
||||
mercilessly reused. In the `main()` function there's even a nice little
|
||||
identifier first used as a global and then reused (shadowed) in the *same*
|
||||
scope, and this did not produce even a little squeak of a warning from the
|
||||
compiler! Macro compression is rather sparingly used, however magic numbers
|
||||
abound everywhere, and bit twiddling is magical too. Do you know for example why
|
||||
we have `unsigned F=-1` ? (No warning there of course :) Hint: Later in the
|
||||
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
|
||||
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.
|
||||
|
||||
|
||||
### Further spoilers, engineering, and obfuscation galore:
|
||||
|
||||
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
|
||||
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
|
||||
message, and to top it all it even avoids gets!
|
||||
message, and to top it all it even avoids `gets(3)`!
|
||||
|
||||
|
||||
### Special thanks:
|
||||
|
||||
|
||||
+37
-37
@@ -1,13 +1,13 @@
|
||||
// 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.
|
||||
// Xlib is evidently used . Should be runnable almost everywhere
|
||||
// with gcc command such as:
|
||||
// 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:
|
||||
// https://jennyhasahat.github.io/hashlife.html
|
||||
// You can also read Tom Rokicki article appearing in DrDobbs
|
||||
// If you want to understand Hashlife The clearest description with diagrams of the recursion I found was in:
|
||||
// https://web.archive.org/web/20191224211844/https://jennyhasahat.github.io/hashlife.html
|
||||
// You can also read Tom Rokicki article appearing in DrDobbs
|
||||
// http://www.drdobbs.com/jvm/an-algorithm-for-compressing-space-and-t/184406478
|
||||
// And of course look it up in wikipedia, etc ...
|
||||
//
|
||||
@@ -22,7 +22,7 @@
|
||||
#define MAXLEV 1024 // Maximal level supported by our universe.
|
||||
#define W (32*40l) // Display window size
|
||||
#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 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
|
||||
// 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.
|
||||
// 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)
|
||||
{
|
||||
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;
|
||||
for(int i=0;i<4;i++) {
|
||||
ulong o=in>>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.
|
||||
// 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;
|
||||
}
|
||||
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
|
||||
// an econmoical 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.
|
||||
// an economical and aligned manner. We use 32bit indices into the array in lieu of pointers which occupy 64bit
|
||||
// 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:
|
||||
// g_lmem[i] : Two upper quads ptrs (each 32 bits of course).
|
||||
@@ -78,10 +78,10 @@ ulong q8x8(ulong in)
|
||||
ulong *g_lmem;
|
||||
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.
|
||||
// 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 ...
|
||||
// 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.
|
||||
@@ -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.
|
||||
|
||||
// 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.
|
||||
// Notice that here is the single place we actualy assume little endianity, as it affects the expression
|
||||
// The main complication here is the case of leaves that gets split to quarters-leaves differently.
|
||||
// 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.
|
||||
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 ;
|
||||
@@ -121,12 +121,12 @@ unsigned hget(unsigned* qi, int level)
|
||||
{
|
||||
ulong leaf,lh,ll;
|
||||
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;
|
||||
|
||||
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.
|
||||
// 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.
|
||||
if(lv>0) {
|
||||
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
|
||||
// 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.
|
||||
// The probablity of encountering this bug is so low that the actual obfuscated entry has not got
|
||||
// *and* its hash is also similar/close. This is possible but the probability is very low indeed.
|
||||
// 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.
|
||||
|
||||
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
|
||||
// at zero used by the getin leaf reading code.
|
||||
//
|
||||
// Finaly we reached the most intersting part of result calculation / hashlife recursion.
|
||||
// After all the ground work we've layed before, it becomes surprsingly short, heck the
|
||||
// Finally we reached the most interesting part of result calculation / hashlife recursion.
|
||||
// After all the ground work we've laid before, it becomes surprisingly short, heck the
|
||||
// comments are longer than the code !
|
||||
//
|
||||
unsigned calc_result(unsigned cell,ulong leaf,ulong lh,unsigned *qi,int level,int res_step)
|
||||
{
|
||||
if(!cell) { // Create a new one ...
|
||||
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;
|
||||
}
|
||||
if(!level) {
|
||||
@@ -191,19 +191,19 @@ unsigned calc_result(unsigned cell,ulong leaf,ulong lh,unsigned *qi,int level,in
|
||||
else {
|
||||
int j;
|
||||
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,
|
||||
// all during the sub-steps in the hashlife recursion calculation. Its recommended looking at the link above for
|
||||
// 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
|
||||
// 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.
|
||||
QUADLOOP(mq(qi[j],q+2*j));
|
||||
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...
|
||||
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....
|
||||
@@ -215,7 +215,7 @@ unsigned calc_result(unsigned cell,ulong leaf,ulong lh,unsigned *qi,int level,in
|
||||
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)
|
||||
{
|
||||
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,
|
||||
// So as to avoind core dumps, etc ...
|
||||
// So as to avoid core dumps, etc ...
|
||||
int g_freeze=0;
|
||||
|
||||
//
|
||||
// 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
|
||||
// and then shrinking back if neccessary.
|
||||
// and then shrinking back if necessary.
|
||||
//
|
||||
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.
|
||||
} 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).
|
||||
//
|
||||
@@ -277,13 +277,13 @@ unsigned adv(unsigned cell,int *ilevel)
|
||||
|
||||
#define MAXMOVES 500000
|
||||
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 :)
|
||||
void error(char *s) {printf("%s\n",s);exit(1);}
|
||||
//
|
||||
// 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)
|
||||
{
|
||||
@@ -321,7 +321,7 @@ int getin(FILE *f,int *lv)
|
||||
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_out=g_area+16*8*(W+16*8);
|
||||
unsigned g_stride=W+16*8;
|
||||
@@ -332,7 +332,7 @@ unsigned g_stride=W+16*8;
|
||||
double g_mx,g_my;
|
||||
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
|
||||
// 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
|
||||
@@ -340,8 +340,8 @@ int g_pscale;
|
||||
void draw(unsigned cell,int level,double sx, double sy,int cx,int cy)
|
||||
{
|
||||
double sz=ldexp(8,level);
|
||||
// The if below checks for empty space however we dont return if we
|
||||
// are in small enough scale so as to draw the colored backgroud...
|
||||
// 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 background...
|
||||
if(cell<MAXLEV*3+2 && g_pscale > 6) return;
|
||||
double width2=ldexp(W,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) {
|
||||
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];
|
||||
mq(cell,q);
|
||||
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..
|
||||
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];
|
||||
for(int i=0;i<8<<z;i++) {
|
||||
for (int j=0;j<8<<z;j++) {
|
||||
|
||||
Executable
+47
@@ -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
|
||||
@@ -3313,6 +3313,15 @@ in the de.sh/de.alt.sh scripts:
|
||||
# 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
|
||||
|
||||
|
||||
@@ -4168,6 +4168,16 @@ own sha512sum value.
|
||||
|
||||
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]))
|
||||
|
||||
|
||||
Reference in new issue
Block a user