Gioco stabile della vita


19

Sfida:

Data una matrice (o 2d array) di 0s e 1s, genera il numero di passi necessari affinché il gioco della vita di Conway raggiunga uno stato stabile, o -1 se non lo raggiunge mai. Uno stato stabile è uno stato in cui nessuna cella viene accesa o spenta per ogni passaggio. Il gioco deve essere eseguito nella matrice indicata, con la parte superiore e inferiore connesse e i lati collegati. (ovvero, data una matrice 4x3, dovrebbe funzionare su un toro 4x3) La matrice di input non sarà più grande di 15x15.

Nota: se la matrice inizia in uno stato stabile, l'output dovrebbe essere 0.

Campioni:

Ingresso:

[[0,0,0],  
 [0,1,1],  
 [0,1,0]]

Produzione:

2

Processo: (questo non deve essere visualizzato)

[[0,0,0],
 [0,1,1],
 [0,1,0]]

[[1,1,1],
 [1,1,1],
 [1,1,1]]

[[0,0,0],
 [0,0,0],
 [0,0,0]]

Ingresso:

[[0,0,1,1],
 [0,1,1,1],
 [0,1,0,0],
 [0,1,1,1]]

Produzione:

2

Processi:

[[0,0,1,1],
 [0,1,1,1],
 [0,1,0,0],
 [0,1,1,1]]

[[0,0,0,0],
 [0,1,0,1],
 [0,0,0,0],
 [0,1,0,1]]

[[0,0,0,0],
 [0,0,0,0],
 [0,0,0,0],
 [0,0,0,0]]

Ingresso:

[[0,1,0,0],
 [0,1,0,0],
 [0,1,0,0],
 [0,0,0,0]]

Produzione:

-1

Processi:

[[0,1,0,0],
 [0,1,0,0],
 [0,1,0,0],
 [0,0,0,0]]

[[0,0,0,0],
 [1,1,1,0],
 [0,0,0,0],
 [0,0,0,0]]

[[0,1,0,0],
 [0,1,0,0],
 [0,1,0,0],
 [0,0,0,0]]

ripetendo per sempre

Ingresso:

[[0,0,0,0],
 [0,0,0,1],
 [0,1,1,1],
 [0,0,1,0]]

Produzione:

4

Processi:

[[0,0,0,0],
 [0,0,0,1],
 [0,1,1,1],
 [0,0,1,0]]

[[0,0,0,0],
 [1,0,0,1],
 [1,1,0,1],
 [0,1,1,1]]

[[0,1,0,0],
 [0,1,1,1],
 [0,0,0,0],
 [0,1,0,1]]

[[0,1,0,1],
 [1,1,1,0],
 [0,1,0,1],
 [1,0,1,0]]

[[0,0,0,0],
 [0,0,0,0],
 [0,0,0,0],
 [0,0,0,0]]

Ingresso:

[[0,0,0,0],
 [0,1,1,0],
 [0,1,1,0],
 [0,0,0,0]]

Produzione:

0

Processi:

Lo stato iniziale è stabile.

Regole del gioco della vita

Se una cella che è spenta (0) è accanto esattamente a tre celle (1) accese, viene attivata. Altrimenti, viene lasciato fuori. Se una cella accesa si trova accanto a 2 o 3 su quadrati, dice su. Altrimenti, è spento.


Quindi cosa dovrebbe essere emesso se il modello si ripete per sempre?
Fondi Monica's Lawsuit,

2
Possibili formati di input? Qualche limite sulle dimensioni delle matrici? In caso contrario, se avessimo una matrice 100x100? Inoltre, dovresti probabilmente mettere un riassunto delle regole del Gioco della vita nella domanda in modo che sia autonomo.
El'endia Starman

3
Oh, capisco. Ho letto male uno degli esempi. Un'altra domanda, però: a che punto dovremmo presumere che non diventi stabile? Perché sono sicuro che ci sono molti pattern che diventano stabili dopo centinaia o migliaia di iterazioni. C'è persino una categoria per questo: Methuselah
Finanzi la causa di Monica il

18
Sono abbastanza sicuro che questa sfida stia essenzialmente chiedendo "risolvere il problema dell'arresto".
Mego

