Trò chơi ổn định của cuộc sống


19

Thử thách:

Đưa ra một ma trận (hoặc mảng 2d) 0 và 1, xuất ra số bước cần thiết để trò chơi cuộc sống của Conway đạt đến trạng thái ổn định hoặc -1 nếu nó không bao giờ đạt đến một. Trạng thái ổn định là trạng thái trong đó không có ô nào được bật hoặc tắt mỗi bước. Trò chơi phải chạy trong ma trận đã cho, với kết nối trên và dưới và các bên được kết nối. (tức là đã cho một ma trận 4x3, nó sẽ chạy trên một hình xuyến 4x3) Ma trận đầu vào sẽ không lớn hơn 15x15.

Lưu ý: Nếu ma trận bắt đầu ở trạng thái ổn định, đầu ra phải là 0.

Mẫu:

Đầu vào:

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

Đầu ra:

2

Quá trình: (không cần hiển thị)

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

Đầu vào:

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

Đầu ra:

2

Quá trình:

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

Đầu vào:

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

Đầu ra:

-1

Quá trình:

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

lặp đi lặp lại mãi mãi

Đầu vào:

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

Đầu ra:

4

Quá trình:

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

Đầu vào:

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

Đầu ra:

0

Quá trình:

Trạng thái bắt đầu ổn định.

Luật chơi

Nếu một ô bị tắt (0) bên cạnh chính xác ba ô (1), nó sẽ được bật. Nếu không, nó được để lại. Nếu một ô được bật bên cạnh 2 hoặc 3 trên các ô vuông, nó sẽ hiện trên. Nếu không, nó đã bị tắt.


Vì vậy, những gì nên được đầu ra nếu mô hình lặp đi lặp lại mãi mãi?
Vụ kiện của Quỹ Monica

2
Định dạng đầu vào có thể? Bất kỳ giới hạn về kích thước ma trận? Nếu không, nếu chúng ta có ma trận 100x100 thì sao? Ngoài ra, có lẽ bạn nên đặt một bản tóm tắt các quy tắc Trò chơi Cuộc sống trong câu hỏi để nó khép kín.
El'endia Starman

3
Ồ, tôi hiểu rồi. Tôi đọc sai một trong những ví dụ. Tuy nhiên, một câu hỏi khác - tại thời điểm nào chúng ta nên cho rằng nó không trở nên ổn định? Bởi vì tôi chắc chắn có rất nhiều mẫu trở nên ổn định sau hàng trăm hoặc hàng nghìn lần lặp. Thậm chí còn có một hạng mục dành cho nó: Methuselah
Vụ kiện của Quỹ Monica

18
Tôi khá chắc chắn rằng thách thức này về cơ bản là yêu cầu "giải quyết vấn đề tạm dừng".
Mego

6
Như một ví dụ để hiển thị 250 thế hệ không phải lúc nào cũng đủ: Đối với ma trận 15 x 14, một tàu lượn trong một đấu trường trống khác sẽ mất 15 * 14 * 4 = 840 thế hệ để trở về trạng thái ban đầu. Nếu điểm cuối của con đường dài đó bị chặn bởi khối 2 by 2, tàu lượn sẽ hủy để lại cấu hình ổn định. Đây sẽ là một vài hàng ngắn ở cuối con đường để tránh phá hủy tàu lượn ngay khi bắt đầu, nhưng vẫn còn hơn 600 thế hệ trước khi ổn định.
trichoplax

Câu trả lời:


10

Toán học, 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&

Tôi không khuyên bạn nên thử nhiều hơn đầu vào 4 x 4, vì sẽ mất nhiều thời gian (và rất nhiều bộ nhớ).

Giải trình

Điều này chỉ đơn giản là mô phỏng Trò chơi cuộc sống trong 2 N bước trong đó N là số lượng ô trong đầu vào. Điều này đảm bảo rằng nếu hệ thống ổn định ở trạng thái ổn định, chúng tôi đã đạt được nó. Sau đó, chúng tôi tìm thấy cặp trạng thái giống hệt nhau đầu tiên trong lịch sử mô phỏng.

Chúng ta hãy đi qua mã:

