diff --git a/scripts/performance_test b/scripts/performance_test index beb9614..693a451 100644 Binary files a/scripts/performance_test and b/scripts/performance_test differ diff --git a/src/cellular_automaton/ca_cell.py b/src/cellular_automaton/ca_cell.py index d463527..a28cfd3 100644 --- a/src/cellular_automaton/ca_cell.py +++ b/src/cellular_automaton/ca_cell.py @@ -3,22 +3,21 @@ from typing import Type class Cell: - def __init__(self, state_class: Type[CellState], coordinate): - self.coordinate = coordinate + def __init__(self, state_class: Type[CellState]): self.state = state_class() self.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]]) + if cell.state.is_active(iteration): + new_state = rule(cell.state.get_state_of_last_iteration(iteration), + [n.get_state_of_last_iteration(iteration) for n in cell.neighbours]) Cell.set_new_state_and_activate(cell, 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) + changed = cell.state.set_state_of_iteration(new_state, iteration) if changed: - cell[0].set_active_for_next_iteration(iteration) - for n in cell[1]: + cell.state.set_active_for_next_iteration(iteration) + for n in cell.neighbours: n.set_active_for_next_iteration(iteration) diff --git a/src/cellular_automaton/ca_display.py b/src/cellular_automaton/ca_display.py index ecd8b21..e832890 100644 --- a/src/cellular_automaton/ca_display.py +++ b/src/cellular_automaton/ca_display.py @@ -29,10 +29,10 @@ class DisplayFor2D: pygame.display.update(update_rects) def _cell_redraw_rectangles(self): - for cell in self._cellular_automaton.cells: + for coordinate, cell in self._cellular_automaton.cells.items(): if cell.state.is_set_for_redraw(): cell_color = cell.state.get_state_draw_color(self._cellular_automaton.evolution_iteration_index) - cell_pos = _calculate_cell_position(self._display_info.cell_size, cell) + cell_pos = _calculate_cell_position(self._display_info.cell_size, coordinate) surface_pos = list(map(operator.add, cell_pos, self._display_info.grid_pos)) yield self._display_info.screen.fill(cell_color, (surface_pos, self._display_info.cell_size)) cell.state.was_redrawn() @@ -97,5 +97,5 @@ class PyGameFor2D: print("SIZE: " + "{0:.4f}".format(size / (1024 * 1024)) + "MB") -def _calculate_cell_position(cell_size, cell): - return list(map(operator.mul, cell_size, cell.coordinate)) +def _calculate_cell_position(cell_size, coordinate): + return list(map(operator.mul, cell_size, coordinate)) diff --git a/src/cellular_automaton/ca_factory.py b/src/cellular_automaton/ca_factory.py index e8a65a1..bd811ed 100644 --- a/src/cellular_automaton/ca_factory.py +++ b/src/cellular_automaton/ca_factory.py @@ -12,23 +12,18 @@ class CAFactory: cells = CAFactory._make_cells(dimension, state_class) CAFactory._apply_neighbourhood_to_cells(cells, neighborhood, dimension) - return tuple(cells.values()) + return cells @staticmethod def _make_cells(dimension, state_class): cells = {} for c in itertools.product(*[range(d) for d in dimension]): - coordinate_string = _join_coordinate(c) - cells[coordinate_string] = Cell(state_class, c) + cells[tuple(c)] = Cell(state_class) return cells @staticmethod def _apply_neighbourhood_to_cells(cells, neighborhood, dimension): - for cell in cells.values(): - n_coordinates = neighborhood.calculate_cell_neighbor_coordinates(cell.coordinate, dimension) - cell.neighbours = [cells[_join_coordinate(coordinate)].state for coordinate in n_coordinates] - - -def _join_coordinate(coordinate): - return '-'.join(str(x) for x in coordinate) + for coordinate, cell in cells.items(): + n_coordinates = neighborhood.calculate_cell_neighbor_coordinates(coordinate, dimension) + cell.neighbours = [cells[tuple(nc)].state for nc in n_coordinates] diff --git a/src/cellular_automaton/cellular_automaton.py b/src/cellular_automaton/cellular_automaton.py index 39c7061..d745eaa 100644 --- a/src/cellular_automaton/cellular_automaton.py +++ b/src/cellular_automaton/cellular_automaton.py @@ -25,7 +25,7 @@ class CellularAutomatonProcessor: self._ca.evolution_iteration_index += 1 i = self._ca.evolution_iteration_index r = self._ca.evolution_rule.evolve_cell - list(map(lambda c: Cell.evolve_if_ready((c.state, c.neighbours), r, i), self._ca.cells)) + list(map(lambda c: Cell.evolve_if_ready((c.state, c.neighbours), r, i), tuple(self._ca.cells.items()))) # print(sum(1 for c in self._ca.cells if c.state.is_set_for_redraw())) @@ -33,25 +33,25 @@ class CellularAutomatonMultiProcessor(CellularAutomatonProcessor): def __init__(self, cellular_automaton, process_count: int = 2): if process_count < 1: raise ValueError + super().__init__(cellular_automaton) - self.ca = cellular_automaton - cells = {i: (c.state, c.neighbours) for i, c in enumerate(self.ca.cells)} - self.evolve_range = range(len(self.ca.cells)) + + self.evolve_range = range(len(self._ca.cells)) self.evolution_iteration_index = multiprocessing.RawValue(c_int, -1) self.pool = multiprocessing.Pool(processes=process_count, initializer=_init_process, - initargs=(cells, - self.ca.evolution_rule, + initargs=(tuple(self._ca.cells.values()), + self._ca.evolution_rule, self.evolution_iteration_index)) self._evolve_method = self.pool.map - for cell in self.ca.cells: + for cell in self._ca.cells.values(): del cell.neighbours def evolve(self): - self.ca.evolution_iteration_index += 1 - self.evolution_iteration_index.value = self.ca.evolution_iteration_index + self._ca.evolution_iteration_index += 1 + self.evolution_iteration_index.value = self._ca.evolution_iteration_index self.pool.map(_process_routine, self.evolve_range) diff --git a/test/test_cell.py b/test/test_cell.py index f10bf40..ee946cb 100644 --- a/test/test_cell.py +++ b/test/test_cell.py @@ -12,14 +12,14 @@ class TestState(CellState): class TestCellState(unittest.TestCase): def setUp(self): - self.cell = [TestState(), []] + self.cell = Cell(TestState) self.neighbours = [TestState() for x in range(5)] for neighbour in self.neighbours: neighbour.set_state_of_iteration((0, ), 0) - self.cell[1] = self.neighbours + self.cell.neighbours = self.neighbours def cell_and_neighbours_active(self, iteration): - self.neighbours.append(self.cell[0]) + self.neighbours.append(self.cell.state) all_active = True for state in self.neighbours: if not state.is_active(iteration): diff --git a/test/test_factory.py b/test/test_factory.py index df5fd8e..231eeca 100644 --- a/test/test_factory.py +++ b/test/test_factory.py @@ -28,31 +28,32 @@ class TestCAFactory(unittest.TestCase): with mock.patch.object(CAFactory, '_make_cells', return_value={1: True}): with mock.patch.object(CAFactory, '_apply_neighbourhood_to_cells'): cells = CAFactory.make_cellular_automaton([10], Neighborhood, CellState) - self.assertEqual(cells, (True, )) + self.assertEqual(tuple(cells.values()), (True, )) def test_1dimension_coordinates(self): fac = TestFac() c = fac.make_cells([3], CellState) - self.assertEqual(list(c.keys()), ['0', '1', '2']) + self.assertEqual(list(c.keys()), [(0,), (1,), (2,)]) def test_2dimension_coordinates(self): fac = TestFac() c = fac.make_cells([2, 2], CellState) - self.assertEqual(list(c.keys()), ['0-0', '0-1', '1-0', '1-1']) + self.assertEqual(list(c.keys()), [(0, 0), (0, 1), (1, 0), (1, 1)]) def test_3dimension_coordinates(self): fac = TestFac() c = fac.make_cells([2, 2, 2], CellState) - self.assertEqual(list(c.keys()), ['0-0-0', '0-0-1', '0-1-0', '0-1-1', '1-0-0', '1-0-1', '1-1-0', '1-1-1']) + self.assertEqual(list(c.keys()), [(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), + (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1)]) def test_apply_neighbourhood(self): fac = TestFac() cells = fac.make_cells([3, 3], CellState) fac.apply_neighbourhood(cells, MooreNeighborhood(EdgeRule.IGNORE_EDGE_CELLS), [3, 3]) - neighbours = self.__create_neighbour_list_of_cell('1-1', cells) + neighbours = self.__create_neighbour_list_of_cell((1, 1), cells) - self.assertEqual(set(neighbours), set(cells['1-1'].neighbours)) + self.assertEqual(set(neighbours), set(cells[(1, 1)].neighbours)) @staticmethod def __create_neighbour_list_of_cell(cell_id, cells):