Implement the game of life in 3D

17

2

The challenge is to find the shortest implementation of the game of life in 3D (example). These are the rules:

Cells (in this case, cubes) with only 1 or less neighbours die, as if by lonliness.
If exactly 5 cells surround an empty cell, they breed and fill it.
If a cell has 8 or more neighbours, it dies from overcrowding.

Make it at least a 10x10x10, where the layers are outputted individually like this:

0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 X 0 0 X 0 0 0 0 0
0 0 X X X 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0

Of course, a graphic 3D simulation is also accepted
The starting position may be hardcoded but it must work if it is changed to any starting position. It must be able to calculate any amount of generations, and the user must be able to manually ask for the next generation.

Shortest code in characters wins!

I made my own implementation of this for any (cube) size: http://jensrenders.site88.net/life3D.htm You can use this to test, and you can base your code on mine, although I didn't comment it.

Jens Renders

Posted 2014-02-28T15:54:01.733

Reputation: 1 476

I'd like to see a popcon version of this challenge. – ATaco – 2017-10-01T22:07:32.363

1Implied the code-golf tag from your statement find the shortest implementation. Please check if it is what you want. You should also give some details about how to input, how many cycles, animated yes/no, ... because it is essential for code-golf to have a robust specification. – Howard – 2014-02-28T16:22:20.390

@Howard I added some more specifications, and yes, forgot the code-golf tag ;) thanks for that. – Jens Renders – 2014-02-28T16:30:52.323

@PeterTaylor Yes exactly 5, i'll edit it. – Jens Renders – 2014-02-28T16:55:59.140

I would add specifics about the output format (e.g. each cell must be separated by a space as in your example, one newline between each grid layer of the output, living and dead cells must be represented by different characters, and those must be visible characters.) Also, bear in mind that if framed as code-golf, you are unlikely to get graphic simulations. – Jonathan Van Matre – 2014-02-28T17:35:42.920

Did you really mean to forbid all loopholes discussed in that meta thread, or only those meeting the (dis)approval criteria (+5 score, at least twice as many upvotes as downvotes)? Because I'm sure I could totally think of some pretty interesting "loopholes" to discuss... ;-) – Ilmari Karonen – 2014-02-28T18:53:07.973

Can we get a test case please? Maybe using a smaller size, like 4x4x4, if you don't want to post 2kB of data inline. – Tobia – 2014-02-28T19:53:22.620

I appreciate the online implementation, but I can't get it to work :-( – Tobia – 2014-02-28T22:56:52.567

@Tobia I should say I only tested in google chrome... And you have to change the 0's by X's (capital X) – Jens Renders – 2014-02-28T23:00:19.927

Link is down... :/ – Kroltan – 2014-11-02T20:35:29.940

Answers

14

Mathematica - 120 bytes

