added PyPlot Animation, changed board starte to numpy instead of python list

matplotlib
Tom Weber 2 years ago
parent f42fa91f1d
commit 377ace5e29

@ -1,4 +1,6 @@
# Conway's Game of Life # Conway's Game of Life
Rules: https://en.wikipedia.org/wiki/Conway's_Game_of_Life Rules: https://en.wikipedia.org/wiki/Conway\'s_Game_of_Life
This is a game that relies on simple rules but can spawn complex behaviour.

@ -0,0 +1,79 @@
import matplotlib.animation as animation
import matplotlib.pyplot as plt
#import plotly.graph_objects as go
import plotly.express as px
import numpy as np
class PlotlyAnimation(object):
def __init__(self, state, steps):
self.state = state
self.steps = steps
self.frames = np.expand_dims(self.state.board, axis=0)
self.frame_gen()
self.animation = self.animation_gen()
def frame_gen(self):
for _ in range(self.steps):
self.frames = np.concatenate((self.frames, np.expand_dims(self.state.step(), axis=0)), axis=0)
return self.frames
def animation_gen(self):
fig = px.imshow(self.frames, animation_frame=0)
fig.layout.updatemenus[0].buttons[0].args[1]['frame']['duration'] = 30
fig.layout.updatemenus[0].buttons[0].args[1]['transition']['duration'] = 5
fig.layout.updatemenus[0].showactive = True
fig.layout.sliders[0].visible = False
fig.layout.coloraxis.showscale = False
fig.layout.xaxis.showticklabels = False
fig.layout.yaxis.showticklabels = False
return fig
def show(self):
self.animation.show()
class PltAnimation(object):
def __init__(self, state, steps=None):
self.state = state
self.steps = steps
self.fig, self.ax = plt.subplots()
self.ax = self.ax.matshow(self.state.board)
def frame_yield(self):
while True:
self.state.step()
yield self.state.board
def frame_gen(self):
frames = []
for i in range(self.steps):
self.state.step()
[].append(self.state.board)
return self.ax, frames
def init(self):
return self.state.board
def update(self, data):
self.ax.set_data(data)
return self.ax
def animate(self):
if self.steps is None:
return animation.FuncAnimation(
self.fig,
self.update,
self.frame_yield,
init_func=self.init,
interval=100,
)
else:
return animation.FuncAnimation(
self.fig,
self.update,
self.frame_gen,
init_func=self.init,
interval=100,
)

