This was mostly (at least in general gist) 'written' in my head before I even saw the closing line of the above post. With the caveat that I'm really not an expert, just an enthusiastic wannabe-polymath (but so far failed). But.. luckily, it seems you
like my long posts. And as that is very much my default mode...
I actually implemented Conway's Game of Life in 3 dimensions today. Right now, the cubes only check 6 directions (+ or - 1 to each axis) which makes it even less sustainable than the regular game of life. I'll mess around with it and see if I can find a good balance between processing time and sustainability. Then...honestly no idea how to do an interface, but I could put that together and release it. It's been a satisfying problem.
The general algorithm for N-dimensional adjacent+diagonal checking would be:
for D1 (-1..+1) {
for D2 (-1..+1) {
for D3 (-1..+1) {
[...any more Ds you want up to DN..]
next loop if (D1 D2 D3 [as needed, up to DN] all equal 0) // i.e. skip if no non-zero values
countTally+=CheckNeighbour(here.axis1+D1,here.axis2+D2,here.axis3+D3[,...here.axisN+DN])
// However you count things and accumulate them, in your version
}
}
}
// now use the countTally
There's a version of that which just loops by N, within a handler that holds the iterations of all D[N] array items, but that's the one you can manually hardcode to handle greater or lesser dimensions, which is all you want if you're not going arbitrarily far up. And is better than
for D (1..N) { checkNeighbour(here.axisD±1) /* etc */ }, as it gives you the corners (compound displacements) without needing to ensure you're covering all cases explicitly.
Additionally, the traditional Conway "machine" is described by B3/S23, just two number-sets. The number of neighbours that cause a 'birth' (empty cell being made to live, i.e. 3 live neighbours) and the number that cause a 'survival' (the living cell not dying, here being 2 or 3 live neighbours). Even in 2D GoLs, you can use other sets, to create different evolutions of pattern. And it need not be contiguous or even make any particular sense (e.g. B0/S02468, top of my head, no idea if that does anything interesting other than autofill an empty-field into permanent fullness!) but there are indeed interesting versions that are not B3/S23.
My suggestion is that you tweak B3/S23 into something that seems to work 'as well' in 3D as 2D, by at least making S=(2,3) into something higher-topped (maybe higher-bottomed, too?) to reflect the fact that you have 26 'neighbours' instead of just the 8. But whether some B(9?)/S6789[10,..?] is linearly equivalent or not would be trial and error on your part.
Perhaps try prospective formulae upon every single 3x3x3 pattern (you can code that, automatically, similarly to the the neighbour-code, above) then either procedurally or visually check to see if any 3x3x3 cycles emerge from that, to confirm that statics, oscilators and gliders result (even better, emerging gliders but I think 3x3x3 might be too small for a classic glider-gun unless it expands out). If you get any likely B#/S#, you can pay more attention to these, but any variation of B and S rule that just goes superdead or superlive (or superstatic) for all cases, within a few cycles, can probably be readily forgotten.
Visualisation is a doozy. I'd probably do a grid of grids (well, a line of grids, unless doing 4D), where you show a subset of the field (say start with 15x15) in a number of slices (15 of them), the centre of the central one being tile 0,0,0 etc... Rendering a 3D view (isometric would do, no need for complicated viewport stuff,perhaps just add visual cues like hypsometric shading/shaded relief to add depth cues to distinguish near 'cubes' from non-near ones that just look like they are touching) can be done in a bit of canvas off to one side of the grid-slices area, if you like, but neither view alone will be perfect. (Like 2D GoL, you have to consider how big the visual grid can be, what happens if the active cells get near the border[1], etc. But you'll have decided what method you like for the 2D version, I imagine.)
All of this, and more, will have been addressed by 'professional' GoL academics and fanboys alike. There'll be lists of other "useful" 2D B/S rulesets, and perhaps even someone exhaustively proven any equivalently interesting 3D (or moreD!) rulesets. Or else proven them as mathematically implausible for the same sort of reason as Fermat doesn't work well with indices beyond 2...
But I think you'll enjoy finding out. I'm pushing some of my own 'clues' as to how *I* would do this (again[2]) to perhaps help you on your own way. But it
might just end up being a distraction, so be sure to use your proven skills at scheduling to only spend a limited amount of time on it before actually stopping yourself from tweaking it further and sinking more of your time into it than you planned. This is one of those rabbithole projects, if I'm any judge.
[1] Your playing array ought to be bigger than the visual window, unless you're implementing wrap-around in all directions, and maybe you allow it to increase the array as more rows/columns/slices are needed (or shift the playing field over, if it's only "bursting out" on one edge).
[2] Hands up... Yes, I've done it before, but with much more primitive computers/code. And I could have really done with more than a few kB of working memory and a relatively low-res screen to output through! Darnit, I might just try it again myself, I could probably do it in Perl with only about half the time spent trying to decide how to implement the data-structure so that I don't eat up memory like nobody's business...