Implementar o jogo da vida em 3D

17

O desafio é encontrar a menor implementação do jogo da vida em 3D ( exemplo ). Estas são as regras:

Células (neste caso, cubos) com apenas 1 ou menos vizinhos morrem, como se fossem solitários.
Se exatamente 5 células cercam uma célula vazia, elas se reproduzem e a preenchem.
Se uma célula tem 8 ou mais vizinhos, morre por superlotação.

Faça pelo menos um 10x10x10, onde as camadas são produzidas individualmente assim:

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

Obviamente, uma simulação 3D gráfica também é aceita.
A posição inicial pode ser codificada permanentemente, mas deve funcionar se for alterada para qualquer posição inicial. Ele deve poder calcular qualquer quantidade de gerações e o usuário deve poder solicitar manualmente a próxima geração.

O menor código em caracteres vence!

Fiz minha própria implementação para qualquer tamanho (cubo): http://jensrenders.site88.net/life3D.htm Você pode usar isso para testar e pode basear seu código no meu, embora eu não tenha comentado .

Jens Renders
fonte
11
Implicada a tag code-golf da sua declaração, encontre a implementação mais curta . Por favor, verifique se é o que você deseja. Você também deve fornecer alguns detalhes sobre como inserir, quantos ciclos, animação sim / não, ... porque é essencial que o code-golf tenha uma especificação robusta.
287 Howard
@ Howard eu adicionei mais algumas especificações, e sim, esqueci a tag code-golf;) obrigado por isso.
Jens processa
@ PeterTaylor Sim exatamente 5, eu vou editá-lo.
Jens Processa
Eu adicionaria detalhes sobre o formato de saída (por exemplo, cada célula deve ser separada por um espaço, como no seu exemplo, uma nova linha entre cada camada de grade da saída, as células vivas e mortas devem ser representadas por caracteres diferentes, e esses devem ser caracteres visíveis .) Além disso, lembre-se de que, se enquadrado como código-golfe, é improvável que você obtenha simulações gráficas.
Jonathan Van Matre
Você realmente quis proibir todas as brechas discutidas nesse meta thread, ou apenas aquelas que atendem aos critérios de (des) aprovação (pontuação de +5, pelo menos duas vezes mais votos positivos e negativos)? Porque eu tenho certeza que eu poderia totalmente pensar em algumas interessantes "brechas" bonitas para discutir ... ;-)
Ilmari Karonen

Respostas:

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

Certamente não é um candidato à vitória, mas essa não era minha intenção. Além disso, isso provavelmente poderia ser reduzido significativamente, apenas descobrindo o número da regra. Eu realmente queria escrever uma visualização (embora eu tenha certeza de que já existem toneladas por aí). Aqui vamos nos):

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

E depois de experimentar várias condições iniciais, obtive coisas como as seguintes:

insira a descrição da imagem aqui

E aqui está um com um tamanho de grade de 20x20x20. Demorou alguns segundos para simular e renderizar:

insira a descrição da imagem aqui

A propósito, isso pressupõe condições de contorno periódicas.

Martin Ender
fonte
Aqueles realmente estão entrando em um estado de equilíbrio ou a animação está parando? No primeiro caso, você me deu algumas idéias puras ...
Kroltan
11
@ Kroltan Já faz um tempo, mas tenho certeza de que eles estavam alcançando o equilíbrio.
Martin Ender
11
Bom obrigado. Fatias individuais do equilíbrio parecem muito com o mapa da sala, por exemplo, um jogo parecido com um rougel.
Kroltan
12

APL, 46

Demorei algum tempo, mas reduzi para 46 caracteres:

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

Essa é uma função que pega uma matriz 3D booleana de qualquer tamanho e calcula a próxima geração, de acordo com as regras fornecidas. As condições de contorno não foram especificadas, então optei por envolver o outro lado, como no espaço toroidal.

Explicação

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

O resultado intermediário mé uma matriz com a mesma forma da matriz original, que conta para cada elemento quantas células estão vivas em sua vizinhança 3 × 3 × 3, incluindo a si mesma. Então:

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

Exemplo

Defina uma matriz aleatória 4 × 4 × 4 com cerca de 1/3 de células = 1 e calcule sua 1ª e 2ª geração. A ⊂[2 3]parte da frente é apenas um truque para imprimir os planos horizontalmente em vez 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
fonte
+1 Resposta muito boa! e, de fato, os limites não foram especificados; portanto, é permitido contornar.
Jens Processa
9

J - 42 char

Estamos assumindo uma placa toroidal (em volta) nas três dimensões. A exibição automática de resultados de J parece seguir as especificações de saída, usando 1para células vivas e 0mortas. Esse código funciona em placas de qualquer largura, comprimento e altura (podem ser 10x10x10, 4x5x6 etc.).

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

Segue uma explicação:

  • ,{3#<i:1 - Subexpressão da lista de compensações para a célula e todos os seus vizinhos.
    • <i:1 - A lista de números inteiros entre 1 e -1, inclusive.
    • ,{3#- Faça três cópias da lista ( 3#) e leve o produto cartesiano ( ,{).
  • (,{3#<i:1)|.&><- Para cada conjunto de deslocamentos 3D, mude a matriz. A um custo de 3 caracteres, você pode mudar |.&>para |.!.0&>não ter wrap-around.
  • [:+/ - Soma todas as tábuas deslocadas.
  • ((1&<*<&8)@-*]+.5=-)~- O verbo externo longo era um gancho, de modo que ele recebe o quadro à esquerda e à direita, e o lado à direita que estivemos mudando e somando. A ~troca é feita por esse verbo interno.
    • 5=- - 1 em cada célula em que a soma das placas deslocadas menos a placa original (ou seja, a contagem de vizinhos) é igual a 5 e 0 em todas as outras.
    • ]+. - Lógico OU acima com a placa original.
    • (1&<*<&8) - 1 se o número estiver sendo comparado entre 1 e 8 exclusivo, 0 caso contrário.
    • (1&<*<&8)@-* - Compare (como acima) a contagem de vizinhos e multiplique (ou seja, AND lógico quando o domínio é apenas 1 ou 0) o resultado OU lógico por isso.

O uso é como no APL, basta aplicar a função ao quadro inicial para cada etapa. J tem um operador de energia funcional ^:para facilitar isso.

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

Eu digo "aleatório" porque o ?.primitivo fornece resultados aleatórios reproduzíveis usando sempre uma semente fixa. ?é o verdadeiro RNG.

algoritmshark
fonte
Maldição J e seu |.verbo imundo !! Bom trabalho.
Tobia