GAME OF LIFE
1、问题介绍
这是个模拟生命演化的游戏,在一个广阔的生存空间里,设定生命群落存活和繁衍的规则,个体和群落依据既相互竞争又相互依存的法则进行进化。
假定:对于每一个单元,在它的 3 × 3 3\times3 3×3邻域内:少于2邻居,死;多于3邻居,死;正好3邻居,生。
2、python模拟
规则:
- 用Python实现游戏规则
- 在1000x1000共一百万个单元里模拟
- 尽量短的代码
- 尽量高效
思路一:
对每个单元的3x3邻域进行统计
import random as random
import timeit
# 产生一个百万0,1数组,0代表空(死),1代表生
Z = [[random.choice([0,1]) for x in range(1000)] for y in range(1000)]
# 计算八个邻居数目
def neighbours(Z):
s = len(Z), len(Z[0])
# 一个初始全为0的邻居数量矩阵
N = [[0,]*(s[0]) for i in range(s[1])]
for x in range(1, s[0]-1):
for y in range(1, s[1]-1):
N[x][y] = (Z[x-1][y-1] + Z[x][y-1] + Z[x+1][y-1] +
Z[x-1][y] + Z[x+1][y] +
Z[x-1][y+1] + Z[x][y+1] + Z[x+1][y+1])
return N
# 根据周围邻居总数应用规则
def evolve(Z):
s = len(Z), len(Z[0])
N = neighbours(Z)
for x in range(1, s[0]-1):
for y in range(1, s[1]-1):
if Z[x][y] == 1 and (N[x][y] < 2 or N[x][y] > 3): # 灭亡规则
Z[x][y] = 0
elif Z[x][y] == 0 and N[x][y] == 3: # 繁衍规则
Z[x][y] = 1
return Z
print(timeit.timeit(lambda: evolve(Z), number=3)) # 对百万人口作三代进化,统计运算效率
思路二:
把1000x1000共一百万个单元当作一个整体进行运算
import timeit
import numpy as np
Znp = np.random.randint(2, size=(1000,1000))
#print(Znp)
def nextGeneration(Z):
neighborCount = sum(np.roll(np.roll(Z, i, 0), j, 1) for i in (-1, 0, 1) for j in (-1, 0, 1) if (i != 0 or j != 0))
#return (neighborCount == 3) | ((neighborCount == 1) & (neighborCount == 2)).astype("int8")
return (neighborCount == 3) | ((neighborCount == 1) & (neighborCount == 2))
def np_solver(Z):
#Z = np.argwhere(nextGeneration(Z))#下一代
Z = np.where(nextGeneration(Z),1,0)#下一代
return Z # 把实现填进来
print(timeit.timeit(lambda: np_solver(Znp), number=3))
思路三:
只对有生命的单元进行运算
from collections import namedtuple, defaultdict
import random as random
import timeit
Cell = namedtuple('Cell', ['x', 'y'])
Z = [[random.choice([0,1]) for x in range(10)] for y in range(10)]
def getNeighbours(cell):
for x in range(cell.x - 1, cell.x + 2):
for y in range(cell.y - 1, cell.y + 2):
if (x, y) != (cell.x, cell.y):
yield Cell(x, y)
def getNeighbourCount(board):
neighbour_counts = defaultdict(int)
for cell in board:
for neighbour in getNeighbours(cell):
neighbour_counts[neighbour] += 1
return neighbour_counts
def advanceBoard(board):
new_board = set()
for cell, count in getNeighbourCount(board).items():
if count == 3 or (cell in board and count == 2):
new_board.add(cell)
return new_board
def generateBoard(desc):
board = set()
row , col = len(desc),len(desc[0])
for i in range(row):
for j in range(col):
if desc[i][j] == 1:
board.add(Cell(int(i), int(j)))
return board
def evolve(Z):
f = generateBoard(Z)
f = advanceBoard(f)
return f
print(timeit.timeit(lambda: evolve(Z), number=3))