Zaimplementuj grę życia w 3D

17

Wyzwanie polega na znalezieniu najkrótszej implementacji gry życia w 3D ( przykład ). Oto zasady:

Komórki (w tym przypadku kostki) z tylko 1 sąsiadem lub mniej umierają, jakby przez samotność.
Jeśli dokładnie 5 komórek otacza pustą komórkę, rozmnażają się i wypełniają ją.
Jeśli komórka ma 8 lub więcej sąsiadów, umiera z powodu przeludnienia.

Zrób co najmniej 10x10x10, gdzie warstwy są wyprowadzane indywidualnie w następujący sposób:

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

Oczywiście, graficzna symulacja 3D jest również akceptowana
. Pozycja początkowa może być zakodowana na stałe, ale musi działać, jeśli zostanie zmieniona na dowolną pozycję początkową. Musi być w stanie obliczyć dowolną liczbę pokoleń, a użytkownik musi być w stanie ręcznie poprosić o następną generację.

Najkrótszy kod ze znaków wygrywa!

Zrobiłem własną implementację tego dla dowolnego rozmiaru (kostki): http://jensrenders.site88.net/life3D.htm Możesz użyć tego do testowania i możesz oprzeć swój kod na moim, chociaż tego nie skomentowałem .

Jens Renders
źródło
1
Implikował tag code-golf z twojego oświadczenia, znajdź najkrótszą implementację . Sprawdź, czy tego właśnie chcesz. Powinieneś także podać kilka szczegółów na temat sposobu wprowadzania, liczby cykli, animowanego tak / nie, ... ponieważ kluczowe jest, aby kod-golf miał solidną specyfikację.
Howard
@Jak dodałem trochę więcej specyfikacji i tak, zapomniałem tagu code-golf;) dzięki za to.
Jens Renders
@PeterTaylor Tak dokładnie 5, będę go edytować.
Jens Renders
Dodałbym szczegóły dotyczące formatu wyjściowego (np. Każda komórka musi być oddzielona spacją jak w twoim przykładzie, jedna nowa linia między każdą warstwą siatki danych wyjściowych, żywe i martwe komórki muszą być reprezentowane przez różne znaki, a te muszą być widocznymi znakami .) Pamiętaj też, że jeśli grasz w golfa kodowego, prawdopodobnie nie otrzymasz symulacji graficznych.
Jonathan Van Matre
Czy naprawdę chciałeś zakazać wszystkich omawianych luk? w tym meta wątku, czy tylko tych spełniających (nie) kryteria zatwierdzenia (wynik +5, co najmniej dwa razy więcej głosów pozytywnych niż ocen negatywnych)? Ponieważ jestem pewien, że mogłem całkowicie wymyślić jakieś całkiem interesujące „luki” do omówienia ... ;-)
Ilmari Karonen

Odpowiedzi:

14

Mathematica - 120 bajtów

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

Z pewnością nie pretendent do wygranej, ale nie taki był mój zamiar. Prawdopodobnie można to znacznie obniżyć, po prostu ustalając numer reguły. Po prostu bardzo chciałem napisać wizualizację (chociaż jestem pewien, że jest tam już mnóstwo ton). Więc zaczynamy):

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

Po eksperymentowaniu z szeregiem warunków początkowych otrzymałem następujące rzeczy:

wprowadź opis zdjęcia tutaj

A oto jeden z rozmiarem siatki 20x20x20. Symulacja i renderowanie zajęło kilka sekund:

wprowadź opis zdjęcia tutaj

Nawiasem mówiąc, zakłada to okresowe warunki brzegowe.

Martin Ender
źródło
Czy naprawdę wchodzą w stan równowagi, czy tylko animacja się zatrzymuje? Jeśli ci pierwsi, daliście mi jakieś
fajne
1
@Kroltan Minęło trochę czasu, ale jestem pewien, że osiągnęli równowagę.
Martin Ender
1
Fajnie dzięki. Poszczególne wycinki równowagi wyglądają bardzo podobnie do mapy pokoju, powiedzmy, w stylu przypominającym rougel.
Kroltan
12

APL, 46

Zajęło mi to trochę czasu, ale zredukowałem go do 46 znaków:

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

Jest to funkcja, która przyjmuje logiczną macierz 3D o dowolnym rozmiarze i oblicza następną generację, zgodnie z podanymi regułami. Warunki brzegowe nie zostały określone, więc postanowiłem owinąć się po drugiej stronie, jak w przestrzeni toroidalnej.

Wyjaśnienie

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

Pośrednim wynikiem mjest matryca o takim samym kształcie jak oryginalna matryca, która liczy dla każdego elementu, ile komórek żyje w swoim otoczeniu 3 × 3 × 3, włączając siebie. Następnie:

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

Przykład

Zdefiniuj losową macierz 4 × 4 × 4 o około 1/3 komórek = 1 i oblicz jej 1. i 2. generacji. Z ⊂[2 3]przodu jest tylko sztuczką, aby wydrukować płaszczyzny w poziomie zamiast w pionie:

      ⊂[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
źródło
+1 Bardzo ładna odpowiedź! i w rzeczywistości granice nie zostały określone, więc owijanie jest dozwolone.
Jens Renders
9

J - 42 char

Zakładamy toroidalną tablicę (owijającą się) we wszystkich trzech wymiarach. Automatyczne wyświetlanie wyników przez J wydaje się zgodne ze specyfikacją wyjściową, 1dla żywych komórek i 0dla martwych. Ten kod działa na płytach o dowolnej szerokości, długości i wysokości (może wynosić 10x10x10, 4x5x6 itd.).

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

Wyjaśnienie jest następujące:

  • ,{3#<i:1 - Podwyrażenie listy przesunięć dla komórki i wszystkich jej sąsiadów.
    • <i:1 - Lista liczb całkowitych od 1 do -1 włącznie.
    • ,{3#- Zrób trzy kopie listy ( 3#) i weź iloczyn kartezjański ( ,{).
  • (,{3#<i:1)|.&><- Dla każdego zestawu przesunięć 3D przesuń tablicę. Kosztem 3 znaków, można zmienić |.&>, aby |.!.0&>nie mieć Wrap-around.
  • [:+/ - Zsumuj wszystkie przesunięte deski razem.
  • ((1&<*<&8)@-*]+.5=-)~- Długi czasownik zewnętrzny był hakiem, więc otrzymuje tablicę po lewej i prawej stronie, a po prawej stronie przesuwaliśmy i sumowaliśmy. W ~swapy to wokół tej wewnętrznej czasownika.
    • 5=- - 1 w każdej komórce, że suma przesuniętych desek minus pierwotna plansza (tj. Liczba sąsiadów) wynosi 5, a 0 we wszystkich pozostałych.
    • ]+. - Logiczne LUB powyższe z oryginalną tablicą.
    • (1&<*<&8) - 1, jeśli liczba jest porównywana między 1 a 8 wyłącznie, 0 w przeciwnym razie.
    • (1&<*<&8)@-* - Porównaj (jak wyżej) liczbę sąsiadów i pomnóż (tj. Logiczne AND, gdy domena ma tylko 1 lub 0), logiczny wynik OR przez to.

Użycie jest takie jak w przypadku APL, po prostu zastosuj funkcję na płycie początkowej dla każdego kroku. J ma funkcjonalny operator mocy, ^:aby to ułatwić.

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

Mówię „losowo”, ponieważ ?.prymityw daje powtarzalne losowe wyniki za każdym razem przy użyciu ustalonego ziarna. ?jest prawdziwym RNG.

algorytmshark
źródło
Przeklnij J i jego faul |.! Dobra robota.
Tobia