【问题标题】:Conway's Game of Life: check if a cell is in the corner/border康威的生命游戏:检查一个单元格是否在角落/边界
【发布时间】:2020-01-10 15:54:28
【问题描述】:

我正在尝试用 Python 实现 Game Of Life。 new_state 函数应该计算一个单元格的邻居,并根据规则(if 语句)决定它是在下一代中死亡(转 0)还是活着(转 1)。

有没有办法检查一个值是否在数组的角落/边界?一个单元格的相邻单元格将是直接周围的单元格,无需包装数组。现在, new_state 抛出一个索引错误。我正在为这个函数使用 numPy。

import numpy

def new_state(array):
    updated_array=[]
    for x in range(len(array)):
        for y in range(len(array[x])):
            cell = array[x][y]
            neighbours = (array[x-1][y-1], array[x][y-1], array[x+1][y-1], array[x+1][y], array[x+1][y+1], array[x][y+1],
                          array[x-1][y+1], array[x-1][y])
            neighbours_count = sum(neighbours)
            if cell == 1:
                if neighbours_count == 0 or neighbours_count == 1:
                    updated_array.append(0)
                elif neighbours_count == 2 or neighbours_count == 3:
                    updated_array.append(1)
                elif neighbours_count > 3:
                    updated_array.append(0)
            elif cell == 0:
                if neighbours_count == 3:
                    updated_array.append(1)
    return updated_array

【问题讨论】:

  • 您可以检查索引是否在范围内的第一个/最后一个,并考虑这种状态,实现进一步的逻辑。
  • 您是否考虑过周期性边界条件以使您的领域变得无限大......只是一个想法。

标签: python numpy conways-game-of-life


【解决方案1】:

为避免索引错误,您可以用零填充数组:

def new_state(array):
    array_padded = np.pad(array, 1)
    updated_array=array.copy()
    for x in range(1, array.shape[0]+1):
        for y in range(1, array.shape[1]+1):
            cell = array[x-1][y-1]
            neighbours = (array_padded[x-1][y-1], array_padded[x][y-1],
                          array_padded[x+1][y-1], array_padded[x+1][y],
                          array_padded[x+1][y+1], array_padded[x][y+1],
                          array_padded[x-1][y+1], array_padded[x-1][y])
            neighbours_count = sum(neighbours)
            if cell == 1 and (neighbours_count < 2 or neighbours_count > 3):
                updated_array[x-1, y-1] = 0
            elif cell == 0 and neighbours_count == 3:
                updated_array[x-1, y-1] = 1
    return updated_array

这是一个更快的矢量化版本:

from scipy.signal import correlate2d

def new_state_v(array):
    kernel = np.ones((3,3))
    kernel[1,1] = 0
    neighbours = correlate2d(array, kernel, 'same')

    updated_array=array.copy()
    updated_array[(array == 1) & ((neighbours < 2) | (neighbours > 3))] = 0
    updated_array[(array == 0) & (neighbours == 3)] = 1
    return updated_array

让我们测试一下

>>> array = np.random.randint(2, size=(5,5))
>>> array
array([[0, 0, 1, 1, 0],
       [0, 0, 1, 0, 0],
       [0, 0, 0, 0, 1],
       [1, 1, 0, 0, 1],
       [0, 1, 1, 1, 0]])

>>> new_state_v(array)
array([[0, 0, 1, 1, 0],
       [0, 0, 1, 0, 0],
       [0, 1, 0, 1, 0],
       [1, 1, 0, 0, 1],
       [1, 1, 1, 1, 0]])

速度对比:

array = np.random.randint(2, size=(1000,1000))

%timeit new_state(array)
7.76 s ± 94.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit new_state_v(array)
90.4 ms ± 703 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

【讨论】:

  • 感谢您的帖子,矢量化版本效果很好!如果游戏绕着数组的角,你会如何处理呢?
【解决方案2】:

我尚未对此进行彻底测试,但我的做法是允许数组索引值换行 - 这样除了换行之外不需要额外的逻辑(在需要修改时可能更容易出错下线)。

用途:

import numpy as np

a = np.array([[1,2,3], [4,5,6], [7,8,9], [10,11,12]])

a[np.mod(x,a.shape[0]),np.mod(y,a.shape[1])]

其中xy 是您的原始索引。

例子:

a[np.mod(4,a.shape[0]),np.mod(3,a.shape[1])]
>>> 1
# even wraps correctly with negative indexes!
a[np.mod(-1,a.shape[0]),np.mod(-1,a.shape[1])]
>>> 12

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-02-21
    • 1970-01-01
    • 2011-01-20
    • 2010-09-07
    • 2017-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多