Implementa el juego de la vida en 3D

17

El desafío es encontrar la implementación más corta del juego de la vida en 3D ( ejemplo ). Estas son las reglas:

Las células (en este caso, cubos) con solo 1 o menos vecinos mueren, como por soledad.
Si exactamente 5 celdas rodean una celda vacía, se reproducen y la llenan.
Si una celda tiene 8 o más vecinos, muere por hacinamiento.

Que sea al menos 10x10x10, donde las capas se emiten individualmente de esta manera:

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

Por supuesto, también se acepta una simulación 3D gráfica.
La posición inicial puede estar codificada pero debe funcionar si se cambia a cualquier posición inicial. Debe poder calcular cualquier cantidad de generaciones, y el usuario debe poder solicitar manualmente la próxima generación.

¡El código más corto en caracteres gana!

Hice mi propia implementación de esto para cualquier tamaño (cubo): http://jensrenders.site88.net/life3D.htm. Puedes usar esto para probar y puedes basar tu código en el mío, aunque no lo comenté. .

Jens Renders
fuente
1
La etiqueta de código de golf implícita de su declaración encuentra la implementación más corta . Por favor, compruebe si es lo que quiere. También debe dar algunos detalles sobre cómo ingresar, cuántos ciclos, animado sí / no, ... porque es esencial que el código de golf tenga una especificación robusta.
Howard
@Howard agregué algunas especificaciones más, y sí, olvidé la etiqueta code-golf;) gracias por eso.
Jens Renders
@PeterTaylor Sí exactamente 5, lo editaré.
Jens Renders
Agregaría detalles sobre el formato de salida (por ejemplo, cada celda debe estar separada por un espacio como en su ejemplo, una nueva línea entre cada capa de cuadrícula de la salida, las celdas vivas y muertas deben estar representadas por diferentes caracteres, y esos deben ser caracteres visibles .) Además, tenga en cuenta que si se enmarca como código de golf, es poco probable que obtenga simulaciones gráficas.
Jonathan Van Matre
¿Realmente quisiste prohibir todas las lagunas legales discutidas en ese metahilo, o solo aquellas que cumplen con los criterios de (des) aprobación (puntaje +5, al menos el doble de votos positivos que negativos)? Porque estoy seguro de que podría totalmente pensar en algunas interesantes "lagunas" bonitas para discutir ... ;-)
Ilmari Karonen

Respuestas:

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}},##]&

Ciertamente no soy un candidato para la victoria, pero esa no era mi intención. Además, esto probablemente podría reducirse significativamente al descubrir el número de la regla. Solo quería escribir una visualización (aunque estoy seguro de que ya hay toneladas). Así que, aquí vamos):

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

Y después de experimentar con un montón de condiciones iniciales, obtuve cosas como las siguientes:

ingrese la descripción de la imagen aquí

Y aquí hay uno con un tamaño de cuadrícula de 20x20x20. Esto tomó unos segundos para simular y renderizar:

ingrese la descripción de la imagen aquí

Por cierto, esto supone condiciones de contorno periódicas.

Martin Ender
fuente
¿Están realmente entrando en un estado de equilibrio, o es solo la parada de la animación? Si es lo primero, me diste algunas
buenas
1
@Kroltan Ha pasado un tiempo, pero estoy bastante seguro de que estaban llegando al equilibrio.
Martin Ender
1
Genial gracias. Las rebanadas individuales del equilibrio se ven muy como en el mapa de la habitación, por ejemplo, un juego de rougelike.
Kroltan el
12

APL, 46

Me tomó algo de tiempo, pero lo reduje a 46 caracteres:

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

Esta es una función que toma una matriz 3D booleana de cualquier tamaño y calcula la próxima generación, de acuerdo con las reglas dadas. Las condiciones de contorno no se especificaron, por lo que decidí envolver el otro lado, como en el espacio toroidal.

Explicación

{                           ⊂⍵}   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

El resultado intermedio mes una matriz con la misma forma que la matriz original, que cuenta para cada elemento cuántas células están vivas en su vecindario 3 × 3 × 3, incluido él mismo. Luego:

           |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.

Ejemplo

Defina una matriz aleatoria de 4 × 4 × 4 con aproximadamente 1/3 celdas = 1 y calcule su primera y segunda generación. El ⊂[2 3]frente es solo un truco para imprimir los planos horizontalmente en lugar de verticalmente:

      ⊂[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
fuente
+1 Muy buena respuesta! y de hecho, los límites no se especificaron, por lo que se permite envolver.
Jens rinde
9

J - 42 char

Asumimos un tablero toroidal (se envuelve) en las tres dimensiones. La visualización automática de resultados de J parece seguir las especificaciones de salida, que se utilizan 1para células vivas y 0para muertos. Este código funciona en tableros de cualquier ancho, largo y alto (puede ser 10x10x10, 4x5x6, etc.).

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

Sigue una explicación:

  • ,{3#<i:1 - Subexpresión de la lista de compensaciones para la celda y todos sus vecinos.
    • <i:1 - La lista de enteros entre 1 y -1 inclusive.
    • ,{3#- Haga tres copias de la lista ( 3#) y tome el producto cartesiano ( ,{).
  • (,{3#<i:1)|.&><- Para cada conjunto de desplazamientos 3D, cambie la matriz. A un costo de 3 caracteres, puede cambiar |.&>a |.!.0&>no tener envolvente.
  • [:+/ - Suma todos los tableros desplazados juntos.
  • ((1&<*<&8)@-*]+.5=-)~- El verbo externo largo era un gancho, por lo que recibe el tablero a la izquierda y a la derecha, y el lado a la derecha hemos estado cambiando y sumando. Los ~intercambios de este verbo interno.
    • 5=- - 1 en cada celda que la suma de tableros desplazados menos el tablero original (es decir, el recuento de vecinos) es igual a 5 y 0 en todos los demás.
    • ]+. - Lógico O lo anterior con el tablero original.
    • (1&<*<&8) - 1 si el número que se compara entre 1 y 8 es exclusivo, 0 en caso contrario.
    • (1&<*<&8)@-* - Compare (como anteriormente) el recuento de vecinos y multiplique (es decir, AND lógico cuando el dominio es solo 1 o 0) el resultado OR lógico por esto.

El uso es como con el APL, simplemente aplique la función a la placa inicial para cada paso. J tiene un operador de potencia funcional ^:para facilitar esto.

   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|
+-------+-------+-------+-------+

Digo "aleatorio" porque la ?.primitiva da resultados aleatorios reproducibles al usar una semilla fija cada vez. ?Es el verdadero RNG.

Algoritmo de tiburón
fuente
¡Maldición J y su |.verbo asqueroso ! Buen trabajo.
Tobia