Compare commits

..

25 Commits

Author SHA1 Message Date
Tom Weber 3b33dc23c0 glider and acorn start
ci/woodpecker/push/woodpecker Pipeline was successful Details
2 years ago
Tom Weber 62cfa5de1f glider and acorn start
ci/woodpecker/push/woodpecker Pipeline was successful Details
2 years ago
Tom Weber 7c56c9fa6f pyproject deps
ci/woodpecker/push/woodpecker Pipeline was successful Details
2 years ago
Tom Weber 6caaf3e31f pyproject deps
ci/woodpecker/push/woodpecker Pipeline failed Details
2 years ago
Tom Weber 096a2beb07 rm -rf plt
ci/woodpecker/push/woodpecker Pipeline failed Details
2 years ago
Tom Weber 17e5ffba53 update dependencies
ci/woodpecker/push/woodpecker Pipeline failed Details
2 years ago
Tom Weber d2e8aa0b78 update woodpecker to not use requirements
ci/woodpecker/push/woodpecker Pipeline failed Details
2 years ago
Tom Weber cb6b78aeec dependencies into pyproject.toml
ci/woodpecker/push/woodpecker Pipeline failed Details
2 years ago
Tom Weber b699b2146c refactor
ci/woodpecker/push/woodpecker Pipeline was successful Details
2 years ago
Tom Weber affb0a3a27 cleanup for django
ci/woodpecker/push/woodpecker Pipeline was successful Details
2 years ago
Tom Weber 728f67de93 starting func
ci/woodpecker/push/woodpecker Pipeline failed Details
2 years ago
Tom Weber 50c09332e1 starting func
2 years ago
Tom Weber a750e8a47f woodpecker test with passing pytest
ci/woodpecker/push/woodpecker Pipeline was successful Details
2 years ago
Tom Weber b167092366 woodpecker test with passing pytest
ci/woodpecker/push/woodpecker Pipeline failed Details
2 years ago
Tom Weber f110972d79 woodpecker test with passing pytest
ci/woodpecker/push/woodpecker Pipeline failed Details
2 years ago
Tom Weber a1e4e78f03 woodpecker test with passing pytest
ci/woodpecker/push/woodpecker Pipeline failed Details
2 years ago
Tom Weber 509f8123a2 woodpecker test with passing pytest
ci/woodpecker/push/woodpecker Pipeline failed Details
2 years ago
Tom Weber 3e79c402cc woodpecker test with non passing pytest
ci/woodpecker/push/woodpecker Pipeline failed Details
2 years ago
Tom Weber d02427df20 woodpecker test with non passing pytest
ci/woodpecker/push/woodpecker Pipeline was successful Details
2 years ago
Tom Weber 04df494617 woodpecker test with non passing pytest
ci/woodpecker/push/woodpecker Pipeline was successful Details
2 years ago
Tom Weber b86934cf49 pyproject addition and simple tests for ci
ci/woodpecker/push/woodpecker Pipeline was successful Details
2 years ago
Tom Weber 6c34b9940f refactor for woodpecker and testing
ci/woodpecker/push/woodpecker Pipeline was successful Details
2 years ago
Tom Weber bc01ea89d5 refactor for woodpecker and testing
ci/woodpecker/push/woodpecker Pipeline was successful Details
2 years ago
Tom Weber c5bc7c4c81 testing woodpecker
ci/woodpecker/push/woodpecker Pipeline was successful Details
2 years ago
Tom Weber 1f6da02144 testing woodpecker
ci/woodpecker/push/woodpecker Pipeline was successful Details
2 years ago

1
.gitignore vendored

@ -6,6 +6,7 @@ __pycache__/
# C extensions # C extensions
*.so *.so
.idea/
# Distribution / packaging # Distribution / packaging
.Python .Python
build/ build/

@ -0,0 +1,29 @@
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

@ -0,0 +1,19 @@
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,8 +1,7 @@
# Conway's Game of Life # Conway's Game of Life
[![status-badge](https://ci.weber.codes/api/badges/tom/gameoflife/status.svg)](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.

@ -1,79 +0,0 @@
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,
)

@ -0,0 +1,31 @@
[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",
]

@ -1,15 +0,0 @@
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

@ -1,19 +0,0 @@
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'
],
)

@ -0,0 +1,29 @@
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,9 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
import copy import copy
import matplotlib.pyplot as plt
import numpy as np import numpy as np
from conway.anime import PltAnimation
from conway.anime import PlotlyAnimation from conway.anime import PlotlyAnimation
@ -32,6 +30,7 @@ class State(object):
def randomBoard(self): def randomBoard(self):
self.board = np.random.binomial(1, 0.5, (self.width, self.depth)) self.board = np.random.binomial(1, 0.5, (self.width, self.depth))
return self.board return self.board
def terminal_render(self): def terminal_render(self):
print("-" * (self.width + 2)) print("-" * (self.width + 2))
for i in self.board: for i in self.board:
@ -42,10 +41,6 @@ class State(object):
) )
print("-" * (self.width + 2)) print("-" * (self.width + 2))
def plt_render(self):
plt.imshow(self.board)
plt.show()
def step(self): def step(self):
boardcopy = copy.deepcopy(self.board) boardcopy = copy.deepcopy(self.board)
for rowidx, row in enumerate(self.board): for rowidx, row in enumerate(self.board):
@ -90,21 +85,31 @@ class State(object):
alive += 1 alive += 1
return alive return alive
def get_anime(size=100, steps=100, start="random"): def get_anime(size=100, steps=100, start="random"):
state = State(size, size, start) state = State(size, size, start)
anime = PlotlyAnimation(state, steps) anime = PlotlyAnimation(state, steps)
return anime.animation return anime.animation
def get_starting_board(size, start="random"):
# TODO: implement other starting options like e.g. glider
if start == "random":
return State(size, size, "random")
if start == "glider":
return State(size, size, [(0, 1), (1, 2), (2, 0), (2, 1), (2, 2)])
if start == "acorn":
return State(size, size, coords=[(20+5, 20+3), (20+5, 20+4), (20+3, 20+4), (20+4, 20+6), (20+5, 20+7), (20+5, 20+8), (20+5, 20+9)])
else:
return State(size, size, None)
def get(size = 50, steps = 200, start="random"):
board = get_starting_board(size, start)
return PlotlyAnimation(board, steps).animation
def main(): def main():
# state = State(20, 20, [(0, 1), (1, 2), (2, 0), (2, 1), (2, 2)]) anime = get(50, 200, "acorn")
anime.show()
state = State(100, 100, "random")
#animation = PltAnimation(state)
#ani = animation.animate()
#plt.show()
animation = PlotlyAnimation(state, 100)
animation.show()
if __name__ == "__main__": if __name__ == "__main__":
main() main()

@ -0,0 +1,12 @@
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

@ -0,0 +1,17 @@
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…
Cancel
Save