6
Come controesempio mostrare 250 generazioni non è sempre sufficiente: per una matrice 15 per 14, un singolo aliante in un'arena altrimenti vuota impiegherà 15 * 14 * 4 = 840 generazioni per tornare al suo stato originale. Se la fine di quel lungo percorso è bloccata da un blocco 2 per 2, l'aliante si annichilerà lasciando una configurazione stabile. Questo sarà a poche file dalla fine del percorso per evitare di distruggere l'aliante proprio all'inizio, ma comunque ben oltre 600 generazioni prima della stabilità.
trichoplax,

Risposte:


10

Mathematica, 130 129 byte

#&@@FirstPosition[Partition[CellularAutomaton[{224,{2,{{2,2,2},{2,1,2},{2,2,2}}},{1,1}},#,2^Length[Join@@#]],2,1],{x_,x_},0,1]-1&

Non consiglierei di provare più di ingressi 4x4, perché ci vorrà per sempre (e molto memoria).

Spiegazione

Questo simula semplicemente il gioco della vita per 2 N gradini dove N è il numero di celle in ingresso. Questo garantisce che se il sistema si stabilizza in uno stato stabile, lo abbiamo raggiunto. Successivamente, troviamo la prima coppia di stati identici consecutivi nella storia simulata.

Analizziamo il codice:

