redraw speedup though use of generator
This commit is contained in:
parent
68ac036203
commit
f26a74d224
@ -2,11 +2,12 @@
|
||||
|
||||
import random
|
||||
|
||||
from cellular_automaton.cellular_automaton import CellularAutomaton
|
||||
from cellular_automaton.cellular_automaton import CellularAutomaton, CellularAutomatonEvolver
|
||||
from cellular_automaton.ca_rule import Rule
|
||||
from cellular_automaton.ca_neighborhood import MooreNeighborhood, EdgeRule
|
||||
from cellular_automaton.ca_display import PyGameFor2D
|
||||
from cellular_automaton.ca_cell_state import CellState
|
||||
from cellular_automaton.ca_grid import Grid
|
||||
|
||||
|
||||
class TestRule(Rule):
|
||||
@ -43,6 +44,8 @@ class MyStatus(CellState):
|
||||
if __name__ == "__main__":
|
||||
random.seed(1000)
|
||||
rule = TestRule()
|
||||
ca = CellularAutomaton([400, 400], MooreNeighborhood(EdgeRule.FIRST_AND_LAST_CELL_OF_DIMENSION_ARE_NEIGHBORS), rule)
|
||||
ca_window = PyGameFor2D([1000, 800], ca, 5)
|
||||
ca = CellularAutomaton(Grid([400, 400], MooreNeighborhood(EdgeRule.FIRST_AND_LAST_CELL_OF_DIMENSION_ARE_NEIGHBORS)),
|
||||
rule)
|
||||
ca_evolver = CellularAutomatonEvolver(2)
|
||||
ca_window = PyGameFor2D([1000, 800], ca, ca_evolver, 5)
|
||||
ca_window.main_loop()
|
||||
|
@ -2,49 +2,45 @@ import pygame
|
||||
import time
|
||||
import operator
|
||||
|
||||
from cellular_automaton.cellular_automaton import CellularAutomaton
|
||||
from cellular_automaton.cellular_automaton import CellularAutomaton, CellularAutomatonEvolver
|
||||
|
||||
|
||||
class _DisplayInfo:
|
||||
def __init__(self, grid_size, grid_pos, cell_size, screen):
|
||||
self.grid_size = grid_size
|
||||
self.grid_pos = grid_pos
|
||||
self.cell_size = cell_size
|
||||
self.screen = screen
|
||||
|
||||
|
||||
class DisplayFor2D:
|
||||
def __init__(self, grid_rect: list, cellular_automaton: CellularAutomaton, screen):
|
||||
self.grid_size = grid_rect[-2:]
|
||||
self.grid_pos = grid_rect[:2]
|
||||
self._cellular_automaton = cellular_automaton
|
||||
self.screen = screen
|
||||
|
||||
self.cell_size = self._calculate_cell_display_size()
|
||||
|
||||
self._surfaces_to_update = []
|
||||
cell_size = self._calculate_cell_display_size(grid_rect[-2:])
|
||||
self._display_info = _DisplayInfo(grid_rect[-2:], grid_rect[:2], cell_size, screen)
|
||||
|
||||
def set_cellular_automaton(self, cellular_automaton):
|
||||
self._cellular_automaton = cellular_automaton
|
||||
|
||||
def _redraw_cellular_automaton(self):
|
||||
for cell in self._cellular_automaton.grid.get_cells().values():
|
||||
self._redraw_cell(cell)
|
||||
pygame.display.update(self._surfaces_to_update)
|
||||
self._surfaces_to_update = []
|
||||
pygame.display.update(list(_cell_redraw_rectangles(self._cellular_automaton.grid.get_cells().values(),
|
||||
self._cellular_automaton.evolution_iteration_index,
|
||||
self._display_info)))
|
||||
|
||||
def _redraw_cell(self, cell):
|
||||
if cell.is_set_for_redraw:
|
||||
cell_color = cell.state.get_state_draw_color(self._cellular_automaton.get_iteration_index())
|
||||
surface_pos = self._calculate_cell_position(cell)
|
||||
surface_pos = list(map(operator.add, surface_pos, self.grid_pos))
|
||||
self._surfaces_to_update.append(self.screen.fill(cell_color, (surface_pos, self.cell_size)))
|
||||
cell.is_set_for_redraw = False
|
||||
|
||||
def _calculate_cell_position(self, cell):
|
||||
return list(map(operator.mul, self.cell_size, cell.coordinate))
|
||||
|
||||
def _calculate_cell_display_size(self):
|
||||
def _calculate_cell_display_size(self, grid_size):
|
||||
grid_dimension = self._cellular_automaton.grid.get_dimension()
|
||||
return list(map(operator.truediv, self.grid_size, grid_dimension))
|
||||
return list(map(operator.truediv, grid_size, grid_dimension))
|
||||
|
||||
|
||||
class PyGameFor2D:
|
||||
def __init__(self, windows_size: list, cellular_automaton: CellularAutomaton, ca_iterations_per_draw):
|
||||
def __init__(self,
|
||||
windows_size: list,
|
||||
cellular_automaton: CellularAutomaton,
|
||||
cellular_automaton_evolver: CellularAutomatonEvolver,
|
||||
ca_iterations_per_draw):
|
||||
self._window_size = windows_size
|
||||
self._cellular_automaton = cellular_automaton
|
||||
self._cellular_automaton_evolver = cellular_automaton_evolver
|
||||
self._ca_steps_per_draw = ca_iterations_per_draw
|
||||
|
||||
pygame.init()
|
||||
@ -69,7 +65,7 @@ class PyGameFor2D:
|
||||
|
||||
while running:
|
||||
time_ca_start = time.time()
|
||||
self._cellular_automaton.evolve_x_times(self._ca_steps_per_draw)
|
||||
self._cellular_automaton_evolver.evolve_x_times(self._cellular_automaton, self._ca_steps_per_draw)
|
||||
time_ca_end = time.time()
|
||||
self.ca_display._redraw_cellular_automaton()
|
||||
time_ds_end = time.time()
|
||||
@ -79,3 +75,16 @@ class PyGameFor2D:
|
||||
if event.type == pygame.QUIT:
|
||||
running = False
|
||||
|
||||
|
||||
def _cell_redraw_rectangles(cells, evolution_index, display_info):
|
||||
for cell in cells:
|
||||
if cell.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.is_set_for_redraw = False
|
||||
|
||||
|
||||
def _calculate_cell_position(cell_size, cell):
|
||||
return list(map(operator.mul, cell_size, cell.coordinate))
|
||||
|
@ -6,11 +6,13 @@ class Grid:
|
||||
def __init__(self, dimension: list, neighborhood: Neighborhood):
|
||||
self._dimension = dimension
|
||||
self._cells = {}
|
||||
self._neighborhood = neighborhood
|
||||
self._active_cells = {}
|
||||
|
||||
self._init_cells(neighborhood)
|
||||
|
||||
def _init_cells(self, neighborhood):
|
||||
self._create_cells()
|
||||
self._set_cell_neighbours()
|
||||
|
||||
self._set_cell_neighbours(neighborhood)
|
||||
self._active_cells = self._cells.copy()
|
||||
self._set_all_cells_active()
|
||||
|
||||
@ -68,10 +70,10 @@ class Grid:
|
||||
new_cod = coordinate + [cell_index]
|
||||
recursion_method(dimension_index + 1, new_cod)
|
||||
|
||||
def _set_cell_neighbours(self):
|
||||
def _set_cell_neighbours(self, neighborhood):
|
||||
for cell in self._cells.values():
|
||||
neighbours_coordinates = self._neighborhood.calculate_cell_neighbor_coordinates(cell.coordinate,
|
||||
self._dimension)
|
||||
neighbours_coordinates = neighborhood.calculate_cell_neighbor_coordinates(cell.coordinate,
|
||||
self._dimension)
|
||||
cell.neighbours = list(map(self._get_cell_by_coordinate, neighbours_coordinates))
|
||||
|
||||
def _get_cell_by_coordinate(self, coordinate):
|
||||
|
@ -1,61 +1,54 @@
|
||||
from cellular_automaton.ca_grid import Grid
|
||||
from cellular_automaton.ca_rule import Rule
|
||||
from cellular_automaton.ca_neighborhood import Neighborhood
|
||||
|
||||
|
||||
class CellularAutomaton:
|
||||
def __init__(self, dimension: list, neighborhood: Neighborhood, evolution_rule: Rule=None):
|
||||
self.grid = Grid(dimension, neighborhood)
|
||||
def __init__(self, grid: Grid, evolution_rule: Rule):
|
||||
self.grid = grid
|
||||
self.evolution_rule = evolution_rule
|
||||
self.iteration = 0
|
||||
self.test_number = 0
|
||||
self.evolution_iteration_index = 0
|
||||
|
||||
def set_rule(self, rule: Rule):
|
||||
""" Set new evolution rule.
|
||||
:param rule:
|
||||
:return:
|
||||
"""
|
||||
self.evolution_rule = rule
|
||||
|
||||
def get_iteration_index(self):
|
||||
""" Get the count of evolution cycles done.
|
||||
:return: Evolution steps done.
|
||||
"""
|
||||
return self.iteration
|
||||
class CellularAutomatonEvolver:
|
||||
def __init__(self, process_count: int = 1):
|
||||
self.__processes = process_count
|
||||
self.__cellular_automaton = None
|
||||
|
||||
def evolve_x_times(self, evolutions: int):
|
||||
def evolve_x_times(self, cellular_automaton: CellularAutomaton, evolution_steps: int):
|
||||
""" Evolve all cells for x time steps.
|
||||
:param evolutions: the count of evolutions done.
|
||||
:param evolution_steps: the count of evolutions done.
|
||||
:return: True if all cells are inactive
|
||||
"""
|
||||
for evo in range(evolutions):
|
||||
finished = self.evolve()
|
||||
for evo in range(evolution_steps):
|
||||
finished = self.evolve(cellular_automaton)
|
||||
if finished:
|
||||
return True
|
||||
return False
|
||||
|
||||
def evolve(self):
|
||||
def evolve(self, cellular_automaton: CellularAutomaton):
|
||||
""" Evolves all active cells for one time step.
|
||||
:return: True if all cells are inactive.
|
||||
"""
|
||||
self.__cellular_automaton = cellular_automaton
|
||||
if self._is_evolution_finished():
|
||||
return True
|
||||
else:
|
||||
self.iteration += 1
|
||||
cellular_automaton.evolution_iteration_index += 1
|
||||
self._evolve_all_active_cells()
|
||||
return False
|
||||
|
||||
def _is_evolution_finished(self):
|
||||
return len(self.__cellular_automaton.grid.get_active_cell_names()) == 0
|
||||
|
||||
def _evolve_all_active_cells(self):
|
||||
active_cells = self.grid.get_active_cells()
|
||||
self.grid.clear_active_cells()
|
||||
active_cells = self.__cellular_automaton.grid.get_active_cells()
|
||||
self.__cellular_automaton.grid.clear_active_cells()
|
||||
self._evolve_cells(active_cells.values())
|
||||
|
||||
def _is_evolution_finished(self):
|
||||
return len(self.grid.get_active_cell_names()) == 0
|
||||
|
||||
def _evolve_cells(self, cells: list):
|
||||
cellular_automaton = self.__cellular_automaton
|
||||
for cell in cells:
|
||||
active = self.evolution_rule.evolve_cell(cell, self.iteration)
|
||||
active = cellular_automaton.evolution_rule.evolve_cell(cell, cellular_automaton.evolution_iteration_index)
|
||||
|
||||
if active:
|
||||
self.grid.set_cells_active([cell] + cell.neighbours)
|
||||
cellular_automaton.grid.set_cells_active([cell] + cell.neighbours)
|
||||
|
Loading…
Reference in New Issue
Block a user