g=CellularAutomaton[{(l=Flatten@#;c=l[[14]];n=Total@Drop[l,{14}];Which[n<2||n>7,0,n==5||c==1,1,0<1,0])&,{},{1,1,1}},##]&

Certainly not a contender for the win, but that was not my intention. Also, this could probably be golfed down significantly by just figuring out the rule number. I just really wanted to write a visualisation (although I'm actually sure there are already tons out there). So here we go):

animateGol3d[size_, i_, n_] := 
  ListAnimate[
    Graphics3D[
      Cuboid /@ Position[#, 1], 
      PlotRange -> {{0, size}, {0, size}, {0, size}} + 1
    ] & /@ g[i, n]
  ];

And after experimenting with a bunch of initial conditions, I got things like the following:

enter image description here

And here is one with a grid size of 20x20x20. This took a few seconds to simulate and render:

enter image description here

By the way, this assumes periodic boundary conditions.

Martin Ender

Posted 2014-02-28T15:54:01.733

Reputation: 184 808

Are those really entering a equilibrium state, or it's just the animation stopping? If the former, you gave me some neat ideas... – Kroltan – 2014-11-02T20:34:20.660

1@Kroltan It's been a while, but I'm pretty sure they were reaching equilibrium. – Martin Ender – 2014-11-02T20:44:19.833

1Nice, thanks. Individual slices of the equilibrium look very room-map-y for say, a rougelike game. – Kroltan – 2014-11-02T20:48:31.710

12

APL, 46

It took me some time, but I got it down to 46 chars:

{(5=m)∨⍵∧3>|5.5-m←⊃+/,i∘.⌽i∘.⊖(i←2-⍳3)⌽[2]¨⊂⍵}

This is a function that takes a boolean 3D matrix of any size and computes the next generation, according to the given rules. Boundary conditions were not specified, so I chose to wrap around the other side, as in toroidal space.

Explanation

{                           ⊂⍵}   Take the argument matrix and enclose it in a scalar
               (i←2-⍳3)           Prepare an array with values -1 0 1 and call it i
                       ⌽[2]¨      Shift the matrix along the 2nd dim. by each of -1 0 1
           i∘.⊖                   Then for each result do the same along the 1st dimension
       i∘.⌽                       And for each result again along the 3rd dimension
 m←⊃+/,                           Sum element-wise all 27 shifted matrices and call it m

The intermediate result m is a matrix with the same shape as the original matrix, which counts for each element how many cells are alive in its 3×3×3 neighbourhood, including itself. Then:

           |5.5-m   For each element (x) in m, take its distance from 5.5
       ⍵∧3>         If that distance is <3 (which means 3≤x≤8) and the original cell was 1,
 (5=m)∨             or if the element of m is 5, then the next generation cell will be 1.

Example

Define a random 4×4×4 matrix with about 1/3 cells = 1 and compute its 1st and 2nd generation. The ⊂[2 3] at the front is just a trick to print the planes horizontally instead of vertically:

      ⊂[2 3] m←1=?4 4 4⍴3
 1 0 0 0  1 0 1 0  1 0 1 0  0 0 0 1 
 1 1 0 0  0 0 0 0  0 0 0 1  1 0 1 0 
 0 0 0 0  0 1 0 0  0 0 0 0  0 0 1 0 
 1 1 0 0  0 0 0 1  1 0 0 1  0 0 1 0 
      ⊂[2 3] {(5=m)∨⍵∧3>|5.5-m←⊃+/,i∘.⌽i∘.⊖(i←2-⍳3)⌽[2]¨⊂⍵} m
 0 0 0 0  0 0 1 0  1 0 1 0  0 0 0 0 
 1 0 0 0  0 0 1 0  0 0 0 0  1 0 1 0 
 0 0 0 0  0 1 0 0  0 0 0 0  0 0 1 0 
 1 1 0 0  0 0 0 0  1 0 0 0  0 0 1 0 
      ⊂[2 3] {(5=m)∨⍵∧3>|5.5-m←⊃+/,i∘.⌽i∘.⊖(i←2-⍳3)⌽[2]¨⊂⍵}⍣2⊢ m
 0 0 1 0  1 0 1 0  1 0 1 0  0 0 0 0 
 1 0 1 0  0 0 1 1  0 0 0 0  1 0 1 0 
 1 0 0 0  1 1 0 0  0 0 1 0  1 0 1 0 
 1 1 1 0  1 0 0 1  1 0 1 0  0 0 1 0 

Tobia

Posted 2014-02-28T15:54:01.733

Reputation: 5 455

+1 Very nice answer! and indeed, boundaries were not specified so wrap around is allowed. – Jens Renders – 2014-02-28T23:11:10.557

9

J - 42 char

We are assuming a toroidal board (wraps around) in all three dimensions. J's automatic display of results appears to follow the output spec, using 1 for live cells and 0 for dead. This code works on boards of any width, length, and height (can be 10x10x10, 4x5x6, and so on).

(((1&<*<&8)@-*]+.5=-)~[:+/(,{3#<i:1)|.&><)

An explanation follows:

  • ,{3#<i:1 - Subexpression of the list of offsets for the cell and all its neighbours.
    • <i:1 - The list of integers between 1 and -1 inclusive.
    • ,{3# - Make three copies of the list (3#), and take the Cartesian product (,{).
  • (,{3#<i:1)|.&>< - For each set of 3D offsets, shift the array. At a cost of 3 characters, you can change |.&> to |.!.0&> to not have wrap-around.
  • [:+/ - Sum the all the shifted boards together.
  • ((1&<*<&8)@-*]+.5=-)~ - The long outer verb was a hook so it receives the board on the left and the right, and the side on the right we've been shifting and summing. The ~ swaps this around for this inner verb.
    • 5=- - 1 in each cell that the sum-of-shifted-boards minus the original board (i.e. the neighbour count) equals 5, and 0 in all others.
    • ]+. - Logical OR the above with the original board.
    • (1&<*<&8) - 1 if the number being compared between 1 and 8 exclusive, 0 otherwise.
    • (1&<*<&8)@-* - Compare (as above) the neighbour count, and multiply (i.e. logical AND when the domain is only 1 or 0) the logical OR result by this.

Usage is as with the APL, just apply the function to the initial board for each step. J has a functional-power operator ^: to make this easy.

   life =: (((1&<*<&8)@-*]+.5=-)~[:+/(,{3#<i:1)|.&><)  NB. for convenience
   board =: 1 = ?. 4 4 4 $ 4  NB. "random" 4x4x4 board with approx 1/4 ones
   <"2 board  NB. we box each 2D plane for easier viewing
+-------+-------+-------+-------+
|0 0 0 0|1 1 0 0|0 1 0 0|0 0 1 0|
|0 1 0 0|0 0 0 0|0 0 0 1|1 0 0 0|
|0 0 0 0|0 0 1 0|0 1 0 0|0 0 0 1|
|1 1 0 0|1 0 0 0|0 0 0 1|0 1 1 0|
+-------+-------+-------+-------+
   <"2 life board
+-------+-------+-------+-------+
|0 0 0 0|0 1 0 1|0 1 0 0|0 0 1 0|
|1 1 1 1|0 0 0 0|0 0 0 1|1 1 0 0|
|0 0 0 0|0 0 1 1|0 1 0 0|0 0 0 1|
|1 0 0 0|1 0 0 1|0 0 0 1|0 1 1 1|
+-------+-------+-------+-------+
   <"2 life^:2 board  NB. two steps
+-------+-------+-------+-------+
|0 0 0 0|0 1 0 0|0 1 0 0|0 0 0 0|
|0 1 0 0|0 0 0 0|0 0 0 1|0 1 0 0|
|0 0 0 0|0 0 0 0|0 1 0 0|0 0 0 0|
|0 0 0 0|0 0 0 1|0 0 0 0|0 1 1 1|
+-------+-------+-------+-------+
   <"2 life^:3 board  NB. etc
+-------+-------+-------+-------+
|0 1 0 0|1 1 1 0|0 1 0 0|0 1 0 0|
|0 1 0 0|1 0 1 0|1 0 1 0|1 1 1 0|
|1 0 0 0|0 0 0 0|0 1 0 0|0 1 0 0|
|0 0 1 0|0 0 0 0|0 1 0 0|0 1 1 0|
+-------+-------+-------+-------+

I say "random" because the ?. primitive gives reproducible random results by using a fixed seed every time. ? is the true RNG.

algorithmshark

Posted 2014-02-28T15:54:01.733

Reputation: 8 144

Curse J and its foul |. verb!! Good job. – Tobia – 2014-03-01T17:56:14.780