Стабильная Игра Жизни


19

Вызов:

Учитывая матрицу (или 2-мерный массив) 0 и 1, выведите количество шагов, которое необходимо, чтобы игра жизни Конвея достигла стабильного состояния, или -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

Mathematica, 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@@как используется для выравнивания 2D-списка.

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

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

Кто хочет массовое подчинение? \ О /

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

Сохранено ~ 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

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

Контрольные примеры

Вот несколько тестов

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

Почти победил Mathematica в этом ...

Это решение для 126 байтов работает только в старых версиях Perl (где вы можете использовать константу в качестве переменной):

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

Я веду историю каждой доски, поэтому, если я получу доску, которую видел раньше, я знаю, что произошло одно из двух. Во-первых, возможно, мы нашли устойчивую позицию, и в этом случае она станет самой последней в нашей истории. Другая возможность заключается в том, что у нас есть цикл.


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

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

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.