라이프 게임을 numpy를 사용하여 구현해 보았습니다.
소개
회사의 신졸 공부회에서 라이프 게임에 대해 배웠다. 이전부터 존재 자체는 인식하고 있어 실장해 보고 싶었던 것의 하나였다. 좋은 기회이므로 Python으로 구현하고 라이프 게임이 만들어내는 세계관에 잠겨 본다.
Life 게임이란?
Wikipedia에 의하면, 라이프 게임은, 「영국의 수학자 존 호튼 컨웨이가 고안한 생명의 탄생, 진화, 도태 등의 프로세스를 간이적인 모델로 재현한 시뮬레이션 게임이다」라고 한다. 요점은 특정 초기 조건을 정의하고이를 변경하는 규칙을 적용하고 시간이 지남에 따라 상황이 어떻게 바뀌는지를 시뮬레이션하는 것입니다.
우선은 간단하기 위해 아래 그림과 같은 3×3의 검은 셀과 흰색 셀이 깔린 사각형으로 생각한다. 검은 셀은 생명이 존재하고 흰색 셀은 아무것도없는 상태를 나타냅니다.
일반적으로, 생명이 탄생하기 위해서는, 근처에 있는 일정 수의 생명이 존재할 필요가 있다. 반대로 생명이 주변에 전혀 존재하지 않는 경우, 새로운 생명이 태어나는 일은 없고, 멸종해 버린다.
이것을 이 흑과 흑의 매스의 변화로 나타내는 것이 라이프 게임이다.
여기에서 고려할 규칙은 3개 있다.
1. 중앙 셀이 흰색일 때 그 주변에 3개의 검은 셀이 존재할 때 다음 세대에서 중앙 셀은 검은 셀이 된다(생명의 탄생).
2. 중앙 셀이 검은색일 때, 그 셀 주위에 2~3개의 검은 셀이 있는 경우, 다음 세대에서도 검은 셀이 된다(유지).
3. 1,2 이외의 경우, 다음 세대에서 중앙의 셀이 희게 된다(도태).
이상의 3개의 룰에 따라, 다음 세대의 셀 배치가 정해진다.
파이썬 (numpy)에서의 구현
첫째, 규칙에 따라 다음 세대 셀의 색상을 결정하려면 $ 3\times3 $의 사각형 블록의 현재 중앙 색상과 주변의 검은 셀 수를 알아야합니다. 여기에서는 현재의 $3\times3$ 블록을 받아, 다음 세대의 블록을 돌려주는 함수를 정의해 둔다.
# calc score
def calc(a):
a[1,1] = 0
return a.sum()
# 状態を変化させる
def change(a):
x = a[1,1]
score = calc(a)
if (x==1):
if(score==2 or score==3):
a[1,1] = 1
else:
a[1,1] = 0
if (x==0):
if (score==3):
a[1,1] = 1
else:
a[1,1] = 0
return a
정의한 함수를 이용하여 다음 세대의 상태를 모두 구하는 함수를 다음과 같이 정의하였다. 여기서, 가장자리의 상태를 판단 할 수 있도록, $ N\times N $의 행렬을 $ (N + 2)\times (N + 2) $의 행렬로 확장하여 처리한다.
# matrix すべての状態を変化させる
def change_state(matrix_input):
width = matrix_input.shape[0]+2
matrix_pad = np.zeros(width**2).reshape(width,width)
new_matrix = np.zeros(width**2).reshape(width,width)
matrix_pad[1:width-1,1:width-1] =matrix_pad[1:width-1,1:width-1] + matrix_input
for i in range(width-2):
for j in range(width-2):
mat = np.copy(matrix_pad[i:i+3,j:j+3])
new_matrix[i+1,j+1] = change(mat)[1,1]
return np.array(new_matrix[1:width-1,1:width-1])
이하에서는 여기 을 참고로 Image 를 돌려주는 함수를 정의하고 있다. 후술하지만 세대마다의 Image를 보존해 두고, 최종적으로 애니메이션화하는 것으로, 라이프 게임의 상태의 추이를 확인한다.
# http://aidiary.hatenablog.com/entry/20120113/1326464820
def render(results, filename="ca.png"):
"""セルオートマトンを描画"""
width = len(results[0])
height = len(results)
img = Image.new("RGB", (width, height), (255,255,255))
draw = ImageDraw.Draw(img)
for y in range(height):
for x in range(width):
if results[y][x] == 1:
draw.point((x, y), (0, 0, 0))
return img
이 함수는 mats라는 목록에 저장된 이미지를 이미지로 표시하는 imshow를 호출하는 함수입니다. 이것은 나중에 사용하는 FuncAnimation에 시계열 당 생활 게임 셀 상태를 표현한 Image를 배달하기 위하여 정의하고 있다.
def __updated_plot(i):
return plt.imshow(mats[i])
여기까지 정의해 온 함수를 이용해, 라이프 게임을 해본다. 여기서는 $8\times 8$의 셀에서 랜덤하게 0 또는 1을 배치한 상태를 초기값으로서 실행한다. 취득한 Image 오브젝트에 대해서 __updated_plot 함수를 실행해, FuncAnimation에 시계열 마다 matplotlib의 axiesImage를 건네준다. 얻은 것을 HTML5 Video 형식으로 변환하여 동영상으로 하고 있다.
mats = []
new_mat = np.random.choice([0.,1.],64).reshape(8,8)
im = render(new_mat)
mats.append(im)
for i in range(100):
new_mat = change_state(new_mat)
im = render(new_mat)
mats.append(im)
fig = plt.figure()
anim = FuncAnimation(fig, __updated_plot, frames=len(mats), interval=1000)
HTML(anim.to_html5_video())
이하에 나타낸 것은, 이전에, 적당한 초기 상태(글라이더라고 불리는 것을 2개 조금 어긋나게 배치)로부터 세대를 경과할 때마다 어떻게 변화하는지를 본 것이다.
할 수 있었다. 자다. 피 c. 라고 r. 이 m/R4SlMb 키 R — Blackcat🌗 (요코야마 마사키) (@myblackcat7112) August 1, 2019
Wikipedia에 의하면, 라이프 게임은, 「영국의 수학자 존 호튼 컨웨이가 고안한 생명의 탄생, 진화, 도태 등의 프로세스를 간이적인 모델로 재현한 시뮬레이션 게임이다」라고 한다. 요점은 특정 초기 조건을 정의하고이를 변경하는 규칙을 적용하고 시간이 지남에 따라 상황이 어떻게 바뀌는지를 시뮬레이션하는 것입니다.
우선은 간단하기 위해 아래 그림과 같은 3×3의 검은 셀과 흰색 셀이 깔린 사각형으로 생각한다. 검은 셀은 생명이 존재하고 흰색 셀은 아무것도없는 상태를 나타냅니다.
일반적으로, 생명이 탄생하기 위해서는, 근처에 있는 일정 수의 생명이 존재할 필요가 있다. 반대로 생명이 주변에 전혀 존재하지 않는 경우, 새로운 생명이 태어나는 일은 없고, 멸종해 버린다.
이것을 이 흑과 흑의 매스의 변화로 나타내는 것이 라이프 게임이다.
여기에서 고려할 규칙은 3개 있다.
1. 중앙 셀이 흰색일 때 그 주변에 3개의 검은 셀이 존재할 때 다음 세대에서 중앙 셀은 검은 셀이 된다(생명의 탄생).
2. 중앙 셀이 검은색일 때, 그 셀 주위에 2~3개의 검은 셀이 있는 경우, 다음 세대에서도 검은 셀이 된다(유지).
3. 1,2 이외의 경우, 다음 세대에서 중앙의 셀이 희게 된다(도태).
이상의 3개의 룰에 따라, 다음 세대의 셀 배치가 정해진다.
파이썬 (numpy)에서의 구현
첫째, 규칙에 따라 다음 세대 셀의 색상을 결정하려면 $ 3\times3 $의 사각형 블록의 현재 중앙 색상과 주변의 검은 셀 수를 알아야합니다. 여기에서는 현재의 $3\times3$ 블록을 받아, 다음 세대의 블록을 돌려주는 함수를 정의해 둔다.
# calc score
def calc(a):
a[1,1] = 0
return a.sum()
# 状態を変化させる
def change(a):
x = a[1,1]
score = calc(a)
if (x==1):
if(score==2 or score==3):
a[1,1] = 1
else:
a[1,1] = 0
if (x==0):
if (score==3):
a[1,1] = 1
else:
a[1,1] = 0
return a
정의한 함수를 이용하여 다음 세대의 상태를 모두 구하는 함수를 다음과 같이 정의하였다. 여기서, 가장자리의 상태를 판단 할 수 있도록, $ N\times N $의 행렬을 $ (N + 2)\times (N + 2) $의 행렬로 확장하여 처리한다.
# matrix すべての状態を変化させる
def change_state(matrix_input):
width = matrix_input.shape[0]+2
matrix_pad = np.zeros(width**2).reshape(width,width)
new_matrix = np.zeros(width**2).reshape(width,width)
matrix_pad[1:width-1,1:width-1] =matrix_pad[1:width-1,1:width-1] + matrix_input
for i in range(width-2):
for j in range(width-2):
mat = np.copy(matrix_pad[i:i+3,j:j+3])
new_matrix[i+1,j+1] = change(mat)[1,1]
return np.array(new_matrix[1:width-1,1:width-1])
이하에서는 여기 을 참고로 Image 를 돌려주는 함수를 정의하고 있다. 후술하지만 세대마다의 Image를 보존해 두고, 최종적으로 애니메이션화하는 것으로, 라이프 게임의 상태의 추이를 확인한다.
# http://aidiary.hatenablog.com/entry/20120113/1326464820
def render(results, filename="ca.png"):
"""セルオートマトンを描画"""
width = len(results[0])
height = len(results)
img = Image.new("RGB", (width, height), (255,255,255))
draw = ImageDraw.Draw(img)
for y in range(height):
for x in range(width):
if results[y][x] == 1:
draw.point((x, y), (0, 0, 0))
return img
이 함수는 mats라는 목록에 저장된 이미지를 이미지로 표시하는 imshow를 호출하는 함수입니다. 이것은 나중에 사용하는 FuncAnimation에 시계열 당 생활 게임 셀 상태를 표현한 Image를 배달하기 위하여 정의하고 있다.
def __updated_plot(i):
return plt.imshow(mats[i])
여기까지 정의해 온 함수를 이용해, 라이프 게임을 해본다. 여기서는 $8\times 8$의 셀에서 랜덤하게 0 또는 1을 배치한 상태를 초기값으로서 실행한다. 취득한 Image 오브젝트에 대해서 __updated_plot 함수를 실행해, FuncAnimation에 시계열 마다 matplotlib의 axiesImage를 건네준다. 얻은 것을 HTML5 Video 형식으로 변환하여 동영상으로 하고 있다.
mats = []
new_mat = np.random.choice([0.,1.],64).reshape(8,8)
im = render(new_mat)
mats.append(im)
for i in range(100):
new_mat = change_state(new_mat)
im = render(new_mat)
mats.append(im)
fig = plt.figure()
anim = FuncAnimation(fig, __updated_plot, frames=len(mats), interval=1000)
HTML(anim.to_html5_video())
이하에 나타낸 것은, 이전에, 적당한 초기 상태(글라이더라고 불리는 것을 2개 조금 어긋나게 배치)로부터 세대를 경과할 때마다 어떻게 변화하는지를 본 것이다.
할 수 있었다. 자다. 피 c. 라고 r. 이 m/R4SlMb 키 R — Blackcat🌗 (요코야마 마사키) (@myblackcat7112) August 1, 2019
# calc score
def calc(a):
a[1,1] = 0
return a.sum()
# 状態を変化させる
def change(a):
x = a[1,1]
score = calc(a)
if (x==1):
if(score==2 or score==3):
a[1,1] = 1
else:
a[1,1] = 0
if (x==0):
if (score==3):
a[1,1] = 1
else:
a[1,1] = 0
return a
# matrix すべての状態を変化させる
def change_state(matrix_input):
width = matrix_input.shape[0]+2
matrix_pad = np.zeros(width**2).reshape(width,width)
new_matrix = np.zeros(width**2).reshape(width,width)
matrix_pad[1:width-1,1:width-1] =matrix_pad[1:width-1,1:width-1] + matrix_input
for i in range(width-2):
for j in range(width-2):
mat = np.copy(matrix_pad[i:i+3,j:j+3])
new_matrix[i+1,j+1] = change(mat)[1,1]
return np.array(new_matrix[1:width-1,1:width-1])
# http://aidiary.hatenablog.com/entry/20120113/1326464820
def render(results, filename="ca.png"):
"""セルオートマトンを描画"""
width = len(results[0])
height = len(results)
img = Image.new("RGB", (width, height), (255,255,255))
draw = ImageDraw.Draw(img)
for y in range(height):
for x in range(width):
if results[y][x] == 1:
draw.point((x, y), (0, 0, 0))
return img
def __updated_plot(i):
return plt.imshow(mats[i])
mats = []
new_mat = np.random.choice([0.,1.],64).reshape(8,8)
im = render(new_mat)
mats.append(im)
for i in range(100):
new_mat = change_state(new_mat)
im = render(new_mat)
mats.append(im)
fig = plt.figure()
anim = FuncAnimation(fig, __updated_plot, frames=len(mats), interval=1000)
HTML(anim.to_html5_video())
마지막으로, colabratory에서의 구현을 여기 에 나타냅니다.
Reference
이 문제에 관하여(라이프 게임을 numpy를 사용하여 구현해 보았습니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/myblackcat7112/items/37e17af41b9e04aca11b텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)