fixed tests and refactored cellstate
This commit is contained in:
parent
823fdbc307
commit
b0a8fb05a4
@ -14,4 +14,7 @@ TOTAL TIME: 0.1792s # probably wrong calculated (asizeof was in there)
|
||||
SIZE: 20.2575MB # Factory instead of grid
|
||||
|
||||
TOTAL TIME: 0.1152s # dict instead of list for cells
|
||||
SIZE: 20.2575MB # process size 53 / 75,8
|
||||
SIZE: 20.2575MB # process size 53 / 75,8
|
||||
|
||||
TOTAL TIME: 0.1135s # evolve is static
|
||||
SIZE: 20.2575MB # process size 50.8 / 76 (no more cell objects in processes)
|
@ -48,7 +48,7 @@ if __name__ == "__main__":
|
||||
freeze_support()
|
||||
|
||||
random.seed(1000)
|
||||
# best is 400/400 with 0,2 ca speed and 0,09 redraw
|
||||
# best single is 400/400 with 0,2 ca speed and 0,09 redraw / multi is 300/300 with 0.083
|
||||
neighborhood = MooreNeighborhood(EdgeRule.FIRST_AND_LAST_CELL_OF_DIMENSION_ARE_NEIGHBORS)
|
||||
ca = make_cellular_automaton(dimension=[100, 100], neighborhood=neighborhood, rule=TestRule(), state_class=MyState)
|
||||
ca_window = PyGameFor2D(window_size=[1000, 800], cellular_automaton=ca)
|
||||
|
Binary file not shown.
@ -4,33 +4,21 @@ from typing import Type
|
||||
|
||||
class Cell:
|
||||
def __init__(self, state_class: Type[CellState], coordinate):
|
||||
self._coordinate = coordinate
|
||||
self.coordinate = coordinate
|
||||
self.state = state_class()
|
||||
self.neighbours = []
|
||||
|
||||
def set_neighbours(self, neighbours):
|
||||
self.neighbours = neighbours
|
||||
@staticmethod
|
||||
def evolve_if_ready(cell, rule, iteration):
|
||||
if cell[0].is_active(iteration):
|
||||
new_state = rule(cell[0].get_state_of_last_iteration(iteration),
|
||||
[n.get_state_of_last_iteration(iteration) for n in cell[1]])
|
||||
Cell.set_new_state_and_activate(cell, new_state, iteration)
|
||||
|
||||
def get_state(self):
|
||||
return self.state
|
||||
|
||||
def get_coordinate(self):
|
||||
return self._coordinate
|
||||
|
||||
def evolve_if_ready(self, rule, iteration):
|
||||
if self.state.is_active(iteration):
|
||||
new_state = rule(self.state.get_state_of_last_iteration(iteration), self.get_neighbour_states(iteration))
|
||||
self.set_new_state_and_activate(new_state, iteration)
|
||||
|
||||
def get_neighbour_states(self, index):
|
||||
return [n.get_state_of_last_iteration(index) for n in self.neighbours]
|
||||
|
||||
def set_new_state_and_activate(self, new_state: CellState, iteration):
|
||||
changed = self.state.set_state_of_iteration(new_state, iteration)
|
||||
@staticmethod
|
||||
def set_new_state_and_activate(cell, new_state: CellState, iteration):
|
||||
changed = cell[0].set_state_of_iteration(new_state, iteration)
|
||||
if changed:
|
||||
self._set_active_for_next_iteration(iteration)
|
||||
|
||||
def _set_active_for_next_iteration(self, iteration):
|
||||
self.state.set_active_for_next_iteration(iteration)
|
||||
for n in self.neighbours:
|
||||
n.set_active_for_next_iteration(iteration)
|
||||
cell[0].set_active_for_next_iteration(iteration)
|
||||
for n in cell[1]:
|
||||
n.set_active_for_next_iteration(iteration)
|
||||
|
@ -17,16 +17,6 @@ class CellState:
|
||||
else:
|
||||
self._dirty = RawValue(c_bool, False)
|
||||
|
||||
def get_state_of_iteration(self, iteration):
|
||||
""" Will return the state for the iteration modulo number of saved states.
|
||||
:param iteration: Uses the iteration index, to differ between concurrent states.
|
||||
:return The state for this iteration.
|
||||
"""
|
||||
return self._state_slots[self.__calculate_slot(iteration)]
|
||||
|
||||
def __calculate_slot(self, iteration):
|
||||
return iteration % self.__class__._state_save_slot_count
|
||||
|
||||
def is_active(self, iteration):
|
||||
return self._active[self.__calculate_slot(iteration)]
|
||||
|
||||
@ -42,6 +32,13 @@ class CellState:
|
||||
def get_state_of_last_iteration(self, current_iteration_index):
|
||||
return self.get_state_of_iteration(current_iteration_index - 1)
|
||||
|
||||
def get_state_of_iteration(self, iteration):
|
||||
""" Will return the state for the iteration modulo number of saved states.
|
||||
:param iteration: Uses the iteration index, to differ between concurrent states.
|
||||
:return The state for this iteration.
|
||||
"""
|
||||
return self._state_slots[self.__calculate_slot(iteration)]
|
||||
|
||||
def set_state_of_iteration(self, new_state, iteration):
|
||||
""" Will set the new state for the iteration modulo number of saved states.
|
||||
:param new_state: The new state to set.
|
||||
@ -66,3 +63,7 @@ class CellState:
|
||||
|
||||
def get_state_draw_color(self, iteration):
|
||||
raise NotImplementedError
|
||||
|
||||
@classmethod
|
||||
def __calculate_slot(cls, iteration):
|
||||
return iteration % cls._state_save_slot_count
|
||||
|
@ -92,13 +92,13 @@ class PyGameFor2D:
|
||||
|
||||
def _cell_redraw_rectangles(cells, evolution_index, display_info):
|
||||
for cell in cells:
|
||||
if cell.get_state().is_set_for_redraw():
|
||||
cell_color = cell.get_state().get_state_draw_color(evolution_index)
|
||||
if cell.state.is_set_for_redraw():
|
||||
cell_color = cell.state.get_state_draw_color(evolution_index)
|
||||
cell_pos = _calculate_cell_position(display_info.cell_size, cell)
|
||||
surface_pos = list(map(operator.add, cell_pos, display_info.grid_pos))
|
||||
yield display_info.screen.fill(cell_color, (surface_pos, display_info.cell_size))
|
||||
cell.get_state().was_redrawn()
|
||||
cell.state.was_redrawn()
|
||||
|
||||
|
||||
def _calculate_cell_position(cell_size, cell):
|
||||
return list(map(operator.mul, cell_size, cell.get_coordinate()))
|
||||
return list(map(operator.mul, cell_size, cell.coordinate))
|
||||
|
@ -25,9 +25,9 @@ class CAFactory:
|
||||
@staticmethod
|
||||
def _apply_neighbourhood_to_cells(cells, neighborhood, dimension):
|
||||
for cell in cells.values():
|
||||
n_coordinates = neighborhood.calculate_cell_neighbor_coordinates(cell.get_coordinate(),
|
||||
n_coordinates = neighborhood.calculate_cell_neighbor_coordinates(cell.coordinate,
|
||||
dimension)
|
||||
cell.set_neighbours([cells[_join_coordinate(coordinate)].get_state() for coordinate in n_coordinates])
|
||||
cell.neighbours = [cells[_join_coordinate(coordinate)].state for coordinate in n_coordinates]
|
||||
|
||||
|
||||
def _join_coordinate(coordinate):
|
||||
|
@ -1,6 +1,7 @@
|
||||
import multiprocessing
|
||||
|
||||
from cellular_automaton.ca_rule import Rule
|
||||
from cellular_automaton.ca_cell import Cell
|
||||
|
||||
|
||||
class CellularAutomaton:
|
||||
@ -14,7 +15,7 @@ class CellularAutomaton:
|
||||
class CellularAutomatonProcessor:
|
||||
def __init__(self, cellular_automaton, process_count: int = 1):
|
||||
self.ca = cellular_automaton
|
||||
cells = {i: self.ca.cells[i] for i in range(len(self.ca.cells))}
|
||||
cells = {i: (c.state, c.neighbours) for i, c in enumerate(self.ca.cells)}
|
||||
self.evolve_range = range(len(self.ca.cells))
|
||||
self.pool = multiprocessing.Pool(processes=process_count,
|
||||
initializer=_init_process,
|
||||
@ -22,7 +23,7 @@ class CellularAutomatonProcessor:
|
||||
self.ca.evolution_rule,
|
||||
self.ca.evolution_iteration_index))
|
||||
for cell in self.ca.cells:
|
||||
cell.set_neighbours(None)
|
||||
del cell.neighbours
|
||||
|
||||
def evolve_x_times(self, x):
|
||||
for x in range(x):
|
||||
@ -46,5 +47,5 @@ def _init_process(cells, rule, index):
|
||||
|
||||
|
||||
def _process_routine(i):
|
||||
global_cells[i].evolve_if_ready(global_rule.evolve_cell, global_iteration.value)
|
||||
Cell.evolve_if_ready(global_cells[i], global_rule.evolve_cell, global_iteration.value)
|
||||
|
||||
|
@ -1,26 +1,25 @@
|
||||
import sys
|
||||
sys.path.append('../src')
|
||||
|
||||
import cellular_automaton.ca_cell_state as cas
|
||||
import cellular_automaton.ca_cell as cac
|
||||
from cellular_automaton import *
|
||||
import unittest
|
||||
|
||||
|
||||
class TestState(cas.CellState):
|
||||
class TestState(CellState):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
|
||||
class TestCellState(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.cell = cac.Cell(TestState, [])
|
||||
self.cell = [TestState(), []]
|
||||
self.neighbours = [TestState() for x in range(5)]
|
||||
for neighbour in self.neighbours:
|
||||
neighbour.set_state_of_iteration((0, ), 0)
|
||||
self.cell.set_neighbours(self.neighbours)
|
||||
self.cell[1] = self.neighbours
|
||||
|
||||
def cell_and_neighbours_active(self, iteration):
|
||||
self.neighbours.append(self.cell.get_state())
|
||||
self.neighbours.append(self.cell[0])
|
||||
all_active = True
|
||||
for state in self.neighbours:
|
||||
if not state.is_active(iteration):
|
||||
@ -28,12 +27,12 @@ class TestCellState(unittest.TestCase):
|
||||
return all_active
|
||||
|
||||
def test_evolve_activation(self):
|
||||
self.cell.evolve_if_ready((lambda a, b: (1,)), 0)
|
||||
Cell.evolve_if_ready(self.cell, (lambda a, b: (1,)), 0)
|
||||
all_active = self.cell_and_neighbours_active(1)
|
||||
self.assertTrue(all_active)
|
||||
|
||||
def test_evolve_activation_on_no_change(self):
|
||||
self.cell.evolve_if_ready((lambda a, b: (0,)), 0)
|
||||
Cell.evolve_if_ready(self.cell, (lambda a, b: (0,)), 0)
|
||||
all_active = self.cell_and_neighbours_active(1)
|
||||
self.assertFalse(all_active)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user