Conway 的生命游戏:检查一个单元格是否在 corner/border
Conway's Game of Life: check if a cell is in the corner/border
我正在尝试在 Python 中实现 Game Of Life。 new_state 函数应该计算一个细胞的邻居,并根据规则(if 语句)决定它是否会在下一代死亡(转 0)或存活(转 1)。
有没有办法检查一个值是否在数组的 corner/border 中?一个单元格的相邻单元格将是直接周围的单元格,不需要包装阵列。现在,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
我还没有彻底测试过这个,但我的方法是允许数组索引值换行——这样除了换行之外不需要额外的逻辑(这可能更容易出错需要进行修改)。
使用:
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])]
其中 x
和 y
是您的原始索引。
示例:
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
为避免索引错误,您可以用零填充数组:
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)
我正在尝试在 Python 中实现 Game Of Life。 new_state 函数应该计算一个细胞的邻居,并根据规则(if 语句)决定它是否会在下一代死亡(转 0)或存活(转 1)。
有没有办法检查一个值是否在数组的 corner/border 中?一个单元格的相邻单元格将是直接周围的单元格,不需要包装阵列。现在,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
我还没有彻底测试过这个,但我的方法是允许数组索引值换行——这样除了换行之外不需要额外的逻辑(这可能更容易出错需要进行修改)。
使用:
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])]
其中 x
和 y
是您的原始索引。
示例:
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
为避免索引错误,您可以用零填充数组:
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)