diff --git a/scripts/main_ui.py b/scripts/main_ui.py index 46505d8..80c85a3 100644 --- a/scripts/main_ui.py +++ b/scripts/main_ui.py @@ -3,6 +3,9 @@ from cellular_automaton.ca_cell_state import CellState from cellular_automaton.ca_rule import Rule +from cellular_automaton.cellular_automaton import CellularAutomaton, CellularAutomatonProcessor +from cellular_automaton.ca_factory import Factory + class TestRule(Rule): @staticmethod @@ -31,23 +34,24 @@ class MyState(CellState): return [red, 0, 0] +def make_cellular_automaton(dimension, neighborhood, rule, state_class): + ca_factory = Factory() + cells = ca_factory.make_cellular_automaton(dimension=dimension, neighborhood=neighborhood, state_class=state_class) + return CellularAutomaton(cells, dimension, rule) + + if __name__ == "__main__": import random from multiprocessing import freeze_support - - from cellular_automaton.cellular_automaton import CellularAutomaton, CellularAutomatonProcessor from cellular_automaton.ca_neighborhood import MooreNeighborhood, EdgeRule from cellular_automaton.ca_display import PyGameFor2D - from cellular_automaton.ca_grid import Grid freeze_support() + random.seed(1000) - dimension = [100, 100] - rule = TestRule() - grid = Grid(dimension=dimension, # best is 400/400 with 0,2 ca speed and 0,09 redraw - neighborhood=MooreNeighborhood(EdgeRule.FIRST_AND_LAST_CELL_OF_DIMENSION_ARE_NEIGHBORS), - state_class=MyState) - ca = CellularAutomaton(tuple(grid.get_cells().values()), dimension, rule) + # best is 400/400 with 0,2 ca speed and 0,09 redraw + 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) ca_processor = CellularAutomatonProcessor(process_count=4, cellular_automaton=ca) ca_window.main_loop(cellular_automaton_processor=ca_processor, diff --git a/src/cellular_automaton/ca_display.py b/src/cellular_automaton/ca_display.py index d1b5df5..77de284 100644 --- a/src/cellular_automaton/ca_display.py +++ b/src/cellular_automaton/ca_display.py @@ -77,7 +77,7 @@ class PyGameFor2D: size = asizeof.asizeof(self._cellular_automaton) cProfile.runctx("cap.evolve_x_times(10)", None, locals(), "performance_test") print("PERFORMANCE") - p = pstats.Stats('performance_test2') + p = pstats.Stats('performance_test') p.strip_dirs() # sort by cumulative time in a function p.sort_stats('cumulative').print_stats(10) diff --git a/src/cellular_automaton/ca_factory.py b/src/cellular_automaton/ca_factory.py new file mode 100644 index 0000000..cdec237 --- /dev/null +++ b/src/cellular_automaton/ca_factory.py @@ -0,0 +1,61 @@ +from cellular_automaton.ca_cell import Cell, CellState +from cellular_automaton.ca_neighborhood import Neighborhood +from typing import Type + + +class Factory: + def __init__(self): + self._dimension = None + self._state_class = None + self._cells = {} + + def make_cellular_automaton(self, + dimension, + neighborhood: Type[Neighborhood], + state_class: Type[CellState]): + self._dimension = dimension + self._state_class = state_class + + self.__create_cells() + self.__set_cell_neighbours(self._cells, neighborhood) + return tuple(self._cells.values()) + + def __create_cells(self, dimension_index=0, coordinate=None): + """ Recursively steps down the dimensions to create cells in n dimensions and adds them to a dict. + :param dimension_index: The index indicating which dimension is currently traversed. + :param coordinate: The coordinate generated so far. + (each recursion adds one dimension to the coordinate. + """ + coordinate = _instantiate_coordinate_if_necessary(coordinate) + + try: + self.__recursive_step_down_dimensions(coordinate, dimension_index) + except IndexError: + coordinate_string = _join_coordinate(coordinate) + self._cells[coordinate_string] = Cell(self._state_class, coordinate) + + def __recursive_step_down_dimensions(self, coordinate, dimension_index): + """ For the range of the current dimension, recalls the recursion method. + :param coordinate: The coordinate so far. + :param dimension_index: The current dimension lvl. + """ + for cell_index in range(self._dimension[dimension_index]): + new_cod = coordinate + [cell_index] + self.__create_cells(dimension_index + 1, new_cod) + + def __set_cell_neighbours(self, cells, neighborhood): + for cell in cells.values(): + n_coordinates = neighborhood.calculate_cell_neighbor_coordinates(cell.get_coordinate(), + self._dimension) + cell.set_neighbours([cells[_join_coordinate(coordinate)].get_state() for coordinate in n_coordinates]) + + +def _instantiate_coordinate_if_necessary(coordinate): + if coordinate is None: + coordinate = [] + return coordinate + + +def _join_coordinate(coordinate): + return '-'.join(str(x) for x in coordinate) + diff --git a/src/cellular_automaton/ca_grid.py b/src/cellular_automaton/ca_grid.py deleted file mode 100644 index c9781f2..0000000 --- a/src/cellular_automaton/ca_grid.py +++ /dev/null @@ -1,78 +0,0 @@ -from cellular_automaton.ca_cell import Cell -from cellular_automaton.ca_neighborhood import Neighborhood - - -class Grid: - def __init__(self, dimension: list, neighborhood: Neighborhood, state_class): - self._dimension = dimension - self._cells = {} - self._active_cells = {} - self._state_class = state_class - - self._init_cells(neighborhood) - - def _init_cells(self, neighborhood): - self._create_cells() - self._set_cell_neighbours(neighborhood) - self._active_cells = self._cells.copy() - self._set_all_cells_active() - - def _create_cells(self, dimension_index=0, coordinate=None): - """ Recursively steps down the dimensions to create cells in n dimensions and adds them to a dict. - :param dimension_index: The index indicating which dimension is currently traversed. - :param coordinate: The coordinate generated so far. - (each recursion adds one dimension to the coordinate. - """ - coordinate = _instantiate_coordinate_if_necessary(coordinate) - - try: - self._recursive_step_down_dimensions(coordinate, dimension_index, self._create_cells) - except IndexError: - coordinate_string = _join_coordinate(coordinate) - self._cells[coordinate_string] = Cell(self._state_class, coordinate) - - def _recursive_step_down_dimensions(self, coordinate, dimension_index, recursion_method): - """ For the range of the current dimension, recalls the recursion method. - :param coordinate: The coordinate so far. - :param dimension_index: The current dimension lvl. - :param recursion_method: The method to call for recursion. - """ - for cell_index in range(self._dimension[dimension_index]): - new_cod = coordinate + [cell_index] - recursion_method(dimension_index + 1, new_cod) - - def _set_cell_neighbours(self, neighborhood): - for cell in self._cells.values(): - neighbours_coordinates = neighborhood.calculate_cell_neighbor_coordinates(cell.get_coordinate(), - self._dimension) - cell.set_neighbours(list(map(self._get_cell_state_by_coordinate, neighbours_coordinates))) - - def _get_cell_state_by_coordinate(self, coordinate): - return self._cells[_join_coordinate(coordinate)].get_state() - - def _set_all_cells_active(self): - for cell_key, cell in self._cells.items(): - self._active_cells[cell_key] = cell - - def get_active_cell_names(self): - return list(self._active_cells.keys()) - - def get_active_cells(self): - return self._active_cells - - def get_cells(self): - return self._cells - - def get_dimension(self): - return self._dimension - - -def _instantiate_coordinate_if_necessary(coordinate): - if coordinate is None: - coordinate = [] - return coordinate - - -def _join_coordinate(coordinate): - return '-'.join(str(x) for x in coordinate) -