Najkrótsza gra życia


59

Gra życia Conwaya to klasyczny przykład automatyzacji komórkowej. Komórki tworzą kwadratową siatkę i każdy ma dwa stany: żywy lub martwy. W każdej turze każda komórka jednocześnie aktualizuje się zgodnie ze stanem i stanem ośmiu sąsiadów:

  • Żywa komórka pozostaje żywa, jeśli ma dokładnie dwóch lub trzech żywych sąsiadów
  • Martwa komórka ożywa, jeśli ma dokładnie trzech żywych sąsiadów

Twoim zadaniem, jeśli zdecydujesz się to zaakceptować, jest kodowanie najkrótszej implementacji Game of Life w twoim ulubionym języku.

Zasady:

  • Siatka musi mieć wymiary co najmniej 20 x 20
  • Siatka musi się owijać (więc siatka jest jak powierzchnia torusa)
  • Wdrożenie musi umożliwiać użytkownikowi wprowadzenie własnych wzorców początkowych
  • GoL jest trochę bezcelowe, jeśli nie widzisz, co się dzieje, więc musi być widoczny efekt działania automatu, a wynik każdej kolejki pokazywany jest wystarczająco długo, aby był widoczny!

8
Wcześniej w Stack Overflow: Code Golf: Conway's Game of Life , i koniecznie spójrz na link do implementacji APL w komentarzach.
dmckee,

1
Ach, nie widziałem tego. Ale to nieco inne nie (uratować mnie przed usunięciem pracy łączącej wyzwanie?)
Griffin

6
To nie problem. Wiele łamigłówek już uruchomionych na przepełnieniu stosu zostało już tutaj zrobionych, ale ludzie powiedzą, że mam obsesję na punkcie łączenia się z podobnymi wyzwaniami.
dmckee,

@Griffin: Możesz usunąć je wszystkie ;przed }s. Także vars może być wyeliminowane w czasie (jeśli nie złamać kod). I dla jednego wiersza fors, ifs etc, można wyeliminować { }całkowicie: for(...) for(...) dosomething().
pimvdb,

@pimvdb, na zdrowie, jeszcze nie grałem w golfa, nie miałem czasu. chciałem tylko pokazać, że ja też miałem ochotę, niż bezczynnie stawiać sobie wyzwanie. Wkrótce zagra w golfa na maksa.
Griffin,

Odpowiedzi:


27

HTML5 Canvas z JavaScript, 940 639 586 519 znaków

<html><body onload="k=40;g=10;b=[];setInterval(function(){c=[];for(y=k*k;y--;){n=0;for(f=9;f--;)n+=b[(~~(y/k)+k+f%3-1)%k*k+(y+k+~~(f/3)-1)%k];c[y]=n==3||n-b[y]==3;r.fillStyle=b[y]?'red':'tan';r.fillRect(y%k*g,~~(y/k)*g,g-1,g-1)}if(v.nextSibling.checked)b=c},1);v=document.body.firstChild;v.width=v.height=g*k;v.addEventListener('click',function(e){b[~~((e.pageY-v.offsetTop)/g)*k+~~((e.pageX-v.offsetLeft)/g)]^=1},0);r=v.getContext('2d');for(y=k*k;y--;)b[y]=0"><canvas></canvas><input type="checkbox"/>Run</body></html>

Zawsze chciałem zrobić coś z płótnem, więc oto moja próba (oryginalna wersja online ). Możesz przełączać komórki, klikając (możliwe również w trybie pracy).

Możesz teraz wypróbować nową wersję tutaj .

Niestety jest problem, z którym nie mogłem się obejść. Wersja online ma 11 znaków dłużej, ponieważ jsFiddle umieszcza węzeł tekstowy tuż przed kanwą (dlaczego?), A zatem kanwa nie jest już pierwszym dzieckiem.

Edycja 1: Dużo optymalizacji i restrukturyzacji.

Edycja 2: Kilka mniejszych zmian.

Edycja 3: Wprowadzono pełny blok skryptu i drobne zmiany.


Fajnie, ale zmień opóźnienie interwału, aby 1było tak szybkie jak moje, a nie powolne kroczenie. Również jeśli chcesz zaimplementować rysunek (zamiast klikania każdego kwadratu), możesz zaokrąglić pozycję myszy do najbliższego rozmiaru bloku i wypełnić prostokąt w tym punkcie. Więcej postaci, ale więcej punktów.
Griffin,

Można wymienić new Array('#FFF','#800')z ['#FFF','#800'].
Lowjacker

Chociaż mówiąc o rysowaniu, moja gra w super golfa nie pozwala na rysowanie i jest brzydka jak grzech. Ha ha. Możesz ustawić swoje dwa kolory w stablicy, tana redponieważ są to dwa kolory z najkrótszymi reprezentacjami - oszczędza to dwa znaki. Ponadto, jeśli to możliwe, wstaw literalną wersję parametru jdo przedziału. Jestem pewien, że jest jeszcze wiele do wyciśnięcia.
Griffin,

@Griffin and Lowjacker: dziękuję bardzo. Jestem też całkiem pewien, że możesz grać w golfa o wiele więcej (i mam już pewne pomysły). Niestety nie miałem na to czasu. Lepsza wersja w golfa pojawi się jutro - mam nadzieję ...
Howard

2
Możesz usunąć tagi HTML i Body. Będzie działać tak samo
arodebaugh,

32

Python, 219 znaków

Poszedłem do maksymalnego golfa, z interfejsem wystarczającym do zaspokojenia pytania.

import time
P=input()
N=range(20)
while 1:
 for i in N:print''.join(' *'[i*20+j in P]for j in N)
 time.sleep(.1);Q=[(p+d)%400 for d in(-21,-20,-19,-1,1,19,20,21)for p in P];P=set(p for p in Q if 2-(p in P)<Q.count(p)<4)

Uruchamiasz to w ten sposób:

echo "[8,29,47,48,49]" | ./life.py

Liczby na liście reprezentują współrzędne początkowych komórek. Pierwszy rząd to 0-19, drugi rząd to 20-39 itd.

Uruchom go w terminalu z 21 rzędami i wygląda dość niesamowicie.


1
To całkowicie powinno było wygrać. Myślę, że „łatwość wprowadzania” była dość ważna.
primo

@primo Chciałbym nawet posunąć się tak daleko, aby zasugerować, że mma powinna mieć osobny konkurs.
luser droog

2
Więc czy to jest Życie Py?
Christopher Wirt

Zawsze możesz zapisać jeszcze jeden znak ... 2-(p in P)== 2-({p}<P). Ale wtedy musiałbyś zmienić dane wejściowe na {8,29,47,48,49}:)
JBernardo

21

TI-BASIC, 96 bajtów (87 dla wpisu niekonkurującego)

Do kalkulatora graficznego serii TI-84 (!). To było nie lada wyzwaniem, ponieważ nie ma łatwego sposobu, aby napisać buforowany graficzną rutynowe (na pewno nic wbudowane), a ekran wykres ma tylko cztery nakazuje odpowiednie grafiki: Pxl-On(), Pxl-Off(), Pxl-Change(), i pxl-Test().

Wykorzystuje każdy dostępny piksel na ekranie i prawidłowo się zawija. Każda komórka ma jeden piksel, a program aktualizuje wiersz po wierszu poziomo po prawej stronie ekranu. Ponieważ kalkulatory mają tylko procesor Z80 15 MHz, a BASIC jest wolno interpretowanym językiem, kod otrzymuje tylko jedną ramkę co pięć minut.

Wprowadzanie danych przez użytkownika jest łatwe: przed uruchomieniem programu użyj narzędzia Pióro, aby narysować swój kształt na ekranie wykresu.

Dostosowane z mojego wpisu na konkurs golfa kodu na forum kalkulatora Omnimaga .

