Стабільна гра життя


19

Виклик:

З огляду на матрицю (або 2d масив) з 0s і 1s, виведіть кількість кроків, необхідних для того, щоб гра життя Конуея досяг стабільного стану, або -1, якщо вона ніколи не досягає такої. Стабільний стан - це стан, в якому жодна клітина не включається або вимикається на кожному кроці. Гра повинна працювати в заданій матриці, зверху і знизу, а також зв'язані сторони. (тобто, маючи матрицю 4x3, вона повинна працювати на торі 4x3) Вхідна матриця не буде більше 15x15.

Примітка: Якщо матриця починається в стабільному стані, вихід повинен бути 0.

Зразки:

Вхід:

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

Вихід:

2

Процес: (це не потрібно відображати)

[[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]]

Вхід:

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

Вихід:

2

Процес:

[[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]]

Вхід:

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

Вихід:

-1

Процес:

[[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]]

повторюється назавжди

Вхід:

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

Вихід:

4

Процес:

[[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]]

Вхід:

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

Вихід:

0

Процес:

Початковий стан стабільний.

Правила гри життя

Якщо комірка, яка вимкнена (0), розташована поруч із рівними трьома на (1) комірках, вона вмикається. В іншому випадку це відключено. Якщо осередок, що ввімкнений, знаходиться поряд із 2 або 3 на квадратах, він говорить про те. В іншому випадку він вимкнений.


Отже, що має бути результатом, якщо шаблон повторюється назавжди?
Позов по

2
Можливі формати введення? Будь-які межі на розміри матриць? Якщо ні, що робити, якщо у нас є матриця 100x100? Крім того, вам, мабуть, слід поставити підсумок правил гри «Життя», щоб це було самостійно.
El'endia Starman

3
О Я бачу. Я неправильно прочитав один із прикладів. Хоча ще одне питання - в який момент слід вважати, що він не стає стабільним? Тому що я впевнений, що існує багато моделей, які стають стабільними після сотень чи тисяч ітерацій. Існує навіть категорія для цього: Метусела
позов

18
Я майже впевнений, що це завдання по суті просить "вирішити проблему зупинки".
Мего

6
Як контрприклад для показу 250 поколінь не завжди достатньо: для матриці 15 на 14, для одного планера на інакше порожній арені знадобиться 15 * 14 * 4 = 840 поколінь, щоб повернутися до початкового стану. Якщо кінець цього довгого шляху блокується блоком 2 на 2, планер знищить, залишаючи стабільну конфігурацію. Це буде в декількох рядах від кінця шляху, щоб уникнути знищення планера прямо на старті, але все-таки набагато понад 600 поколінь до стабільності.
трихоплакс

Відповіді:


10

Математика, 130 129 байт

#&@@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&

Я б не рекомендував спробувати більше 4х4 входів, оскільки це займе назавжди (і багато пам’яті).

Пояснення

Це просто імітує Гра життя за 2 N кроків, де N - кількість комірок на вході. Це гарантує, що якщо система перетвориться в стабільний стан, ми її досягли. Згодом ми знаходимо першу пару послідовних однакових станів у змодельованій історії.

Давайте пройдемо код:

2^Length[Join@@#]

Це обчислює 2 N , оскільки Join@@використовується для вирівнювання двовимірного списку.

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

Це імітує Гра життя для 2 N поколінь. Матриця 3x3 визначає сусідство тоталістичного 2D автомата і 224є числом правил стандартної гри Життя. Я писав про те, як обчислити це число тут, на Mathematica.SE .

Partition[...,2,1]

Це отримує всі послідовні (перекриваються) пари поколінь.

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

Це знаходить першу пару однакових поколінь, дефолтом яких є, 0якщо таких не знайдено, і обмеженням пошуку на глибину 1. Якщо така пара буде знайдена, то результат повертається у вигляді списку , хоча. Тому ми використовуємо:

#&@@...

Витягнути перший елемент із цього списку (значення за замовчуванням 0, будучи атомним, цим не впливає).

...-1

Нарешті, ми віднімаємо його, тому що виклик очікує на 0основі індексів та -1невдач.


8

Луа, 531 509 488 487 464 424 405 404 байт

Хто хоче масового подання? \ o /

Редагувати: Удосконалено це, але більше не знаю, як це робити в гольф, тому ... пояснення надходять коментарі додаються :)

Збережено ~ 60 байт за допомогою @ KennyLau

Невеликий гольф різання ще один байти шляху перейменування aв , Yщоб запобігти перетворенню вбудованого шістнадцятирічного

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

Безумовно

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

Тестові справи

Ось кілька тестових випадків

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

Желе, 26 25 байт

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

Спробуйте в Інтернеті! або перевірити всі тестові випадки .

Більші тестові випадки (з відповіді @ Katenkyo ): 15 × 15 стабільний | Планер 15 × 14

Як це працює

ṙ-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 байт

Включає +3 для -ap0

Виконати з введенням у вигляді рядка груп цифр, розділених пробілом

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

Це дійсно потрібно лише в тому випадку, якщо вхід негайно стабільний. У всіх інших випадках ви також можете зручніше вказати їх як окремі рядки цифр:

life.pl
0000
0001
0111
0010
^D

Однак введення цього способу дасть 1 замість 0 для негайно стабільної конфігурації.

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

Майже побивши Математику на цьому ...

Тільки в старих версіях perl (де ви можете використовувати константу як змінну) це рішення з 126 байтів працює:

#!/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

Якщо напевно є щонайменше 2 рядки, це 123-байтне рішення працює у всіх версіях 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

рубін, 207 байт

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

Я зберігаю історію кожної дошки, тому якщо я отримав дошку, яку я бачив раніше, я знаю, що сталося одне з двох. по-перше, можливо, ми знайшли стабільну позицію, і в цьому випадку це буде найбільш обурюватися в нашій історії. інша можливість полягає в тому, що у нас є петля.


Матриця 15х15 означає, що у нас є 2 ^ 225 можливих дощок, я дуже сумніваюся, що ви навіть зможете запам'ятати ці матриці, використовуючи пам'ять усіх комп'ютерів у світі (навіть якщо більшість ігор, ймовірно, закінчуються менше ніж 1000 дошками). 64-бітні машини.
GameDeveloper

1
@DarioOO Навіть планеру на дошці 15x14 знадобиться "лише" 840 покоління, перш ніж повернутись до свого першого стану, тому ми можемо очікувати, що майже все буде менше 1000 ген. Крім того, 1000 gens на 15x15 з використанням 32-бітових цілих чисел призводять до використання пам'яті 15*15*4*1000-> 900 КБ, що досить добре для випадків, коли нам знадобиться 10k + gens :).
Katenkyo

1

Джулія, 92 88 байт

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)

Перевірка

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.