2^Length[Join@@#]

Questo calcola 2 N , poiché Join@@viene utilizzato per appiattire un elenco 2D.

CellularAutomaton[{224,{2,{{2,2,2},{2,1,2},{2,2,2}}},{1,1}},#,...]

Questo simula il Gioco della vita per 2 generazioni N. La matrice 3x3 specifica il vicinato di un automa 2D totalistico ed 224è il numero di regola del Game of Life standard. Ho scritto su come calcolare questo numero qui su Mathematica.SE .

Partition[...,2,1]

Questo ottiene tutte le coppie consecutive (sovrapposte) di generazioni.

FirstPosition[...,{x_,x_},0,1]

Questo trova la prima coppia di generazioni identiche, per impostazione predefinita 0se non viene trovata alcuna e limita la ricerca alla profondità 1. Se una tale coppia è trovata , il risultato viene comunque restituito in un elenco. Quindi usiamo:

#&@@...

Per estrarre il primo elemento da quell'elenco (il valore predefinito di 0 , essendo atomico, non è interessato da questo).

...-1

Infine ne sottraggiamo uno perché la sfida prevede 0indici basati -1sul fallimento e per fallimento.


8

Lua, 531 509 488 487 464 424 405 404 byte

Chi vuole una presentazione di massa? \ O /

Modifica: migliorato, ma non so più giocare a golf, quindi ... stanno arrivando spiegazioni commenti aggiunti :)

Salvati ~ 60 byte con l'aiuto di @ KennyLau

piccolo golf tagliando un altro byte rinominandolo ain Yper evitare la conversione esadecimale inline

function f(m)c={}t=table.concat::z::c[#c+1]={}p=c[#c]Y={}for i=1,#m do k=m[i]p[#p+1]=t(k)Y[i]={}for j=1,#k
do v=m[i%#m+1]l=j%#k+1w=m[(i-2)%#m+1]h=(j-2)%#k+1Y[i][j]=v[l]+k[l]+w[l]+v[h]+v[j]+w[h]+w[j]+k[h]end
end s=''for i=1,#m do k=m[i]for j=1,k do
x=Y[i][j]k[j]=k[j]>0 and((x<2or x>3)and 0or 1)or (x==3 and 1or 0)end
s=s..t(k)end for i=1,#c do
if(s==t(c[i]))then return#c>i and-1or i-1
end end goto z end

Ungolfed

function f(m)                -- takes a 2D array of 0 and 1s as input
  c={}                       -- intialise c -> contains a copy of each generation
  t=table.concat             -- shorthand for the concatenating function 
  ::z::                      -- label z, used to do an infinite loop
    c[#c+1]={}               -- initialise the first copy 
    p=c[#c]                  -- initialise a pointer to this copy
    a={}                     -- initialise the 2D array of adjacency
    for i=1,#m               -- iterate over the lines of m
    do
      k=m[i]                 -- shorthand for the current line
      p[#p+1]=t(k])          -- saves the current line of m as a string
      a[i]={}                -- initialise the array of adjacency for the current line
      for j=1,#k             -- iterate over each row of m
      do
                             -- the following statements are used to wraps at borders
        v=m[i%#m+1]          -- wrap bottom to top
        l=j%#k+1             -- wrap right to left
        w=m[(i-2)%#m+1]      -- wrap top to bottom
        h=(j-2)%#k+1         -- wrap left to right

        a[i][j]= v[l]        -- living cells are 1 and deads are 0
                +k[l]        -- just add the values of adjacent cells
                +w[l]        -- to know the number of alive adjacent cells
                +v[h]
                +v[j]
                +w[h]
                +w[j]
                +k[h]
      end
    end

    s=''                     -- s will be the representation of the current generation
    for i=1,#m               -- iterate over each line
    do
      k=m[i]                 -- shorthand for the current line
      for j=1,#k             -- iterate over each row
      do
        x=a[i][j]            -- shorthand for the number of adjacent to the current cell
                             -- the next line change the state of the current cell
        k[j]=k[j]>0          -- if it is alive
                and((x<2     --   and it has less than 2 adjacent
                    or x>3)  --   or more than 3 adjacent
                  and 0      --     kill it
                  or 1)      --     else let it alive
                or           -- if it is dead
                  (x==3      --   and it has 3 adjacent
                  and 1      --     give life to it
                  or 0)      --     else let it dead
      end
      s=s..t(k)              -- save the representation of the current line
    end
    for i=1,#c               -- iterate over all the generation done until now
    do                       
      if(s==t(c[i]))         -- if the representation of the current generation
      then                   -- is equal to one we saved
        return#c>i           -- check if it is the latest generation
              and-1          -- if it isn't, it means we are in a loop -> return -1
              or i-1         -- if it is, we did 2 generations without changing
                             --  -> return the number of generation
      end
    end
  goto z                     -- if we reach that point, loop back to the label z
end

Casi test

Ecco alcuni casi di test

function f(m)c={}t=table.concat::z::c[#c+1]={}p=c[#c]a={}for i=1,#m do k=m[i]p[#p+1]=t(k)a[i]={}for j=1,#k
do v=m[i%#m+1]l=j%#k+1w=m[(i-2)%#m+1]h=(j-2)%#k+1
a[i][j]=v[l]+k[l]+w[l]+v[h]+v[j]+w[h]+w[j]+k[h]end
end s=''for i=1,#m do k=m[i]for j=1,k do
x=a[i][j]k[j]=k[j]>0 and((x<2or x>3)and 0or 1)or (x==3 and 1or 0)end
s=s..t(k)end for i=1,#c do
if(s==t(c[i]))then return#c>i and-1or i-1
end end goto z end




print(f({{0,0,0},{0,1,1},{0,1,0}}))
print(f({{0,1,0,0},{0,1,0,0},{0,1,0,0},{0,0,0,0}}))
-- 53 generation, 15x15, takes 50-100 ms on a bad laptop
print(f({{0,0,0,0,1,1,0,1,0,0,0,0,1,0,0},
       {0,1,1,0,1,1,1,1,1,1,1,0,0,0,0},
       {0,1,1,1,0,1,0,1,0,0,0,0,1,0,0},
       {0,0,1,0,1,1,1,0,0,1,1,1,0,1,1},
       {1,1,0,0,1,1,1,0,1,1,0,0,0,1,0},
       {0,0,0,0,1,1,0,1,0,0,0,0,1,0,0},
       {0,1,1,0,1,1,1,1,1,1,1,0,0,0,0},
       {0,1,1,1,0,1,0,1,0,0,0,0,1,0,0},
       {0,0,1,0,1,1,1,0,0,1,1,1,0,1,1},
       {1,1,0,0,1,1,1,0,1,1,0,0,0,1,0},
       {0,0,1,0,1,1,1,0,0,1,1,1,0,1,1},
       {1,1,0,0,1,1,1,0,1,1,0,0,0,1,0},
       {0,0,0,0,1,1,0,1,0,0,0,0,1,0,0},
       {0,0,0,0,1,1,0,1,0,0,0,0,1,0,0},
       {0,1,1,0,1,1,1,1,1,1,1,0,0,0,0}}))
-- Glider on a 15x14 board
-- 840 distinct generation
-- loop afterward -> return -1
-- takes ~4-5 seconds on the same bad laptop
print(f({{0,0,0,0,0,0,0,0,0,0,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,0,0,0,0,0,0},
       {0,0,0,0,0,1,0,0,0,0,0,0,0,0,0},
       {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,0,0,0,0,0,0,0,0,0,0,0,0,0},
       {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
       {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
       {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}))

5

Gelatina, 26 25 byte

ṙ-r1¤SZµ⁺_|=3
ÇÐĿ-LiṪÇ$$?

Provalo online! o verifica tutti i casi di test .

Casi di prova più grandi (dalla risposta di @ Katenkyo ): 15 × 15 stabile | Aliante 15 × 14

Come funziona

ṙ-r1¤SZµ⁺_|=3  Helper link. Argument: G (grid)
               This link computes the next state of G.

    ¤          Evaluate the three links to the left as a niladic chain.
 -               Yield -1.
   1             Yield 1.
  r              Range; yield [-1, 0, 1].
ṛ              Rotate the rows of G -1, 0 and 1 units up.
     S         Compute the sum of the three resulting grids.
               Essentially, this adds the rows directly above and below each given
               row to that row.
      Z        Zip; transpose rows and columns.
       µ       Convert the preceding chain into a link and begin a new chain.
        ⁺      Apply the preceding chain once more.
               This zips back and adds the surrounding columns to each column.
         _     Subtract G from the result.
               Each cell now contains the number of lit cells that surround it.
          |    That the bitwise OR of the result and G.
               Notably, 3|0 = 3|1 = 2|1 = 3.
           =3  Compare each resulting number with 3.


ÇÐĿ-LiṪÇ$$?    Main link. Argument: G (grid)

ÇÐL            Repeatedly apply the helper link until the results are no longer
               unique. Collect all unique results in a list.
         $     Evaluate the two links to the left as a monadic chain:
        $        Evaluate the two links to the left as a monadic chain:
      Ṫ            Pop the last element of the list of grids.
       Ç           Apply the helper link to get the next iteration.
     i           Get the index of the grid to the right (the first non-unique one)
                 in the popped list of grids. This yields 0 iff the popped list
                 doesn't contain that grid, i.e., the grid reached a stable state.
          ?    If the index is non-zero:
   -             Return -1.
    L            Else, return the length of the popped list of grids.

5

Perl, 154 151 144 140 137 133 129 byte

Include +3 per -ap0

Esegui con l'input come una riga di gruppi di cifre separate da spazio

life.pl <<< "0000 0001 0111 0010"

Ciò è necessario solo nel caso in cui l'ingresso sia immediatamente stabile. In tutti gli altri casi puoi anche fornirlo più comodamente come linee di cifre separate:

life.pl
0000
0001
0111
0010
^D

Dare input in questo modo darebbe comunque 1 invece di 0 per una configurazione immediatamente stabile.

life.pl:

#!/usr/bin/perl -ap0
map{@f=map$F[$_%@F]x3,$i-1..++$i;s%.%"0+($&+33)=~grep\$_,map{(//g)[@--1..@+]}\@f"%eeg}@Q=@F;$_=/@Q/?keys%n:$n{$_="@Q"}--||redo

Quasi battendo Mathematica su questo ...

Solo su versioni perl precedenti (dove è possibile utilizzare una costante come variabile) questa soluzione da 126 byte funziona:

#!/usr/bin/perl -p0a
map{@f=map$F[$_++%@F]x2,-1..1;s%.%"0+($&+33)=~grep\$_,map{(//g)[@--1..@+]}\@f"%eeg}@Q=@F;$_=/@Q/?keys%n:$n{$_="@Q"}--||redo

Nel caso in cui ci siano sicuramente almeno 2 righe questa soluzione da 123 byte funziona su tutte le versioni di perl:

#!/usr/bin/perl -p0a
@F=@F[-$#F..!s%.%"0+($&+33)=~grep\$_,map{(//g,//g)[@--1..@+]}\@F[-1..1]"%eeg]for@Q=@F;$_=/@Q/?keys%n:$n{$_="@Q"}--||redo

1

rubino, 207 byte

->a{r=[];(r<<a;a=(0...a.size).map{|i|(0...a[i].size).map{|j|n=0;(-1..1).map{|u|(-1..1).map{|v|n+=a[(i+u)%a.size][(j+v)%a[i].size]}};[n==3,n>2&&n<5][a[i][j]]?1:0}})while(!r.index(a));(a==r[-1])?r.index(a):-1}

Tengo una cronologia di ogni tavola, quindi se ricevo una tavola che ho visto prima di sapere una delle due cose accadute. in primo luogo potrebbe essere che abbiamo trovato una posizione stabile, nel qual caso sarà il più risentito della nostra storia. l'altra possibilità è che abbiamo un ciclo.


Matrice 15x15 significa che abbiamo 2 ^ 225 possibili schede, dubito fortemente che tu possa persino memorizzare quelle matrici usando la memoria di tutti i computer nei mondi (anche se la maggior parte dei giochi probabilmente finirà con meno di 1000 schede). Macchine a 64 bit.
GameDeveloper,

1
@DarioOO Anche un aliante su una tavola 15x14 avrà bisogno della "sola" generazione 840 prima di tornare al suo primo stato, quindi possiamo aspettarci che quasi tutto sia inferiore a 1000 gens. Inoltre, 1000 gens su un 15x15 usando numeri interi a 32 bit producono un utilizzo della memoria di 15*15*4*1000-> 900 KB, abbastanza buono per i casi in cui avremo bisogno di 10k + gens :).
Katenkyo,

1

Julia, 92 88 byte

f(x,r...)=x∈r?(r[k=end]==x)k-1:f(sum(i->circshift(x,[i÷3,i%3]-1),0:8)-x|x.==3,r...,x)

Verifica

julia> f(x,r...)=x∈r?(r[k=end]==x)k-1:f(sum(i->circshift(x,[i÷3,i%3]-1),0:8)-x|x.==3,r...,x)
f (generic function with 1 method)

julia> f([0 0 0;0 1 1;0 1 0])
2

julia> f([0 0 1 1;0 1 1 1;0 1 0 0;0 1 1 1])
2

julia> f([0 1 0 0;0 1 0 0;0 1 0 0;0 0 0 0])
-1

julia> f([0 0 0 0;0 0 0 1;0 1 1 1;0 0 1 0])
4

julia> f([0 0 0 0;0 1 1 0;0 1 1 0;0 0 0 0])
0

julia> f([0 0 0 0 1 1 0 1 0 0 0 0 1 0 0;0 1 1 0 1 1 1 1 1 1 1 0 0 0 0;0 1 1 1 0 1 0 1 0 0 0 0 1 0 0;0 0 1 0 1 1 1 0 0 1 1 1 0 1 1;1 1 0 0 1 1 1 0 1 1 0 0 0 1 0;0 0 0 0 1 1 0 1 0 0 0 0 1 0 0;0 1 1 0 1 1 1 1 1 1 1 0 0 0 0;0 1 1 1 0 1 0 1 0 0 0 0 1 0 0;0 0 1 0 1 1 1 0 0 1 1 1 0 1 1;1 1 0 0 1 1 1 0 1 1 0 0 0 1 0;0 0 1 0 1 1 1 0 0 1 1 1 0 1 1;1 1 0 0 1 1 1 0 1 1 0 0 0 1 0;0 0 0 0 1 1 0 1 0 0 0 0 1 0 0;0 0 0 0 1 1 0 1 0 0 0 0 1 0 0;0 1 1 0 1 1 1 1 1 1 1 0 0 0 0])
53

julia> f([0 0 0 0 0 0 0 0 0 0 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 0 0 0 0 0 0;0 0 0 0 0 1 0 0 0 0 0 0 0 0 0;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 0 0 0 0 0 0 0 0 0 0 0 0 0;0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;0 0 0 0 0 0 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.