问题

根据百度百科,生命游戏,简称为生命,是英国数学家约翰·何顿·康威在 1970 年发明的细胞自动机。

给定一个包含 m × n 个格子的面板,每一个格子都可以看成是一个细胞。每个细胞都具有一个初始状态:1 即为活细胞(live),或 0 即为死细胞(dead)。每个细胞与其八个相邻位置(水平,垂直,对角线)的细胞都遵循以下四条生存定律:

  1. 如果活细胞周围八个位置的活细胞数少于两个,则该位置活细胞死亡;
  2. 如果活细胞周围八个位置有两个或三个活细胞,则该位置活细胞仍然存活;
  3. 如果活细胞周围八个位置有超过三个活细胞,则该位置活细胞死亡;
  4. 如果死细胞周围正好有三个活细胞,则该位置死细胞复活;

根据当前状态,写一个函数来计算面板上所有细胞的下一个(一次更新后的)状态。下一个状态是通过将上述规则同时应用于当前状态下的每个细胞所形成的,其中细胞的出生和死亡是同时发生的。

示例:

输入:
[
[0,1,0],
[0,0,1],
[1,1,1],
[0,0,0]
]
输出:
[
[0,0,0],
[1,0,1],
[0,1,1],
[0,1,0]
]

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def gameOfLife(self, board: List[List[int]]) -> None:
r=len(board)
c=len(board[0])
direct=[(-1,-1),(0,-1),(1,-1),(1,0),(1,1),(0,1),(-1,1),(-1,0)]
for i in range(0,r):
for j in range(0,c):
n=sum(board[i+d[0]][j+d[1]]&1 for d in direct if 0<=i+d[0]<r and 0<=j+d[1]<c)
if board[i][j]&1==1:
if n==2 or n==3:
board[i][j]|=2
elif n==3:
board[i][j]|=2
for i in range(0,r):
for j in range(0,c):
board[i][j]>>=1

为了记住下一轮状态,同时不使用额外的空间,也不能直接改变原来的状态,因为是按顺序扫描的,改了之后,扫描其他格子时判断依据就不正确了。
因为状态只有0和1,所以扩展一位二进制作为下一轮状态,判断当前状态只需和1相与board[i][j]&1。只判断下一轮仍然是活的情况,将二进制的第2位标记为1,即和2做或运算board[i][j]|=2
每个格子扫描完毕后,全部右移一位,使下一轮状态恢复成当前状态。