0
While 1
For(X,0,94
Ans/7+49seq(pxl-Test(remainder(Y,63),remainder(X+1,95)),Y,62,123
For(Y,0,62
If 1=pxl-Test(Y,X)+int(3fPart(3cosh(fPart(6ֿ¹iPart(sum(Ans,Y+1,Y+3
Pxl-Change(Y,X
End
End
End

Wersja Omnimaga (87 bajtów)

Ten kod ma dodatkową funkcję: wykrywa, czy jest uruchamiany po raz pierwszy i czy losowo wyświetla stan ekranu. W kolejnych cyklach automatycznie kontynuuje symulację, jeśli zostanie zatrzymana po zakończeniu ramki. Nie jest to jednak pozycja konkurencyjna, ponieważ nie zawija ekranu; komórki na zewnętrznej granicy zawsze będą uważane za martwe, jeśli ekran wykresu zostanie wcześniej wyczyszczony.

0
While 1
For(X,0,93
Ans/7+49seq(pxl-Test(Y,X+1),Y,0,62
For(Y,1,61
If 2rand>isClockOn=pxl-Test(Y,X)+int(3fPart(3cosh(fPart(6ֿ¹iPart(sum(Ans,Y,Y+2
Pxl-Change(Y,X
End
End
ClockOff
End

Ta wersja jest prawdopodobnie najbardziej golfowym kodem, jaki kiedykolwiek napisałem, i zawiera kilka naprawdę nieprzyjemnych optymalizacji zaciemniających:

  • Używam stanu zegara jako flagi. Na początku programu włączony jest zegar daty i godziny i używam wartości globalnej flagi isClockOn, aby ustalić, czy jest to pierwsza iteracja. Po narysowaniu pierwszej klatki wyłączam zegar. Oszczędza jeden bajt w stosunku do najkrótszej innej metody i około czterech w stosunku do oczywistej metody.

  • Przechowuję stany trzech kolumn obok aktualizowanej w 63-elementowej tablicy liczb podstawowych 7. Miejsce 49 utrzymuje kolumnę po prawej stronie, miejsce 7 trzyma środkową kolumnę, a miejsce jednostki zawiera lewą kolumnę - 1 dla żywej komórki i 0 dla martwej komórki. Następnie biorę resztę mod 6 sumy trzech liczb wokół modyfikowanej komórki, aby znaleźć całkowitą liczbę żywych komórek sąsiednich (to tak jak podzielność przez 9 lewy - w bazie 7, reszta mod 6 równa się sumie cyfry). Samo oszczędza około 10 bajtów i daje możliwość korzystania z dwóch kolejnych optymalizacji. Przykładowy diagram (powiedzmy, że szybowiec jest wyśrodkowany w pewnej kolumnie przy Y = 45:

    Row # | Cell State       | Stored number | Mod 6 = cell count
    ...
    44      Live, Live, Live   49+7+1 = 57     3
    45      Dead, Dead, Live   49+0+0 = 49     1
    46      Dead, Live, Dead   0+7+0  = 7      1
    ...
    

    Centralna komórka pozostanie martwa, ponieważ jest otoczona dokładnie pięcioma żywymi komórkami.

  • Po zakończeniu każdego wiersza liczby w tablicy są aktualizowane przez podzielenie istniejących liczb przez 7, odrzucenie części dziesiętnej i dodanie 49-krotności wartości komórek w nowej kolumnie. Przechowywanie wszystkich trzech kolumn za każdym razem byłoby znacznie wolniejsze i mniej eleganckie, zajmuje co najmniej 20 bajtów więcej i używa trzech list zamiast jednej, ponieważ wartości komórek w każdym wierszu muszą być przechowywane przed aktualizacją komórek. Jest to zdecydowanie najmniejszy sposób przechowywania pozycji komórek.

  • Fragment int(3fPart(3cosh(daje, 1gdy wejście jest równe 3/6, 2gdy jest równe 4/6, a 0gdy wynosi 0, 1/6, 2/6 lub 5/6. Oszczędza około 6 bajtów.


19

Mathematica - 333

Cechy:

  • Interfejs interaktywny: klikaj komórki, aby tworzyć wzory

  • Niezła siatka

  • Przyciski: RUN, PAUSE, CLEAR

Kod znajduje się poniżej.

Manipulate[x=Switch[run,1,x,2,CellularAutomaton[{224,{2,{{2,2,2},{2,1,2},{2,2,2}}},
{1,1}},x],3,Table[0,{k,40},{j,40}]];EventHandler[Dynamic[tds=Reverse[Transpose[x]];
ArrayPlot[tds,Mesh->True]],{"MouseClicked":>(pos=Ceiling[MousePosition["Graphics"]];
x=ReplacePart[x,pos->1-x[[Sequence@@pos]]];)}],{{run,3,""},{1->"||",2->">",3->"X"}}]

wprowadź opis zdjęcia tutaj

Jeśli chcesz się dowiedzieć, jak to działa, drugi przykład na tym blogu to tylko bardziej rozbudowana wersja (analiza Fouriera na żywo, lepszy interfejs) powyższego kodu. Przykład powinien działać bezpośrednio w przeglądarce po darmowym pobraniu wtyczki.


2
+1, fajny do spróbowania. Tak, to jest problem z tą witryną, jest mnóstwo starych pytań, których zwykle brakuje.
Griffin,

@Griffin dziękuje za to, że w ogóle to zauważył;)
Vitaliy Kaurov,

15

C 1063 znaków

Jako wyzwanie zrobiłem to w C, używając nieprzyjaznego golfowi Windows API dla IO w czasie rzeczywistym. Jeśli włączona jest funkcja capslock, symulacja zostanie uruchomiona. Pozostanie nieruchomy, jeśli Capslock jest wyłączony. Rysuj wzory za pomocą myszy; kliknięcie lewym przyciskiem myszy ożywia komórki, a kliknięcie prawym przyciskiem myszy zabija komórki.

#include <windows.h>
#include<process.h>
#define K ][(x+80)%20+(y+80)%20*20]
#define H R.Event.MouseEvent.dwMousePosition
#define J R.Event.MouseEvent.dwButtonState
HANDLE Q,W;char*E[3],O;Y(x,y){return E[0 K;}U(x,y,l,v){E[l K=v;}I(){E[2]=E[1];E[1]=*E;*E=E[2];memset(E[1],0,400);}A(i,j,k,l,P){while(1){Sleep(16);for(i=0;i<20;++i)for(j=0;j<20;++j){COORD a={i,j};SetConsoleCursorPosition(Q,a);putchar(E[0][i+j*20]==1?'0':' ');}if(O){for(i=0;i<20;++i)for(j=0;j<20;++j){for(k=i-1,P=0;k<i+2;++k)for(l=j-1;l<j+2;++l){P+=Y(k,l);}U(i,j,1,P==3?1:Y(i,j)==1&&P==4?1:0);}I();}}}main(T,x,y,F,D){for(x=0;x<21;++x)puts("#####################");E[0]=malloc(800);E[1]=E[0]+400;I();I();W=GetStdHandle(-10);Q=GetStdHandle(-11);SetConsoleMode(W,24);INPUT_RECORD R;F=D=O=0;COORD size={80,25};SetConsoleScreenBufferSize(Q,size);_beginthread(A,99,0);while(1){ReadConsoleInput(W,&R,1,&T);switch(R.EventType){case 1:O=R.Event.KeyEvent.dwControlKeyState&128;break;case 2:switch(R.Event.MouseEvent.dwEventFlags){case 1:x=H.X;y=H.Y;case 0:F=J&1;D=J&2;}if(F)U(x,y,0,1);if(D)U(x,y,0,0);}}}

Skompilowany plik EXE można znaleźć tutaj

Edycja: Skomentowałem źródło. Jest dostępny tutaj


Chciałbym zobaczyć skomentowaną wersję tego!
luser droog

1
Jasne, jeśli pamiętam, o czym myślałem ... = p
Kaslai 22.12.12

1
@luserdroog Oto pastebin.com/BrX6wgUj
Kaslai

To jest po prostu niesamowite.
rayryeng - Przywróć Monikę

12

J (39 znaków)

l=:[:+/(3 4=/[:+/(,/,"0/~i:1)|.])*.1,:]

Na podstawie tej wersji APL (ten sam algorytm, splot toroidalny).

Przykładowe użycie:

   r =: (i.3 3) e. 1 2 3 5 8
   r
0 1 1          NB. A glider!
1 0 1
0 0 1

   R =: _1 _2 |. 5 7 {. r
   R
0 0 0 0 0 0 0  NB. Test board
0 0 0 1 1 0 0
0 0 1 0 1 0 0
0 0 0 0 1 0 0
0 0 0 0 0 0 0

   l R
0 0 0 0 0 0 0  NB. Single step
0 0 0 1 1 0 0
0 0 0 0 1 1 0
0 0 0 1 0 0 0
0 0 0 0 0 0 0

10

Mathematica, 123 znaki

Bardzo podstawowa implementacja, która nie korzysta z wbudowanej funkcji Mathematica CellularAutomaton.

ListAnimate@NestList[ImageFilter[If[3<=Total@Flatten@#<=3+#[[2]][[2]],1,0]&,#,1]&,Image[Round/@RandomReal[1,{200,200}]],99]

8

Ruby 1.9 + SDL (380 325 314)

EDYCJA : 314 znaków i naprawiono błąd z dodatkowymi komórkami, które pojawiały się przy pierwszej iteracji. Zwiększono rozmiar siatki do 56, ponieważ procedura koloru patrzy tylko na najniższe 8 bitów.

EDYCJA : Grał w golfa do 325 znaków. Szerokość / wysokość siatki wynosi teraz 28, ponieważ 28 * 9 jest największą wartością, jaką możesz mieć, wciąż używając wartości jako koloru tła. Przetwarza teraz tylko jedno zdarzenie SDL na iterację, co całkowicie eliminuje wewnętrzną pętlę. Myślę, że dość ciasno!

Symulacja rozpoczyna się z przerwą, wszystkie komórki są martwe. Możesz nacisnąć dowolny klawisz, aby przełączyć pauzę / pauzę, i kliknąć dowolną komórkę, aby przełączyć ją między żywym a martwym. Uruchamia iterację co dziesiąte sekundy.

Opakowanie jest nieco nieporadne.

require'sdl'
SDL.init W=56
R=0..T=W*W
b=[]
s=SDL::Screen.open S=W*9,S,0,0
loop{r="#{e=SDL::Event.poll}"
r['yU']?$_^=1:r[?Q]?exit: r['nU']?b[e.y/9*W+e.x/9]^=1:0
b=R.map{|i|v=[~W,-W,-55,-1,1,55,W,57].select{|f|b[(i+f)%T]}.size;v==3||v==2&&b[i]}if$_
R.map{|i|s.fillRect i%W*9,i/W*9,9,9,[b[i]?0:S]*3}
s.flip
sleep 0.1}

Wygląda tak:

Zrzut ekranu aplikacji w akcji

Zabawne wyzwanie! Z zadowoleniem przyjmuję wszelkie ulepszenia, które każdy może zobaczyć.


Niezła próba, ale od razu widzę, że popełniłeś błąd. Nie możesz mieć takiego wzoru w GoL. Przeczytaj jeszcze raz zasady: en.wikipedia.org/wiki/Conway%27s_Game_of_Life#Rules
Griffin

@Griffin Myślę, że zrzut ekranu został zrobiony po ręcznym wstrzymaniu i przełączeniu niektórych komórek - jednak ponownie sprawdzę reguły. Dzięki!
Paul Prestidge

7
@Griffin nie może wzór nasion być w jakiejkolwiek możliwej konfiguracji?
nowy

7

Scala, 1181 1158 1128 1063 1018 1003 999 992 987 znaków

import swing._
import event._
object L extends SimpleSwingApplication{import java.awt.event._
import javax.swing._
var(w,h,c,d,r)=(20,20,20,0,false)
var x=Array.fill(w,h)(0)
def n(y:Int,z:Int)=for(b<-z-1 to z+1;a<-y-1 to y+1 if(!(a==y&&b==z)))d+=x((a+w)%w)((b+h)%h)
def top=new MainFrame with ActionListener{preferredSize=new Dimension(500,500)
menuBar=new MenuBar{contents+=new Menu("C"){contents+={new MenuItem("Go/Stop"){listenTo(this)
reactions+={case ButtonClicked(c)=>r= !r}}}}}
contents=new Component{listenTo(mouse.clicks)
reactions+={case e:MouseClicked=>var p=e.point
x(p.x/c)(p.y/c)^=1
repaint}
override def paint(g:Graphics2D){for(j<-0 to h-1;i<-0 to w-1){var r=new Rectangle(i*c,j*c,c,c)
x(i)(j)match{case 0=>g draw r
case 1=>g fill r}}}}
def actionPerformed(e:ActionEvent){if(r){var t=x.map(_.clone)
for(j<-0 to h-1;i<-0 to w-1){d=0
n(i,j)
x(i)(j)match{case 0=>if(d==3)t(i)(j)=1
case 1=>if(d<2||d>3)t(i)(j)=0}}
x=t.map(_.clone)
repaint}}
val t=new Timer(200,this)
t.start}}

Nie golfowany:

import swing._
import event._

object Life extends SimpleSwingApplication
{
    import java.awt.event._
    import javax.swing._
    var(w,h,c,d,run)=(20,20,20,0,false)
    var x=Array.fill(w,h)(0)
    def n(y:Int,z:Int)=for(b<-z-1 to z+1;a<-y-1 to y+1 if(!(a==y&&b==z)))d+=x((a+w)%w)((b+h)%h)
    def top=new MainFrame with ActionListener
    {
        title="Life"
        preferredSize=new Dimension(500,500)
        menuBar=new MenuBar
        {
            contents+=new Menu("Control")
            {
                contents+={new MenuItem("Start/Stop")
                {
                    listenTo(this)
                    reactions+=
                    {
                        case ButtonClicked(c)=>run= !run
                    }
                }}
            }
        }
        contents=new Component
        {
            listenTo(mouse.clicks)
            reactions+=
            {
                case e:MouseClicked=>
                    var p=e.point
                    if(p.x<w*c)
                    {
                        x(p.x/c)(p.y/c)^=1
                        repaint
                    }
            }
            override def paint(g:Graphics2D)
            {
                for(j<-0 to h-1;i<-0 to w-1)
                {
                    var r=new Rectangle(i*c,j*c,c,c)
                    x(i)(j) match
                    {
                        case 0=>g draw r
                        case 1=>g fill r
                    }
                }
            }
        }
        def actionPerformed(e:ActionEvent)
        {
            if(run)
            {
                var t=x.map(_.clone)
                for(j<-0 to h-1;i<-0 to w-1)
                {
                    d=0
                    n(i,j)
                    x(i)(j) match
                    {
                        case 0=>if(d==3)t(i)(j)=1
                        case 1=>if(d<2||d>3)t(i)(j)=0
                    }
                }
                x=t.map(_.clone)
                repaint
            }
        }
        val timer=new Timer(200,this)
        timer.start
    }
}

Większa część kodu tutaj to Swing GUI. Sama gra polega na actionPerformedmetodzie uruchamianej przez Timerfunkcję pomocniczą i, nktóra liczy sąsiadów.

Stosowanie:

Skompiluj go, scalac filenamea następnie uruchom scala L.
Kliknięcie kwadratu odwraca go z życia na martwy, a opcja menu uruchamia i zatrzymuje grę. Jeśli chcesz zmienić rozmiar siatki, zmień pierwsze trzy wartości w linii: var(w,h,c,d,r)=(20,20,20,0,false)są to odpowiednio szerokość, wysokość i rozmiar komórki (w pikselach).


Znalazłem 2 ulepszenia gry w golfa: import java.awt.event._i contents+=m("Go",true)+=m("Stop",false)}}, prowadzące do 1093 postaci.
użytkownik nieznany

@ użytkownik nieznany Dzięki. Sam znalazłem kilka ulepszeń - teraz do 1063.
Gareth

Cholera, byłeś zajęty. Tak trzymaj! Będę testować odpowiedzi, gdy opublikuje je kilka osób.
Griffin,

7

Pure Bash, 244 bajty

Działa na owiniętym toroidami wszechświecie 36x24:

mapfile a
for e in {0..863};{
for i in {0..8};{
[ "${a[(e/36+i/3-1)%24]:(e+i%3-1)%36:1}" == O ]&&((n++))
}
d=\ 
c=${a[e/36]:e%36:1}
[ "$c" == O ]&&((--n==2))&&d=O
((n-3))||d=O
b[e/36]+=$d
n=
}
printf -vo %s\\n "${b[@]}"
echo "$o"
exec $0<<<"$o"

Ponieważ jest to skrypt powłoki, metoda wprowadzania jest zgodna z innymi poleceniami powłoki - np. Ze standardowego wejścia:

$ ./conway.sh << EOF

   O 
    O 
  OOO 

EOF


  O O                                                       
   OO                                                       
   O                                                        

















    O                                                       
  O O                                                       
   OO                                                       

... itd

Możemy przekierowywać dane wejściowe z dowolnego źródła tekstu, przepuszczonego przez trfiltr, aby uzyskać ciekawe początkowe generacje, np

man tr | tr [:alnum:] O | ./conway.sh

6

JavaScript, 130

Nie całkowicie odpowiadając na wyzwanie, ale dla przypomnienia, oto silnik Game of Life w 130 bajtach wyprodukowany przez Subzey i ja w 2013 roku.

http://xem.github.io/miniGameOfLife/

/* Fill an array with 0's and 1's, and call g(array, width, height) to iterate */
g=function(f,c,g,d,e,b,h){g=[];e=[c+1,c,c-1,1];for(b=c*c;b--;g[b]=3==d||f[b]&&2==d,d=0)for(h in e)d+=f[b+e[h]]+f[b-e[h]];return g}

Wydaje się, że ma to pewne problemy z pierwszym rzędem. Na przykład ustawienie @@\n@@(kwadrat 2 na 2 w lewym górnym rogu) lub .@\n.@\n.@. (Kolumna 1 na 3)
Annan

5

C # - 675 znaków

Zawsze chciałem napisać wersję tego programu. Nigdy nie wiedziałem, że szybka i brudna wersja zajmie tylko leniwe pół godziny. (Gra w golfa trwa oczywiście dłużej).

using System.Windows.Forms;class G:Form{static void Main(){new G(25).ShowDialog();}
public G(int z){var g=new Panel[z,z];var n=new int [z,z];int x,y,t;for(int i=0;i<z;
i++)for(int j=0;j<z;j++){var p=new Panel{Width=9,Height=9,Left=i*9,Top=j*9,BackColor
=System.Drawing.Color.Tan};p.Click+=(s,a)=>p.Visible=!p.Visible;Controls.Add(g[i,j]=
p);}KeyUp+=(s,_)=>{for(int i=0;i<99;i++){for(x=0;x<z;x++)for(y=0;y<z;y++){t=0;for(int 
c=-1;c<2;c++)for(int d=-1;d<2;d++)if(c!=0||d!=0){int a=x+c,b=y+d;a=a<0?24:a>24?0:a;b=
b<0?24:b>24?0:b;t+=g[a,b].Visible?0:1;}if(t==3||t>1&&!g[x,y].Visible)n[x,y]=1;if(t<2
||t>3)n[x,y]=0;}for(x=0;x<z;x++)for(y=0;y<z;y++)g[x,y].Visible=n[x,y]<1;Update();}};}}

Stosowanie

  • Wprowadź wzorzec początkowy, klikając komórki, aby je włączyć (żywe).
  • Uruchom grę, naciskając dowolny klawisz klawiatury.
  • Gra działa przez 99 pokoleń po każdym naciśnięciu klawisza (mógłbym ustawić ją na 9, aby zapisać znak, ale to wydawało się zbyt kiepskie).

Kompromisy w golfa

  • Możesz włączyć komórki tylko myszą, a nie wyłączyć, więc jeśli popełnisz błąd, musisz ponownie uruchomić program.
  • Nie ma linii siatki, ale nie wpływa to zbytnio na grywalność.
  • Szybkość aktualizacji jest proporcjonalna do szybkości procesora, więc na bardzo szybkich komputerach prawdopodobnie będzie to tylko rozmycie.
  • Żywe komórki są czerwone, ponieważ „czarny” używa 2 dodatkowych znaków.
  • Niewielka liczba komórek i fakt, że nie zajmują całej przestrzeni formularzy, to także kompromisy oszczędzające znaki.

5

GW-BASIC, 1086 1035 bajtów (tokenizowane)

W postaci tokenizowanej jest to 1035 bajtów. (Formularz ASCII jest oczywiście nieco dłuższy.) Otrzymasz tokenizowany formularz, używając SAVE"lifepolecenia bez dołączania go ",ado interpretera.

10 DEFINT A-Z:DEF SEG=&HB800:KEY OFF:COLOR 7,0:CLS:DEF FNP(X,Y)=PEEK((((Y+25)MOD 25)*80+((X+80)MOD 80))*2)
20 X=0:Y=0
30 LOCATE Y+1,X+1,1
40 S$=INKEY$:IF S$=""GOTO 40
50 IF S$=CHR$(13)GOTO 150
60 IF S$=" "GOTO 130
70 IF S$=CHR$(0)+CHR$(&H48)THEN Y=(Y-1+25)MOD 25:GOTO 30
80 IF S$=CHR$(0)+CHR$(&H50)THEN Y=(Y+1)MOD 25:GOTO 30
90 IF S$=CHR$(0)+CHR$(&H4B)THEN X=(X-1+80)MOD 80:GOTO 30
100 IF S$=CHR$(0)+CHR$(&H4D)THEN X=(X+1)MOD 80:GOTO 30
110 IF S$="c"THEN CLS:GOTO 20
120 GOTO 40
130 Z=PEEK((Y*80+X)*2):IF Z=42 THEN Z=32ELSE Z=42
140 POKE(Y*80+X)*2,Z:GOTO 40
150 LOCATE 1,1,0:ON KEY(1)GOSUB 320:KEY(1) ON
160 V!=TIMER+.5:FOR Y=0 TO 24:FOR X=0 TO 79:N=0
170 Z=FNP(X-1,Y-1):IF Z=42 OR Z=46 THEN N=N+1
180 Z=FNP(X,Y-1):IF Z=42 OR Z=46 THEN N=N+1
190 Z=FNP(X+1,Y-1):IF Z=42 OR Z=46 THEN N=N+1
200 Z=FNP(X-1,Y):IF Z=42 OR Z=46 THEN N=N+1
210 Z=FNP(X+1,Y):IF Z=42 OR Z=46 THEN N=N+1
220 Z=FNP(X-1,Y+1):IF Z=42 OR Z=46 THEN N=N+1
230 Z=FNP(X,Y+1):IF Z=42 OR Z=46 THEN N=N+1
240 Z=FNP(X+1,Y+1):IF Z=42 OR Z=46 THEN N=N+1
250 Z=PEEK((Y*80+X)*2):IF Z=32 THEN IF N=3 THEN Z=43
260 IF Z=42 THEN IF N<2 OR N>3 THEN Z=46
270 POKE(Y*80+X)*2,Z:NEXT:NEXT:FOR Y=0 TO 24:FOR X=0 TO 79:Z=PEEK((Y*80+X)*2):IF Z=46 THEN Z=32
280 IF Z=43 THEN Z=42
290 POKE(Y*80+X)*2,Z:NEXT:NEXT
300 IF TIMER<V!GOTO 300
310 IF INKEY$=""GOTO 160
320 SYSTEM

Jest to wersja z maksymalnym golfem, ale wciąż funkcjonalna: po uruchomieniu dostajesz edytor, w którym możesz poruszać się za pomocą klawiszy kursora; spacja włącza / wyłącza bakterie na bieżącym polu, cczyści ekran, Return uruchamia tryb gry.

Poniżej znajduje się mniej zaciemniona wersja, która również ustanawia planszę początkową z dwiema strukturami (rzecz obracająca się w kółko i szybowiec):

1000 REM Conway's Game of Life
1001 REM -
1002 REM Copyright (c) 2012 Thorsten "mirabilos" Glaser
1003 REM All rights reserved. Published under The MirOS Licence.
1004 REM -
1005 DEFINT A-Z:DEF SEG=&hB800
1006 KEY OFF:COLOR 7,0:CLS
1007 DEF FNP(X,Y)=PEEK((((Y+25) MOD 25)*80+((X+80) MOD 80))*2)
1010 PRINT "Initial setting mode, press SPACE to toggle, RETURN to continue"
1020 PRINT "Press C to clear the board, R to reset. OK? Press a key then."
1030 WHILE INKEY$="":WEND
1050 CLS
1065 DATA 3,3,4,3,5,3,6,3,7,3,8,3,3,4,4,4,5,4,6,4,7,4,8,4
1066 DATA 10,3,10,4,10,5,10,6,10,7,10,8,11,3,11,4,11,5,11,6,11,7,11,8
1067 DATA 11,10,10,10,9,10,8,10,7,10,6,10,11,11,10,11,9,11,8,11,7,11,6,11
1068 DATA 4,11,4,10,4,9,4,8,4,7,4,6,3,11,3,10,3,9,3,8,3,7,3,6
1069 DATA 21,0,22,1,22,2,21,2,20,2,-1,-1
1070 RESTORE 1065
1080 READ X,Y
1090 IF X=-1 GOTO 1120
1100 POKE (Y*80+X)*2,42
1110 GOTO 1080
1120 X=0:Y=0
1125 LOCATE Y+1,X+1,1
1130 S$=INKEY$
1140 IF S$="" GOTO 1130
1150 IF S$=CHR$(13) GOTO 1804
1160 IF S$=" " GOTO 1240
1170 IF S$=CHR$(0)+CHR$(&h48) THEN Y=(Y-1+25) MOD 25:GOTO 1125
1180 IF S$=CHR$(0)+CHR$(&h50) THEN Y=(Y+1) MOD 25:GOTO 1125
1190 IF S$=CHR$(0)+CHR$(&h4B) THEN X=(X-1+80) MOD 80:GOTO 1125
1200 IF S$=CHR$(0)+CHR$(&h4D) THEN X=(X+1) MOD 80:GOTO 1125
1210 IF S$="c" THEN CLS:GOTO 1120
1220 IF S$="r" GOTO 1050
1225 IF S$=CHR$(27) THEN END
1230 GOTO 1130
1240 Z=PEEK((Y*80+X)*2)
1250 IF Z=42 THEN Z=32 ELSE Z=42
1260 POKE (Y*80+X)*2,Z
1270 GOTO 1130
1804 LOCATE 1,1,0
1900 ON KEY(1) GOSUB 2300
1910 KEY(1) ON
2000 V!=TIMER+.5
2010 FOR Y=0 TO 24
2020  FOR X=0 TO 79
2030   N=0
2040   Z=FNP(X-1,Y-1):IF Z=42 OR Z=46 THEN N=N+1
2050   Z=FNP(X  ,Y-1):IF Z=42 OR Z=46 THEN N=N+1
2060   Z=FNP(X+1,Y-1):IF Z=42 OR Z=46 THEN N=N+1
2070   Z=FNP(X-1,Y  ):IF Z=42 OR Z=46 THEN N=N+1
2080   Z=FNP(X+1,Y  ):IF Z=42 OR Z=46 THEN N=N+1
2090   Z=FNP(X-1,Y+1):IF Z=42 OR Z=46 THEN N=N+1
2100   Z=FNP(X  ,Y+1):IF Z=42 OR Z=46 THEN N=N+1
2110   Z=FNP(X+1,Y+1):IF Z=42 OR Z=46 THEN N=N+1
2120   Z=PEEK((Y*80+X)*2)
2130   IF Z=32 THEN IF N=3 THEN Z=43
2140   IF Z=42 THEN IF N<2 OR N>3 THEN Z=46
2150   POKE (Y*80+X)*2,Z
2160  NEXT X
2170 NEXT Y
2200 FOR Y=0 TO 24
2210  FOR X=0 TO 79
2220   Z=PEEK((Y*80+X)*2)
2230   IF Z=46 THEN Z=32
2240   IF Z=43 THEN Z=42
2250   POKE (Y*80+X)*2,Z
2260  NEXT X
2270 NEXT Y
2280 IF TIMER<V! GOTO 2280
2290 IF INKEY$="" GOTO 2000
2300 SYSTEM

Napisałem to w 15 minut, znudzony i czekając na przyjaciela, który grał w golfa ze swoim „uczniem” w Conway's Game of Life w tym samym czasie.

Działa w ten sposób: Natychmiast używa bufora ekranowego w trybie tekstowym 80x25 (zmień wartość początkową, DEF SEGaby użyć, &hB000jeśli korzystasz z karty graficznej Hercules; te ustawienia działają z Qemu i (wolniejszym) dosbox). Gwiazdka *to bakteria.

Działa dwuprzebiegowo: po pierwsze, miejsca narodzin są oznaczone, +a śmierć oznacza ich cele .. W drugim przejściu, +i .otrzymuje się *a , odpowiednio.

Chodzi TIMERo to, aby poczekać pół sekundy po każdej rundzie, na wypadek gdyby Twój host Qemu był bardzo szybki ☺

Nie liczę na najkrótszą wygraną, ale na świetną, zwłaszcza biorąc pod uwagę początkową konfigurację planszy. Mam też wersję, w której silnik gry został zastąpiony przez kod asemblera, na wypadek gdybyś był zainteresowany…


Biorąc pod uwagę, że zwiększyłeś swoje etykiety o 1 w wersji bez gry w golfa, czy można zrobić to samo w wersji z golfem? (czyli 1, 2, 3, itd.) Czy numery linii nie liczyć?
Zacharý

numery linii, gdy są tokenizowane, liczą się jako słowo (16 bitów), jeśli się nie mylę
mirabilos

Okej, chyba chyba myślałem o jakimś innym dialekcie BASIC.
Zacharý

@ Zacharý Kliknij „Format programu tokenizowanego GW-BASICa”, a następnie „Format programu” tutaj, aby zobaczyć, że w rzeczywistości numery linii to zawsze dwa bajty, i aby uzyskać bardziej szczegółowe informacje na temat formatu tokena.
mirabilos

5

Mathematica, 115 bajtów

Oto proste rozwiązanie tego problemu:

ListAnimate[ArrayPlot/@CellularAutomaton[{224,{2,{{2,2,2},{2,1,2},
{2,2,2}}},{1,1}},{RandomInteger[1,{9,9}],0},90]]

1
Mathematica jest w porządku, ale zgodnie z regułami program musi pozwalać użytkownikowi na wprowadzanie własnych wzorców. Ta reguła jest celowa, ponieważ kilka języków pozwala na takie krótkie implementacje, ale bez interakcji użytkownika. Pewnie, że możesz tam umieścić własną tablicę, ale to nie wygra.
Griffin,

„wejście” w Mathematica odbywa się głównie przez interfejs notebooka, więc nie sądzę, że „interakcja użytkownika” jest naprawdę możliwa. Po prostu zamień argument RandomInteger na funkcję CellularAutomaton na dowolną wartość i ponownie oceń kod.
JeremyKun,

3
Interakcja użytkownika jest możliwa. Najbardziej uproszczoną metodą, jaką mogę teraz wymyślić, jest zestaw przycisków. Daj spokój człowieku.
Griffin,

4

Java (OpenJDK 8) - 400 388 367 bajtów

Druga i (prawdopodobnie) ostateczna edycja: Udało się zagrać w golfa dodatkowe 21 bajtów po znalezieniu tych (imo) kopalni złota - zdecydowanie polecam nowym osobom, aby je przeczytały (szczególnie jeśli zamierzasz wypróbować niektóre z tych wyzwań przy użyciu Javy).

Wynikowy kod (prawdopodobnie skończę grać w golfa jeszcze bardziej, jeśli dowiem się, jak skrócić te podwójne zagnieżdżone dla pętli ...):

u->{int w=u.length,h=u[0].length,x,y,i,j,n;Stack<Point>r=new Stack<Point>();for(;;){for(Point c:r)u[c.x][c.y]=1;r.clear();for(x=0;x<w;++x)for(y=0;y<h;++y){boolean o=u[x][y]>0;n=o?-1:0;for(i=-2;++i<2;)for(j=-2;++j<2;)if(u[(w+x+i)%w][(h+y+j)%h]>0)++n;if(o&n>1&n<4|!o&n==3)r.add(new Point(x,y));System.out.print(u[x][y]+(y>h-2?"\n":""));}for(int[]t:u)Arrays.fill(t,0);}}

Wypróbuj online!

(Oryginalny post zaczyna się tutaj.)

Właściwie przez chwilę myślałem, że będę w stanie przynajmniej rzucić wyzwanie najlepszej odpowiedzi w języku Python z moją (prawdopodobnie ograniczoną) znajomością Java lol ... Było to wyzwanie, w którym jednak uczestniczyłem (mimo że dołączyłem do drużyny, być może tylko trochę późno ...)

Naprawdę nie ma w tym nic wielkiego - podstawowe wyjaśnienie (niemodyfikowane):

/*
 * Explanation of each variable's usage:
 * w=height* of array
 * h=width* of array
 * x=y* coord of point in array
 * y=x* coord of point in array
 * i and j are counters for calculating the neighbours around a point in the array
 * n=neighbour counter
 * r=temporary array to store the cells from the current generation
 * u=the 2d array used for all the calculations (parameter from lambda expression)
 * c=temporary variable used to help populate the 2d array
 * o=boolean variable that stores the value of whether the cell is alive or not
 */
u-> // start of lambda statement with u as parameter (no need for brackets as it's only one parameter being passed)
{
    int w=u.length,h=u[0].length,x,y,i,j,n; // defines all the necessary integer variables;
    Stack<Point>r=new Stack<Point>(); // same with the only array list needed (note how I only use two data structures);
    for(;;) // notice how this is still an infinite loop but using a for loop;
    {
        for(Point c:r)u[c.x][c.y]=1; //for every point in the "previous" generation, add that to the 2D array as a live (evil?) cell;
        r.clear(); // clears the array list to be populated later on
        for(x=0;x<w;++x) // a pair of nested for loops to iterate over every cell of the 2D array;
        {
            for(y=0;y<h;++y)
            {
                // sets o to be the presence of a live cell at (x,y) then uses said value in initialising the neighbour counter;
                boolean o=u[x][y]>1;n=o?-1:0;
                for(i=-2;++i<2;) // another pair of nested for loops - this one iterates over a 3x3 grid around *each* cell of the 2D array;
                {                // this includes wrap-around (note the modulus sign in the if statement below);
                    for(j=-2;++j<2;)
                    {
                        if(u[(w+x+i)%w][(h+y+j)%h]>0)++n; // this is where the first interesting thing lies - the bit which makes wrap-around a reality;
                    }
                }
                if(o&n>1&n<4|!o&n==3)r.add(new Point(x,y)); // this is the second interesting bit of my code - perhaps more so as I use bitwise operators to calculate the number of neighbours (x,y) has;
                                                            // (since I'm technically dealing with 0s and 1s, it's not a total misuse of them imo);
                System.out.print(u[x][y]+(y>h-2?"\n":""));  // that extra part of the print statement adds a newline if we reached the end of the current 'line';
            }
        }
        // since the information about the new generation is now in the array list, this array can be emptied out, ready to receive said info on the new generation;
        for(int[]t:u)Arrays.fill(t,0);
    }
} // end of lambda statement

(więcej informacji na temat instrukcji lambda w Javie 8 tutaj )

Tak, w moim podejściu jest pewien haczyk.

Jak większość z was zapewne zauważyła, mój kod w golfa w obecnej postaci będzie zapętlony na zawsze. Aby temu zapobiec, licznik można wprowadzić u góry i użyć w pętli while do wyświetlania n(w tym przypadku 5) iteracji w następujący sposób (zauważ, że bdodano nową zmienną):

u->{int b=0,w=u.length,h=u[0].length,x,y,i,j,n;Stack<Point>r=new Stack<Point>();for(;++b<6;){for(Point c:r)u[c.x][c.y]=1;r.clear();for(x=0;x<w;++x)for(y=0;y<h;++y){boolean o=u[x][y]>0;n=o?-1:0;for(i=-2;++i<2;)for(j=-2;++j<2;)if(u[(w+x+i)%w][(h+y+j)%h]>0)++n;if(o&n>1&n<4|!o&n==3)r.add(new Point(x,y));System.out.print(u[x][y]+(y>h-2?"\n":""));}for(int[]t:u)Arrays.fill(t,0);}}

Dodatkowo kilka punktów, o których warto wspomnieć. Ten program nie sprawdza poprawności danych wejściowych i dlatego zawiedzie (najprawdopodobniej) an ArrayOutOfBoundsException; dlatego upewnij się, że dane wejściowe są poprawne, całkowicie wypełniając część tablicy (krzywe tablice wyrzucą wyjątek wspomniany powyżej). Ponadto tablica, w której jest obecnie, wygląda na „płynną” - to znaczy, że nie ma rozdziału między jednym pokoleniem a następnym. Jeśli chcesz to dodać, aby dokładnie sprawdzić, czy generowane generacje są rzeczywiście ważne, System.out.println();tuż przedtem należy dodać dodatkowe for(int[]t:u)Arrays.fill(t,0);( dla jasności zobacz Wypróbuj online! ). I na koniec, biorąc pod uwagę, że jest to mój pierwszy kod golfowy, wszelkie opinie są bardzo mile widziane :)

Stary kod z poprzedniej 388 bajtowej odpowiedzi:

u->{int w=u.length,h=u[0].length,x,y,i,j,n;ArrayList<Point>r=new ArrayList<Point>();while(true){for(Point c:r)u[c.x][c.y]=1;r.clear();for(x=0;x<w;++x){for(y=0;y<h;++y){boolean o=u[x][y]==1;n=o?-1:0;for(i=-2;++i<2;)for(j=-2;++j<2;)if(u[(w+x+i)%w][(h+y+j)%h]==1)++n;if(o&n>1&n<4|!o&n==3)r.add(new Point(x,y));System.out.print(u[x][y]);}System.out.println();}for(int[]t:u)Arrays.fill(t,0);}}

I od początkowej 400 bajtowej odpowiedzi:

int w=35,h=20,x,y,i,j,n;ArrayList<Point>l=new ArrayList<Point>(),r;while(true){int[][]u=new int[w][h];for(Point c:l)u[c.x][c.y]=1;r=new ArrayList<Point>();for(x=0;x<w;++x){for(y=0;y<h;++y){boolean o=u[x][y]==1;n=o?-1:0;for(i=-2;++i<2;)for(j=-2;++j<2;)if(u[(w+x+i)%w][(h+y+j)%h]==1)++n;if(o&n>1&n<4|!o&n==3)r.add(new Point(x,y));System.out.print(u[x][y]);}System.out.println();}l.clear();l.addAll(r);}

Niesamowity pierwszy post, witamy w PPCG!
Zacharý

Dzięki, zdecydowanie zamierzam robić więcej z nich - są fajne :)
NotBaal

Dołącz do nas, mamy Dennis. Ponadto nie jest to kompletny program ani funkcja, którą powinien być, IIRC.
Zacharý

No tak, zapomniałem części „programowej”: P Edytowanie tego za chwilę.
NotBaal

To może być tylko funkcja.
Zacharý

4

Szablon , 6 bajtów

Nie mój ulubiony język, ale jest krótki…

4 bajty kodu plus flagi nlist i Torus.

3me

Wypróbuj online!

Czy ...
3 3
 członkiem
m tej m oore Sąsiedztwo-count z siebie lub
e The Moor e -neighbourhood-count bez siebie
...?


3

Scala - 799 znaków

Uruchom jako skrypt. Kliknięcie myszą kwadratu włącza lub wyłącza, a dowolny klawisz uruchamia lub zatrzymuje generowanie.

import java.awt.Color._
import swing._
import event._
import actors.Actor._
new SimpleSwingApplication{var(y,r,b)=(200,false,Array.fill(20,20)(false))
lazy val u=new Panel{actor{loop{if(r){b=Array.tabulate(20,20){(i,j)=>def^(i:Int)= -19*(i min 0)+(i max 0)%20
var(c,n,r)=(0,b(i)(j),-1 to 1)
for(x<-r;y<-r;if x!=0||y!=0){if(b(^(i+x))(^(j+y)))c+=1}
if(n&&(c<2||c>3))false else if(!n&&c==3)true else n}};repaint;Thread.sleep(y)}}
focusable=true
preferredSize=new Dimension(y,y)
listenTo(mouse.clicks,keys)
reactions+={case e:MouseClicked=>val(i,j)=(e.point.x/10,e.point.y/10);b(i)(j)= !b(i)(j)case _:KeyTyped=>r= !r}
override def paintComponent(g:Graphics2D){g.clearRect(0,0,y,y);g.setColor(red)
for(x<-0 to 19;y<-0 to 19 if b(x)(y))g.fillRect(x*10,y*10,9,9)}}
def top=new Frame{contents=u}}.main(null)

3

J, 45

Myślałem, że spróbuję J. Nie jest jeszcze szczególnie dobrze golfowany, ale wkrótce spróbuję jeszcze raz.

(]+.&(3&=)+)+/((4&{.,(_4&{.))(>,{,~<i:1))&|.

Przykład:

   f =: 5 5 $ 0 1 0 0 0   0 0 1 0 0   1 1 1 0 0   0 0 0 0 0    0 0 0 0 0
   f
0 1 0 0 0
0 0 1 0 0
1 1 1 0 0
0 0 0 0 0
0 0 0 0 0
   f (]+.&(3&=)+)+/((4&{.,(_4&{.))(>,{,~<i:1))&|. f
0 0 0 0 0
1 0 1 0 0
0 1 1 0 0
0 1 0 0 0
0 0 0 0 0

3

Przetwarzanie 536 532

int h=22,t=24,i,j;int[][]w=new int[t][t],b=new int[t][t];int[]q={1,0,-1};void draw(){if(t<9){clear();for(i=2;i<h;i++){for(j=2;j<h;j++)w[i][j]=b[i][j];w[i][1]=w[i][21];w[i][h]=w[i][2];w[1][i]=w[21][i];w[h][i]=w[2][i];}for(i=1;i<23;i++)for(j=1;j<23;j++){t=-w[i][j];for(int s:q)for(int d:q)t+=w[i+s][j+d];b[i][j]=w[i][j]>0&(t<2|t>3)?0:t==3?1:b[i][j];}a();}}void keyPressed(){t=0;}void mousePressed(){int i=mouseX/5+2,j=mouseY/5+2;w[i][j]=b[i][j]=1;a();}void a(){for(i=0;i<h-2;i++)for(j=0;j<h-2;j++)if(w[i+2][j+2]==1)rect(i*5,j*5,5,5);}

Uważam, że spełnia to wszystkie wymagania.

Nie golfowany:

int h=22,t=24,i,j;
int[][]w=new int[t][t],b=new int[t][t];
int[]q={1,0,-1};
void draw(){
  if(t<9){
  clear();
  for(i=2;i<h;i++){
    for(j=2;j<h;j++)
      w[i][j]=b[i][j];  
    w[i][1]=w[i][21];
    w[i][h]=w[i][2];
    w[1][i]=w[21][i];
    w[h][i]=w[2][i];
  }
  for(i=1;i<23;i++)
    for(j=1;j<23;j++){
      t=-w[i][j];
      for(int s:q)
        for(int d:q)
          t+=w[i+s][j+d];        
      b[i][j]=w[i][j]>0&(t<2|t>3)?0:t==3?1:b[i][j];  
  }
  a();
}
}
void keyPressed(){
  t=0;
}
void mousePressed(){
  int i=mouseX/5+2,j=mouseY/5+2;
  w[i][j]=b[i][j]=1;
  a();
}
void a(){
  for(i=0;i<h-2;i++)
    for(j=0;j<h-2;j++)
      if(w[i+2][j+2]==1)
        rect(i*5,j*5,5,5);
  }  

3

Matlab (152)

b=uint8(rand(20)<0.2)
s=@(m)imfilter(m,[1 1 1;1 0 1;1 1 1],'circular')
p=@(m,n)uint8((n==3)|(m&(n==2)))
while 1
imshow(b)
drawnow
b=p(b,s(b))
end

Nie mam teraz zainstalowanego Matlaba, żeby go przetestować, po prostu grałem w kod napisany kilka lat temu.
Nie golfowany:

%% initialize
Bsize = 20;
nsteps = 100;
board = uint8(rand(Bsize)<0.2); % fill 20% of the board
boardsum = @(im) imfilter(im,[1 1 1; 1 0 1; 1 1 1], 'circular');
step = @(im, sumim) uint8((sumim==3) | (im & (sumim==2)) );

%% run
for i = 1:nsteps
    imshow(kron(board,uint8(ones(4))), [])
    drawnow
    ss(p,i) = sum(board(:));
    board = step(board, boardsum(board));
end
  • Boardsize jest zakodowany na stałe, ale może być dowolny
  • owija się wokół
  • do wprowadzania przez użytkownika można zmienić tablicę początkową albo na stałe zapisując inną matrycę, albo używając edytora zmiennych. Nie ładnie, ale działa
  • Można pominąć 20 znaków, jeśli wyjście graficzne zostanie pominięte, tablica nadal będzie drukowana jako tekst przy każdej iteracji. Komórki jednopikselowe, które zmieniają się co milisekundę, i tak nie są zbyt przydatne

działa w R2014a, właśnie przetestowane
masterX244

3

Perl, 218 216 211 202 bajtów

$,=$/;$~=AX3AAAx76;$b=pack('(A79)23',<>)x6;{print unpack'(a79)23a0',$b;select$v,$v,$v,0.1;$b=pack'(A)*',unpack'((x7a/(x13)X4Ax!18)1817@0)4',pack'((a*)17xx!18)*',unpack"x1737(AA$~Ax$~AA$~@)2222",$b;redo}

(Brak nowego wiersza na końcu tego kodu).

Odczytuje wzorzec początkowy ze standardowego wejścia, jako plik tekstowy, w którym żywe komórki są reprezentowane jako 1, martwe komórki reprezentowane jako spacja, linie są oddzielone nową linią. Dane wejściowe nie mogą zawierać znaków innych niż te. Linie mogą mieć różną długość i będą wypełnione lub obcięte do szerokości dokładnie 79. Przykładem może być szybowiec:

                                  1
                                1 1
                      11      11            11
                     1   1    11            11
          11        1     1   11
          11        1   1 11    1 1
                    1     1       1
                     1   1
                      11









                                         11
                                         1
                                          111
                                            1

Gdy program uruchamia Game of Life, każdy stan jest zrzucany na standardowe wyjście w formacie podobnym do wejścia, a następnie opóźnia 0,1 sekundy. Opóźnienie można dostosować, zmieniając czwarty argument wybranego wywołania.

Plansza jest zakodowana na stałe do rozmiaru 79x23. Jest owinięty torusem: jeśli opuścisz deskę na dole, znajdziesz się na górze; jeśli wyjdziesz po prawej stronie, skończysz po lewej stronie, ale przesunąłeś jeden rząd w dół.

Oto alternatywna wersja, która nie odczytuje żadnych danych wejściowych i zaczyna się od losowej tablicy:

$,=$/;$/=AX3AAAx76;$b=pack("(A)*",map{rand 3<1}0..1816)x6;{print unpack'(a79)23a0',$b;select$v,$v,$v,0.1;$b=pack'(A)*',unpack'((x7a/(x13)X4Ax!18)1817@0)4',pack'((a*)17xx!18)*',unpack"x1737(AA$/Ax$/AA$/@)2222",$b;redo}

Ten kod pochodzi z zaciemnionego programu gry w Perla napisanego przed laty . Bardzo to zmieniłem, aby kod toroidalny i golf były kodem.

Prawdopodobnie nie jest to najkrótsza metoda na wdrożenie Game of Life w Perlu, ale jest to jedna z mniej zrozumiałych.

Tablica jest przechowywana $bjako ciąg '1'i ' ', po jednej dla każdej komórki, tylko cała rzecz jest powtarzana co najmniej trzy razy. Trzecie wywołanie rozpakowywania wyodrębnia 17 wartości dla każdej komórki: jest jedna dla samej komórki i dwie dla każdej z ośmiu sąsiednich komórek, w dowolnej kolejności, a każda wartość to '1'lub pusty ciąg. Komórka powinna być aktywna w następnej iteracji, jeśli liczba '1'wartości wśród tych 17 wartości wynosi 5, 6 lub 7. Trzecie wywołanie paczki łączy te 17 wartości z polem o szerokości 18 znaków wyrównanym do lewej i wypełnionym zerowymi bajtami po prawej stronie . Drugie wywołanie rozpakowania zajmuje tak 18 szerokie pole, wysyła postać na pozycję 7, rozpakowuje przestrzeń z pozycji 17, jeśli jest to'1'lub rozpakowuje postać z pozycji 4 w przeciwnym razie. Ten wynik jest dokładnie wartością, jaką komórka powinna mieć w następnej generacji.


2

Python, 589 bajtów

Przyciski myszy: lewy - wstaw komórkę, prawy - usuń komórkę, środek - start / stop.

z importu Tkinter *
importuj kopię
z = zasięg
F = 50
T = Tk ()
S = 9
f = [F * [0] dla i in'7 '* F]
c = płótno (T, szerokość = S * F, wysokość = S * F)
c.pack ()
def p (x, y, a): f [y] [x] = f [y] [x] lub c.create_oval (x * S, y * S, x * S + S, y * S + S) if a c c.delete (f [y] [x])
r = 1
def R (e): globalny r; r = 1-r
exec ("c.bind ('<Button-% i>', lambda e: p (ex / S, ey / S,% i));" * 2% (1,1,3,0)
c. wiązanie („<Button-2>”, R)
def L ():
 T.after (99, L)
 jeśli r: powrót
 g = copy.deepcopy (f)
 dla yw z (F):
	dla x w z (F):
	 n = 8
	 dla jw z (-1,2):
		dla iw z (-1,2):
		 jeśli i lub j: n- = nie g [(y + j)% F] [(x + i)% F]
	 jeśli 1 <n <4:
		jeśli n == 3 i nie g [y] [x]: p (x, y, 1)
	 else: p (x, y, 0)
L ()
T.mainloop ()

A oto wersja, w której możesz przeciągać myszą, aby rysować. Grafika jest nieco przyjemniejsza.

from Tkinter import*
import copy
z=range
F=50
T=Tk()
S=9
f=[F*[0]for i in'7'*F]
c=Canvas(T,bg='white',width=S*F,height=S*F)
c.pack()
def p(x,y,a):f[y][x]=f[y][x]or c.create_rectangle(x*S,y*S,x*S+S,y*S+S,fill='gray')if a else c.delete(f[y][x])
r=1
def R(e):global r;r=1-r
exec("c.bind('<Button-%i>',lambda e:p(e.x/S,e.y/S,%i));c.bind('<B%i-Motion>',lambda e:p(e.x/S,e.y/S,%i));"*2%(1,1,1,1,3,0,3,0))
c.bind('<Button-2>',R)
def L():
 T.after(99,L)
 if r:return
 g=copy.deepcopy(f)
 for y in z(F):
  for x in z(F):
   n=8
   for j in z(-1,2):
    for i in z(-1,2):
     if i or j:n-=not g[(y+j)%F][(x+i)%F]
   if 1<n<4:
    if n==3and not g[y][x]:p(x,y,1)
   else:p(x,y,0)
L()
T.mainloop()

To nie jest zgodne z zasadami gry.
Steven Rumbalski

1
@StevenRumbalski: Oh naprawdę?
Oleh Prypin

2
naprawdę. Wystąpił błąd wcięcia w drugiej wersji. Sekcja rozpoczynająca się od if 1<n<4:powinna być wcięta na tym samym poziomie cofor j in z(-1,2):
Steven Rumbalski

2

Python 2, 456 bajtów

Chociaż wiem, że to stary post, nie mogłem się powstrzymać od wypróbowania go. Plansza początkowa może mieć dowolny rozmiar, pod warunkiem, że wokół niej narysujesz ramkę i będziesz mieć dodatkowe miejsce w ostatniej linii.

Golf.py

import time,itertools as w,sys;t,q=map(lambda x:list(x[:-1]),sys.stdin.readlines()),list(w.product(range(-1,2),range(-1,2)));del q[4];n=map(lambda x:x[:],t[:])
while time.sleep(0.1)==None:
 for j in range(1,len(t)-1):
  for i in range(1,len(t[j])-1):x=sum(map(lambda s:1 if t[j+s[0]][i+s[1]]in'@'else 0,q));f=t[j][i];n[j][i]='@'if(f=='@'and(x==3 or x==2))or(f==' 'and x==3)else' '
 t=map(lambda x:x[:],n[:]);print'\n'.join(list(map(lambda x:''.join(x),t)))

Input.txt (zwróć uwagę na dodatkowe miejsce w ostatnim wierszu)

+----------------------------------------+
|                    @                   |
|                     @                  |
|                   @@@                  |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
+----------------------------------------+ 

Jak biegać

python Golf.py < input.txt

time.sleep(0.1)==None=> not time.sleep(.1), (f=='@'and(x==3 or x==2)) lub (f == '' i x == 3) =>x==3or f=='@'and x==2
CalculatorFeline

^, Zapomniałeś jednego, 1 if=> 1if.
Zacharý

2

Przetwarzanie 270,261 249 bajtów

Siatka to 100 * 100 pikseli ekranu, dane wejściowe mają postać obrazu png

void setup(){image(loadImage("g.png"),0,0);}void draw(){loadPixels();int n,i=0,j,l=10000;int[]a=new int[l],p=pixels;for(;i<l;a[i]=n==5?-1<<24:n==6?p[i]:-1,i++)for(j=n=0;j<9;j++)n+=j!=4?p[(i+l-1+j%3+100*(j/3-1))%l]&1:0;arrayCopy(a,p);updatePixels();}

Nie golfił

void setup() {
  image(loadImage("g.png"), 0, 0);
}
void draw() {
  loadPixels();
  int c=100, i=0, n, l=c*c, b=color(0);
  int[]a=new int[l], p=pixels;
  for (; i<l; i++) {
    n=p[(i+l-101)%l]&1;
    n+=p[(i+l-100)%l]&1;
    n+=p[(i+l-99)%l]&1;
    n+=p[(i+l-1)%l]&1;
    n+=p[(i+1)%l]&1;
    n+=p[(i+99)%l]&1;
    n+=p[(i+100)%l]&1;
    n+=p[(i+101)%l]&1;
    a[i]=n==5?b:p[i]==b&&n==6?b:-1;
  }
  arrayCopy(a, pixels, l);
  updatePixels();
}

zrzut ekranu


2

Lua + LÖVE / Love2D , 653 bajtów

l=love f=math.floor t={}s=25 w=20 S=1 for i=1,w do t[i]={}for j=1,w do t[i][j]=0 end end e=0 F=function(f)loadstring("for i=1,#t do for j=1,#t[i]do "..f.." end end")()end function l.update(d)if S>0 then return end e=e+d if e>.2 then e=0 F("c=0 for a=-1,1 do for b=-1,1 do if not(a==0 and b==0)then c=c+(t[((i+a-1)%w)+1][((j+b-1)%w)+1]>0 and 1 or 0)end end end g=t[i][j]t[i][j]=(c==3 or(c==2 and g==1))and(g==1 and 5 or-1)or(g==1 and 4 or 0)")F("t[i][j]=t[i][j]%2")end end function l.draw()F("l.graphics.rectangle(t[i][j]==1 and'fill'or'line',i*s,j*s,s,s)")end function l.mousepressed(x,y)S=0 o,p=f(x/s),f(y/s)if t[o]and t[o][p]then t[o][p]=1 S=1 end end

lub rozdzielone:

l=love
f=math.floor
t={}s=25
w=20
S=1
for i=1,w do
    t[i]={}
    for j=1,w do
        t[i][j]=0
    end
end
e=0
F=function(f)
    loadstring("for i=1,#t do for j=1,#t[i] do  "..f.." end end")()
end
function l.update(d)
    if S>0 then
        return
    end
    e=e+d
    if e>.2 then
        e=0
        F([[
        c=0
        for a=-1,1 do
            for b=-1,1 do
                if not(a==0 and b==0)then
                    c=c+(t[((i+a-1)%w)+1][((j+b-1)%w)+1]>0 and 1 or 0)
                end
            end
        end
        g=t[i][j]
        t[i][j]=(c==3 or(c==2 and g==1))and(g==1 and 5 or-1) or (g==1 and 4 or 0)]])
        F("t[i][j]=t[i][j]%2")
    end
end
function l.draw()
    F("l.graphics.rectangle(t[i][j]==1 and'fill'or'line',i*s,j*s,s,s)") end
function l.mousepressed(x,y)
    S=0
    o,p=f(x/s),f(y/s)
    if t[o]and t[o][p] then
        t[o][p]=1
        S=1
    end
end

Kliknij pole, aby dodać żywe komórki. Kliknij poza polem, aby go uruchomić.

Wypróbuj online!

wprowadź opis zdjęcia tutaj


1

Postscriptum 529 515

Zaczął od przykładu z kodu Rosetta . Wywołaj za pomocą argumentu nazwy pliku ( gs -- gol.ps pulsar), pliku zawierającego 20 * 20 liczb binarnych (oddzielonych spacją). Nieskończona pętla: rysuj planszę, poczekaj na wejście, oblicz następną generację.

[/f ARGUMENTS 0 get(r)file/n 20>>begin[/m
n 1 sub/b[n{[n{f token pop}repeat]}repeat]/c 400
n div/F{dup 0 lt{n add}if dup n ge{n sub}if}>>begin{0
1 m{dup 0 1 m{2 copy b exch get exch get 1 xor setgray
c mul exch c mul c c rectfill dup}for pop pop}for
showpage/b[0 1 m{/x exch def[0 1 m{/y exch def 0
y 1 sub 1 y 1 add{F dup x 1 sub 1 x
1 add{F b exch get exch get 3 2 roll add exch
dup}for pop pop}for b x get y get sub b x get y get
0 eq{3 eq{1}{0}ifelse}{dup 2 eq exch 3 eq
or{1}{0}ifelse}ifelse}for]}for]def}loop

Oddzielny, z kilkoma komentarzami stosu (tylko te, których potrzebowałem).

[
/f ARGUMENTS 0 get(r)file
/n 20
/sz 400
%/r{rand 2147483647 div}
>>begin
[
/m n 1 sub
/b[
%n{[n{r .15 le{1}{0}ifelse}repeat]}repeat
 n{[n{f token pop}repeat]}repeat
]
/c sz n div
/F{dup 0 lt{n add}if dup n ge{n sub}if}
>>begin
{
    0 1 m{dup % y y
    0 1 m{ % y y x
        2 copy b exch get exch get 1 xor setgray
        c mul exch c mul c c rectfill
        dup 
    }for pop pop}for
    pstack
    showpage
    /b[0 1 m{/x exch def
      [0 1 m{/y exch def
          0   
          y 1 sub 1 y 1 add{F dup %s y y
          x 1 sub 1 x 1 add{F %s y y x
              b exch get exch get %s y bxy
              3 2 roll add exch %s+bxy y
              dup %s y y
          }for pop pop}for
          b x get y get sub
          b x get y get
          0 eq{3 eq{1}{0}ifelse}{dup 2 eq exch 3 eq or{1}{0}ifelse}ifelse
      }for]
      }for]def
}loop

plik danych pulsar:

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 0 0 0 0 0
0 0 0 0 0 1 1 1 0 0 0 1 1 1 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 1 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0
0 0 0 0 0 1 1 1 0 0 0 1 1 1 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 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0 1 0 1 0 0 0 0 1 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 1 1 1 0 0 0 1 1 1 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 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

1

JavaScript 676

Przepraszam, Griffin, po prostu nie mogłem spojrzeć na twój kod i nie napisać go ponownie ... musiałem zgolić dwa znaki, ale było to cholernie warte!

b=[];r=c=s=20;U=document;onload=function(){for(z=E=0;z<c;++z)for(b.push(t=[]),j=0;j<r;j++)with(U.body.appendChild(U.createElement("button")))t.push(0),id=z+"_"+j,style.position="absolute",style.left=s*j+"px",style.top=s*z+"px",onclick=a}; ondblclick=function(){A=E=E?clearInterval(A):setInterval(function(){Q=[];for(z=0;z<c;++z){R=[];for(j=0;j<r;)W=(c+z-1)%c,X=(c+z+1)%c,Y=(r+j-1)%r,Z=(r+j+1)%r,n=b[W][Y]+b[z][Y]+b[X][Y]+b[W][j]+b[X][j]+b[W][Z]+b[z][Z]+b[X][Z],R.push(b[z][j++]?4>n&&1<n:3==n);Q.push(R)}b=Q.slice();d()})};function a(e){E?0:P=e.target.id.split("_");b[P[0]][P[1]]^=1;d()}function d(){for(z=0;z<c;++z)for(j=0;j<r;)U.getElementById(z+"_"+j).innerHTML=b[z][j++]-0}

Ale jak mówią, łatwiej prosić o wybaczenie niż o pozwolenie ...;)


1

Oktawa (153)

taki sam jak Matlab DenDenDo w Shortest Game of Life , ale musiał zmienić imshow na imagesc:

b=uint8(rand(20)<0.2)
s=@(m)imfilter(m,[1 1 1;1 0 1;1 1 1],'circular')
p=@(m,n)uint8((n==3)|(m&(n==2)))
while 1
imagesc(b)
drawnow
b=p(b,s(b))
end

1

Python 2: 334 bajtów

Tylko 6 lat spóźnienia.

import time
s='';s=map(list,iter(raw_input,s));k=len(s);l=(-1,0,1);n=int;z=range
while 1:
 r=[[0]*k for i in z(k)]
 for i in z(k*k):
  a,b=i//k,i%k
  m,g=sum([n(s[(a+c)%k][(b+d)%k])for c in l for d in l if c|d]),n(s[a][b])
  r[a][b]=n((m==2)&g or m==3)
  print'*'if r[a][b]else' ',
  if b-k+1==0:print
 s=r;time.sleep(.2);print"\033c"

Możesz uruchomić go w następujący sposób:

python gol.py
0000000
0001000
0000100
0011100
0000000
0000000
0000000

Gdy 0 i 1 oznaczają martwe i żywe komórki, dodatkowa nowa linia na końcu rozpoczyna wykonywanie.

Siatki muszą być kwadratowe.

Łatwiej jest go uruchomić niż najkrótszy python, obsługuje siatki dowolnej wielkości i wygląda ładnie po uruchomieniu.

To także 100 bajtów więcej, więc jest to.


0

PHP, 201 bajtów (nie testowano)

for($s=file(f);print"\n";$s=$t)foreach($s as$y=>$r)for($x=-print"
";"
"<$c=$s[$y][++$x];print$t[$y][$x]=" X"[$n<4&$n>2-$a])for($n=-$a=$c>A,$i=$x-!!$x-1;$i++<=$x;)for($k=$y-2;$k++<=$y;)$n+=$s[$k][$i]>A;

Uruchom z -nr.

awaria

for($s=file(f);                         # import input from file "f"
    print"\n";                              # infinite loop: 1. print newline
    $s=$t)                                  # 3. copy target to source, next iteration
    foreach($s as$y=>$r)                    # 2. loop through lines
        for($x=-print"\n";"\n"<$c=$s[$y][++$x]; # print newline, loop $x/$c through line characters (before line break)
            print                                   # 5. print new cell
                $t[$y][$x]=" X"[$n>2-$a&$n<4])      # 4. new cell is alive if neighbour count<4 and >2 (>1 if alive)
            for($n=-                                # 2. init neighbour count: exclude self
                $a=$c>A,                            # 1. $a=cell is alife
                $i=$x-!!$x-1;$i++<=$x;)             # 3. loop $i from one left to one right of current position
                for($k=$y-2;$k++<=$y;)                  # loop $k from one above to one below current position
                    $n+=$s[$k][$i]>A;                       # increase neighbor count if neighbour is alife
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.