redraw speedup though use of generator

This commit is contained in:
Richard Feistenauer 2019-01-05 17:38:21 +01:00
parent 68ac036203
commit f26a74d224
4 changed files with 72 additions and 65 deletions

View File

@ -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()

View File

@ -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))

View File

@ -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,9 +70,9 @@ 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,
neighbours_coordinates = neighborhood.calculate_cell_neighbor_coordinates(cell.coordinate,
self._dimension)
cell.neighbours = list(map(self._get_cell_by_coordinate, neighbours_coordinates))

View File

@ -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)