Compare commits
1 Commits
master
...
matplotlib
Author | SHA1 | Date |
---|---|---|
|
220f0e7ffa | 2 years ago |
@ -1,29 +0,0 @@
|
|||||||
pipeline:
|
|
||||||
standardize:
|
|
||||||
image: python:${TAG}-buster
|
|
||||||
commands:
|
|
||||||
- python -m pip install --upgrade pip
|
|
||||||
# - python -m pip install -r requirements.txt
|
|
||||||
- python -m pip install pylint flake8 mypy>=0.971
|
|
||||||
- python -m flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
|
|
||||||
# - mypy --strict serial_sphinx/
|
|
||||||
# - python -m pylint -f parseable serial_sphinx/*.py
|
|
||||||
|
|
||||||
build:
|
|
||||||
image: python:${TAG}-buster
|
|
||||||
commands:
|
|
||||||
- ls
|
|
||||||
- python -m venv venv
|
|
||||||
- /bin/bash -c "source venv/bin/activate"
|
|
||||||
- python -m pip install --upgrade pip pytest
|
|
||||||
# - python -m pip install -r requirements.txt
|
|
||||||
- python -m pip install .
|
|
||||||
- python -m pytest
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
matrix:
|
|
||||||
TAG:
|
|
||||||
- 3.9
|
|
||||||
- 3.10
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
|||||||
Copyright (c) 2022 Tom Weber
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
@ -1,7 +1,8 @@
|
|||||||
# Conway's Game of Life
|
# Conway's Game of Life
|
||||||
|
|
||||||
[](https://ci.weber.codes/tom/gameoflife)
|
|
||||||
|
|
||||||
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.
|
This is a game that relies on simple rules but can spawn complex behaviour.
|
||||||
|
|
||||||
|
A simple python implementation of Conway's Game of Life.
|
||||||
|
@ -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,31 +0,0 @@
|
|||||||
[build-system]
|
|
||||||
requires = ["setuptools>=61.0"]
|
|
||||||
build-backend = "setuptools.build_meta"
|
|
||||||
|
|
||||||
[project]
|
|
||||||
name = "conway"
|
|
||||||
version = "0.0.1"
|
|
||||||
authors = [
|
|
||||||
{ name="Tom Weber", email="tom@weber.codes" },
|
|
||||||
]
|
|
||||||
description = "A game of life implementation"
|
|
||||||
readme = "README.md"
|
|
||||||
requires-python = ">=3.7"
|
|
||||||
classifiers = [
|
|
||||||
"Programming Language :: Python :: 3",
|
|
||||||
"License :: OSI Approved :: MIT License",
|
|
||||||
"Operating System :: OS Independent",
|
|
||||||
]
|
|
||||||
dependencies = [
|
|
||||||
"numpy>=1.23.3",
|
|
||||||
"plotly>=5.11.0",
|
|
||||||
"pandas>=1.5.1"
|
|
||||||
]
|
|
||||||
|
|
||||||
[project.urls]
|
|
||||||
"repository" = "https://git.weber.codes/tom/gameoflife"
|
|
||||||
|
|
||||||
[tool.pytest.ini_options]
|
|
||||||
addopts = [
|
|
||||||
"--import-mode=importlib",
|
|
||||||
]
|
|
@ -0,0 +1,15 @@
|
|||||||
|
contourpy==1.0.5
|
||||||
|
cycler==0.11.0
|
||||||
|
fonttools==4.37.4
|
||||||
|
kiwisolver==1.4.4
|
||||||
|
matplotlib==3.6.0
|
||||||
|
numpy==1.23.3
|
||||||
|
packaging==21.3
|
||||||
|
pandas==1.5.1
|
||||||
|
Pillow==9.2.0
|
||||||
|
plotly==5.11.0
|
||||||
|
pyparsing==3.0.9
|
||||||
|
python-dateutil==2.8.2
|
||||||
|
pytz==2022.6
|
||||||
|
six==1.16.0
|
||||||
|
tenacity==8.1.0
|
@ -0,0 +1,19 @@
|
|||||||
|
from setuptools import setup
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='conway',
|
||||||
|
version='0.1.0',
|
||||||
|
description="A conway's game of life implementation",
|
||||||
|
url='https://git.weber.codes/tom/conwaysgameoflife',
|
||||||
|
author='Tom Weber',
|
||||||
|
author_email='mail@weber.codes',
|
||||||
|
license='BSD 2-clause',
|
||||||
|
packages=['conway'],
|
||||||
|
install_requires=['wheel',
|
||||||
|
'numpy',
|
||||||
|
'pandas',
|
||||||
|
'matplotlib',
|
||||||
|
'plotly'
|
||||||
|
],
|
||||||
|
|
||||||
|
)
|
@ -1,29 +0,0 @@
|
|||||||
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, color_continuous_scale=[[0, "white"], [1, "black"]])
|
|
||||||
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()
|
|
@ -1,12 +0,0 @@
|
|||||||
import pytest
|
|
||||||
import conway.anime as anime
|
|
||||||
import conway.gameoflife as gol
|
|
||||||
|
|
||||||
|
|
||||||
class TestPlotlyAnimation:
|
|
||||||
state = gol.State(10, 10, "random")
|
|
||||||
steps = 10
|
|
||||||
plotly_anime = anime.PlotlyAnimation(state, steps)
|
|
||||||
def test_frame_gen(self):
|
|
||||||
assert self.plotly_anime.frames.shape == (11,10,10)
|
|
||||||
assert len(self.plotly_anime.frame_gen()) == 2 * self.steps + 1
|
|
@ -1,17 +0,0 @@
|
|||||||
import pytest
|
|
||||||
import numpy as np
|
|
||||||
import conway.gameoflife as gol
|
|
||||||
|
|
||||||
|
|
||||||
class TestState:
|
|
||||||
def test_neighbours(self):
|
|
||||||
state = gol.State(10, 10)
|
|
||||||
n1 = np.array([[1, 1, 1], [1, 1, 1], [1, 1, 1]])
|
|
||||||
assert state.checkNeighbours(n1, 1, 1) == 8
|
|
||||||
assert state.checkNeighbours(n1, 1, 1, neighbourhood="neumann") == 4
|
|
||||||
n2 = np.array([[0, 0, 0], [0, 0, 0], [0, 0, 0]])
|
|
||||||
assert state.checkNeighbours(n2, 1, 1) == 0
|
|
||||||
assert state.checkNeighbours(n2, 1, 1, neighbourhood="neumann") == 0
|
|
||||||
n3 = np.array([[1, 0, 1], [0, 1, 0], [1, 0, 1]])
|
|
||||||
assert state.checkNeighbours(n3, 1, 1, neighbourhood="moore") == 4
|
|
||||||
assert state.checkNeighbours(n3, 1, 1, neighbourhood="neumann") == 0
|
|
Loading…
Reference in new issue