@ -1,7 +1,11 @@
#!/usr/bin/env python
import random import random
import copy import copy
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import matplotlib.animation as animation import numpy as np
from anime import PltAnimation
from anime import PlotlyAnimation
class State(object): class State(object):
@ -9,17 +13,16 @@ class State(object):
# Coords: tuple of ints or list of tuple of ints # Coords: tuple of ints or list of tuple of ints
self.width = width self.width = width
self.depth = depth self.depth = depth
self.board = np.array([[0 for i in range(width)] for j in range(depth)])
self.board = [[0 for i in range(width)] for j in range(depth)]
if coords is None: if coords is None:
pass pass
elif isinstance(coords, tuple): elif isinstance(coords, tuple):
x, y = coords x, y = coords
self.board[x][y] = 1 self.board[x, y] = 1
elif isinstance(coords, list): elif isinstance(coords, list):
for pair in coords: for pair in coords:
x, y = pair x, y = pair
self.board[x][y] = 1 self.board[x, y] = 1
elif coords == "random": elif coords == "random":
self.randomBoard() self.randomBoard()
else: else:
@ -31,9 +34,9 @@ class State(object):
for idx, i in enumerate(self.board): for idx, i in enumerate(self.board):
for jdx, j in enumerate(i): for jdx, j in enumerate(i):
if random.randint(1, 2) == 1: if random.randint(1, 2) == 1:
self.board[idx][jdx] = 1 self.board[idx, jdx] = 1
else: else:
self.board[idx][jdx] = 0 self.board[idx, jdx] = 0
def terminal_render(self): def terminal_render(self):
print("-" * (self.width + 2)) print("-" * (self.width + 2))
@ -54,84 +57,57 @@ class State(object):
for rowidx, row in enumerate(self.board): for rowidx, row in enumerate(self.board):
for elemidx, elem in enumerate(row): for elemidx, elem in enumerate(row):
live_neighbours = self.checkNeighbours(boardcopy, rowidx, elemidx) live_neighbours = self.checkNeighbours(boardcopy, rowidx, elemidx)
if self.board[rowidx][elemidx] == 1: if self.board[rowidx, elemidx] == 1:
if live_neighbours == 2 or live_neighbours == 3: if live_neighbours == 2 or live_neighbours == 3:
pass pass
else: else:
self.board[rowidx][elemidx] = 0 self.board[rowidx, elemidx] = 0
else: else:
if live_neighbours == 3: if live_neighbours == 3:
self.board[rowidx][elemidx] = 1 self.board[rowidx, elemidx] = 1
return self.board
def checkNeighbours(self, board, rowindex, columnindex, neighbourhood="moore"): def checkNeighbours(self, board, rowindex, columnindex, neighbourhood="moore"):
alive = 0 alive = 0
if rowindex != 0: if rowindex != 0:
if board[rowindex - 1][columnindex] == 1: if board[rowindex - 1, columnindex] == 1:
alive += 1 alive += 1
if rowindex < self.depth - 1: if rowindex < self.depth - 1:
if board[rowindex + 1][columnindex] == 1: if board[rowindex + 1, columnindex] == 1:
alive += 1 alive += 1
if columnindex != 0: if columnindex != 0:
if board[rowindex][columnindex - 1] == 1: if board[rowindex, columnindex - 1] == 1:
alive += 1 alive += 1
if columnindex < self.width - 1: if columnindex < self.width - 1:
if board[rowindex][columnindex + 1] == 1: if board[rowindex, columnindex + 1] == 1:
alive += 1 alive += 1
if neighbourhood == "moore": if neighbourhood == "moore":
if rowindex != 0 and columnindex != 0: if rowindex != 0 and columnindex != 0:
if board[rowindex - 1][columnindex - 1] == 1: if board[rowindex - 1, columnindex - 1] == 1:
alive += 1 alive += 1
if rowindex < self.depth - 1 and columnindex < self.width - 1: if rowindex < self.depth - 1 and columnindex < self.width - 1:
if board[rowindex + 1][columnindex + 1] == 1: if board[rowindex + 1, columnindex + 1] == 1:
alive += 1 alive += 1
if rowindex != 0 and columnindex < self.width - 1: if rowindex != 0 and columnindex < self.width - 1:
if board[rowindex - 1][columnindex + 1] == 1: if board[rowindex - 1, columnindex + 1] == 1:
alive += 1 alive += 1
if rowindex < self.depth - 1 and columnindex != 0: if rowindex < self.depth - 1 and columnindex != 0:
if board[rowindex + 1][columnindex - 1] == 1: if board[rowindex + 1, columnindex - 1] == 1:
alive += 1 alive += 1
return alive return alive
class BoardAnimation(object):
def __init__(self, state, steps=None):
self.state = state
self.steps = steps
self.fig, self.ax = plt.subplots()
self.ax = self.ax.matshow(self.state.board)
def frame_yield(self):
while True:
self.state.step()
yield self.state.board
def frame_gen(self):
frames = []
for i in range(self.steps):
self.state.step()
[].append(self.state.board)
return self.ax, frames
def init(self):
return self.state.board
def update(self, data):
self.ax.set_data(data)
return self.ax
def animate(self):
return animation.FuncAnimation(
self.fig, self.update, self.frame_yield, init_func=self.init, interval=100
)
def main(): def main():
state = State(20, 20, [(0, 1), (1, 2), (2, 0), (2, 1), (2, 2)]) # state = State(20, 20, [(0, 1), (1, 2), (2, 0), (2, 1), (2, 2)])
animation = BoardAnimation(state)
ani = animation.animate() state = State(100, 100, "random")
plt.show() #animation = PltAnimation(state)
#ani = animation.animate()
#plt.show()
animation = PlotlyAnimation(state, 100)
animation.show()
if __name__ == "__main__": if __name__ == "__main__":
main() main()

@ -5,7 +5,11 @@ kiwisolver==1.4.4
matplotlib==3.6.0 matplotlib==3.6.0
numpy==1.23.3 numpy==1.23.3
packaging==21.3 packaging==21.3
pandas==1.5.1
Pillow==9.2.0 Pillow==9.2.0
plotly==5.11.0
pyparsing==3.0.9 pyparsing==3.0.9
python-dateutil==2.8.2 python-dateutil==2.8.2
pytz==2022.6
six==1.16.0 six==1.16.0
tenacity==8.1.0

Loading…
Cancel
Save