Fix/display stop when done
This commit is contained in:
parent
9e211aa581
commit
6d1666bb8b
@ -98,8 +98,12 @@ There ist still quite some work to do.
|
|||||||
And for all others, don't hesitate to open issues when you have problems!
|
And for all others, don't hesitate to open issues when you have problems!
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
#### 1.0.8
|
||||||
|
- Fixes automaton using edge cells with radius > 1 not working
|
||||||
|
- Fixes automaton is not stopping after evolution ended
|
||||||
|
|
||||||
#### 1.0.7
|
#### 1.0.7
|
||||||
- Fixes automaton ont active on reactivation
|
- Fixes automaton not active on reactivation
|
||||||
|
|
||||||
#### 1.0.6
|
#### 1.0.6
|
||||||
- Fixes reactivation not redrawing all cells
|
- Fixes reactivation not redrawing all cells
|
||||||
|
@ -75,15 +75,19 @@ class CellularAutomatonCreator(abc.ABC):
|
|||||||
|
|
||||||
|
|
||||||
class CellularAutomaton(CellularAutomatonCreator, abc.ABC):
|
class CellularAutomaton(CellularAutomatonCreator, abc.ABC):
|
||||||
"""
|
""" This class represents a cellular automaton.
|
||||||
This class represents a cellular automaton.
|
|
||||||
It can be created with n dimensions and can handle different neighborhood definitions.
|
It can be created with n dimensions and can handle different neighborhood definitions.
|
||||||
|
|
||||||
:param dimension: Iterable of len = dimensions
|
It is intended to be uses as base class.
|
||||||
(e.g. [4, 3, 3, 3] = 4 x 3 x 3 x 3 cells in a four dimensional cube).
|
Override `init_cell_state()` to define the state the cell(s) are initiated with.
|
||||||
:param neighborhood: Defines which cells are considered neighbors.
|
Override `evolve()` to define the rule that is aplied on every evolution step of this automaton.
|
||||||
"""
|
"""
|
||||||
def __init__(self, neighborhood: Neighborhood, *args, **kwargs):
|
def __init__(self, neighborhood: Neighborhood, *args, **kwargs):
|
||||||
|
""" Initiates a cellular automaton by the use of the `init_cell_state` method.
|
||||||
|
:param neighborhood: Defines which cells are considered neighbors.
|
||||||
|
:param dimension: Iterable of len = dimensions
|
||||||
|
(e.g. [4, 3, 3, 3] = 4 x 3 x 3 x 3 cells in a four dimensional cube).
|
||||||
|
"""
|
||||||
super().__init__(neighborhood=neighborhood, *args, **kwargs)
|
super().__init__(neighborhood=neighborhood, *args, **kwargs)
|
||||||
self._evolution_step = 0
|
self._evolution_step = 0
|
||||||
self._active = True
|
self._active = True
|
||||||
@ -132,7 +136,7 @@ class CellularAutomaton(CellularAutomatonCreator, abc.ABC):
|
|||||||
evolution_rule = self.evolve_rule
|
evolution_rule = self.evolve_rule
|
||||||
for old, new in zip(this_state.values(), next_state.values()):
|
for old, new in zip(this_state.values(), next_state.values()):
|
||||||
if old.is_active:
|
if old.is_active:
|
||||||
new_state = evolution_rule(old.state, [n.state for n in old.neighbors])
|
new_state = evolution_rule(old.state.copy(), [n.state for n in old.neighbors])
|
||||||
old.is_active = False
|
old.is_active = False
|
||||||
evolve_cell(old, new, new_state)
|
evolve_cell(old, new, new_state)
|
||||||
|
|
||||||
|
@ -117,7 +117,8 @@ class CAWindow:
|
|||||||
time.sleep(rest_time)
|
time.sleep(rest_time)
|
||||||
|
|
||||||
def _not_at_the_end(self, last_evolution_step):
|
def _not_at_the_end(self, last_evolution_step):
|
||||||
return self._cellular_automaton.evolution_step < last_evolution_step or last_evolution_step <= 0
|
return (self._cellular_automaton.evolution_step < last_evolution_step or last_evolution_step <= 0) \
|
||||||
|
and self._cellular_automaton.active
|
||||||
|
|
||||||
def __calculate_cell_display_size(self, stretch_cells): # pragma: no cover
|
def __calculate_cell_display_size(self, stretch_cells): # pragma: no cover
|
||||||
grid_dimension = self._cellular_automaton.dimension
|
grid_dimension = self._cellular_automaton.dimension
|
||||||
|
@ -83,7 +83,7 @@ class Neighborhood:
|
|||||||
yield tuple(map(operator.add, rel_n, cell_coordinate))
|
yield tuple(map(operator.add, rel_n, cell_coordinate))
|
||||||
|
|
||||||
def __is_coordinate_on_an_edge(self, coordinate):
|
def __is_coordinate_on_an_edge(self, coordinate):
|
||||||
return any(ci in [0, di-1] for ci, di in zip(coordinate, self._grid_dimensions))
|
return any(not(self._radius-1 < ci < di-self._radius) for ci, di in zip(coordinate, self._grid_dimensions))
|
||||||
|
|
||||||
|
|
||||||
class MooreNeighborhood(Neighborhood):
|
class MooreNeighborhood(Neighborhood):
|
||||||
@ -154,7 +154,6 @@ class RadialNeighborhood(Neighborhood):
|
|||||||
cross_sum = 0
|
cross_sum = 0
|
||||||
for coordinate_i in rel_neighbor:
|
for coordinate_i in rel_neighbor:
|
||||||
cross_sum += pow(coordinate_i, 2)
|
cross_sum += pow(coordinate_i, 2)
|
||||||
|
|
||||||
return math.sqrt(cross_sum) <= self._radius + self.delta
|
return math.sqrt(cross_sum) <= self._radius + self.delta
|
||||||
|
|
||||||
|
|
||||||
|
@ -59,5 +59,7 @@ def profile(code):
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
with contextlib.suppress(KeyboardInterrupt):
|
with contextlib.suppress(KeyboardInterrupt):
|
||||||
|
print("=== CREATION ===")
|
||||||
profile('ca = StarFallAutomaton()')
|
profile('ca = StarFallAutomaton()')
|
||||||
|
print("=== COMPUTATION ===")
|
||||||
profile('ca.evolve(times=10)')
|
profile('ca.evolve(times=10)')
|
||||||
|
2
setup.py
2
setup.py
@ -7,7 +7,7 @@ with open('README.md') as f:
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="cellular_automaton",
|
name="cellular_automaton",
|
||||||
version="1.0.7",
|
version="1.0.8",
|
||||||
author="Richard Feistenauer",
|
author="Richard Feistenauer",
|
||||||
author_email="r.feistenauer@web.de",
|
author_email="r.feistenauer@web.de",
|
||||||
packages=find_packages(exclude=('tests', 'docs', 'examples')),
|
packages=find_packages(exclude=('tests', 'docs', 'examples')),
|
||||||
|
@ -52,7 +52,10 @@ class TAutomaton(ca.CellularAutomaton):
|
|||||||
return [1] if cell_coordinate == (1, 1) else [0]
|
return [1] if cell_coordinate == (1, 1) else [0]
|
||||||
|
|
||||||
def evolve_rule(self, last_cell_state, neighbors_last_states):
|
def evolve_rule(self, last_cell_state, neighbors_last_states):
|
||||||
return [last_cell_state[0] + 1] if neighbors_last_states else last_cell_state
|
ns = last_cell_state[:]
|
||||||
|
if 0 < last_cell_state[0] < 40:
|
||||||
|
ns[0] += 1
|
||||||
|
return ns
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -70,3 +73,12 @@ def test_evolution_steps_per_draw(automaton, pygame_mock):
|
|||||||
def test_updated_rectangle_calls(automaton, pygame_mock):
|
def test_updated_rectangle_calls(automaton, pygame_mock):
|
||||||
ca.CAWindow(cellular_automaton=automaton, window_size=(10, 10)).run(last_evolution_step=4)
|
ca.CAWindow(cellular_automaton=automaton, window_size=(10, 10)).run(last_evolution_step=4)
|
||||||
assert pygame_mock.display.update.call_count == 4 * (3 + 1) # steps * (texts + changed cells)
|
assert pygame_mock.display.update.call_count == 4 * (3 + 1) # steps * (texts + changed cells)
|
||||||
|
|
||||||
|
@import_mock(module='pygame')
|
||||||
|
def test_ends_when_ca_is_done(automaton, pygame_mock):
|
||||||
|
automaton.evolve(39)
|
||||||
|
assert automaton.active == True
|
||||||
|
assert automaton.evolution_step == 39
|
||||||
|
ca.CAWindow(cellular_automaton=automaton, window_size=(10, 10)).run(last_evolution_step=45)
|
||||||
|
assert automaton.active == False
|
||||||
|
assert automaton.evolution_step == 40
|
||||||
|
@ -93,6 +93,26 @@ def test_radial():
|
|||||||
(1, 4), (2, 4), (3, 4))
|
(1, 4), (2, 4), (3, 4))
|
||||||
|
|
||||||
|
|
||||||
|
def test_radial_neighbor_coords():
|
||||||
|
neighborhood = ca.RadialNeighborhood(edge_rule=ca.EdgeRule.FIRST_AND_LAST_CELL_OF_DIMENSION_ARE_NEIGHBORS, radius=2)
|
||||||
|
neighbor_coords = neighborhood.calculate_cell_neighbor_coordinates((0, 0), (10, 10))
|
||||||
|
assert neighbor_coords == ((9, 8), (0, 8), (1, 8),
|
||||||
|
(8, 9), (9, 9), (0, 9), (1, 9), (2, 9),
|
||||||
|
(8, 0), (9, 0), (1, 0), (2, 0),
|
||||||
|
(8, 1), (9, 1), (0, 1), (1, 1), (2, 1),
|
||||||
|
(9, 2), (0, 2), (1, 2))
|
||||||
|
|
||||||
|
|
||||||
|
def test_radial_neighbor_coords():
|
||||||
|
neighborhood = ca.RadialNeighborhood(edge_rule=ca.EdgeRule.FIRST_AND_LAST_CELL_OF_DIMENSION_ARE_NEIGHBORS, radius=2)
|
||||||
|
neighbor_coords = neighborhood.calculate_cell_neighbor_coordinates((1, 1), (10, 10))
|
||||||
|
assert neighbor_coords == ((0, 9), (1, 9), (2, 9),
|
||||||
|
(9, 0), (0, 0), (1, 0), (2, 0), (3, 0),
|
||||||
|
(9, 1), (0, 1), (2, 1), (3, 1),
|
||||||
|
(9, 2), (0, 2), (1, 2), (2, 2), (3, 2),
|
||||||
|
(0, 3), (1, 3), (2, 3))
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(('coordinate', 'expected_neighborhood'),
|
@pytest.mark.parametrize(('coordinate', 'expected_neighborhood'),
|
||||||
(((2, 2), ((1, 0), (2, 0), (3, 0),
|
(((2, 2), ((1, 0), (2, 0), (3, 0),
|
||||||
(0, 1), (1, 1), (2, 1), (3, 1),
|
(0, 1), (1, 1), (2, 1), (3, 1),
|
||||||
|
Loading…
Reference in New Issue
Block a user