2^Length[Join@@#]

Điều này tính 2 N , vì Join@@được sử dụng để làm phẳng danh sách 2D.

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

Này mô phỏng các Game of Life cho 2 N thế hệ. Ma trận 3x3 chỉ định vùng lân cận của máy tự động 2D toàn diện và 224là số quy tắc của Trò chơi Cuộc sống tiêu chuẩn. Tôi đã viết về cách tính số này ở đây trên Mathicala.SE .

Partition[...,2,1]

Điều này nhận được tất cả các cặp thế hệ liên tiếp (chồng chéo).

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

Điều này tìm thấy cặp thế hệ giống hệt đầu tiên, mặc định 0nếu không tìm thấy và giới hạn tìm kiếm theo chiều sâu 1. Nếu một cặp như vậy được tìm thấy, kết quả được trả về trong một danh sách mặc dù. Vì vậy, chúng tôi sử dụng:

#&@@...

Để trích xuất phần tử đầu tiên từ danh sách đó (giá trị mặc định của 0, là nguyên tử, không bị ảnh hưởng bởi điều này).

...-1

Cuối cùng, chúng tôi trừ đi một vì thách thức mong đợi 0các chỉ số dựa trên và -1thất bại.


8

Lua, 531 509 488 487 464 424 405 404 byte

Ai muốn một đệ trình lớn? \ o /

Chỉnh sửa: Đã cải thiện nó, nhưng không biết chơi golf nữa, vì vậy ... những lời giải thích đang được thêm vào :)

Đã lưu ~ 60 byte với sự trợ giúp của @ KennyLau

chơi golf nhỏ cắt thêm một byte bằng cách đổi tên athành Yđể ngăn chuyển đổi thập lục phân nội tuyến

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

Bị đánh cắp

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

Các trường hợp thử nghiệm

Đây là một số trường hợp thử nghiệm

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

Thạch, 26 25 byte

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

Hãy thử trực tuyến! hoặc là xác minh tất cả các trường hợp thử nghiệm .

Các trường hợp thử nghiệm lớn hơn (từ câu trả lời của @ Katenkyo ): ổn định 15 × 15 | Tàu lượn 15 × 14

Làm thế nào nó hoạt động

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

Bao gồm +3 cho -ap0

Chạy với đầu vào là một dòng các nhóm chữ số được phân tách bằng dấu cách

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

Điều này chỉ thực sự cần thiết trong trường hợp đầu vào ổn định ngay lập tức. Trong tất cả các trường hợp khác, bạn cũng có thể cung cấp nó thuận tiện hơn dưới dạng các dòng chữ số riêng biệt:

life.pl
0000
0001
0111
0010
^D

Tuy nhiên, đưa ra đầu vào theo cách này sẽ cung cấp 1 thay vì 0 cho cấu hình ổn định ngay lập tức.

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

Gần như đánh bại Mathicala về điều này ...

Chỉ trên các phiên bản perl cũ hơn (nơi bạn có thể sử dụng hằng số làm biến), giải pháp 126 byte này mới hoạt động:

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

Trong trường hợp chắc chắn có ít nhất 2 hàng, giải pháp 123 byte này hoạt động trên tất cả các phiên bản 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

hồng ngọc, 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}

Tôi giữ một lịch sử của mỗi bảng, vì vậy nếu tôi nhận được một bảng tôi đã thấy trước khi tôi biết một trong hai điều đã xảy ra. đầu tiên có thể là chúng tôi đã tìm thấy một vị trí ổn định, trong trường hợp đó nó sẽ gây phẫn nộ nhất trong lịch sử của chúng tôi. khả năng khác là chúng ta có một vòng lặp.


Ma trận 15x15 có nghĩa là chúng ta có 2 ^ 225 bảng có thể, tôi rất nghi ngờ bạn thậm chí có thể ghi nhớ các ma trận đó bằng cách sử dụng bộ nhớ của tất cả các máy tính trên thế giới (ngay cả khi hầu hết các trò chơi có thể kết thúc với ít hơn 1000 bảng) Máy 64 bit.
Nhà phát triển Game

1
@DarioOO Ngay cả một tàu lượn trên bảng 15x14 sẽ cần "chỉ" thế hệ 840 trước khi quay trở lại trạng thái đầu tiên, vì vậy chúng ta có thể mong đợi gần như mọi thứ đều dưới 1000 gens. Ngoài ra, 1000 gens trên 15x15 sử dụng số nguyên 32 bit dẫn đến việc sử dụng bộ nhớ là 15*15*4*1000-> 900 KB, đủ tốt cho các trường hợp chúng tôi sẽ cần 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)

xác minh

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.