2018-12-09 10:20:16 +00:00
|
|
|
import pygame
|
|
|
|
import time
|
|
|
|
import operator
|
|
|
|
|
2019-02-03 16:17:57 +00:00
|
|
|
import cProfile
|
|
|
|
import pstats
|
|
|
|
from pympler import asizeof
|
|
|
|
|
|
|
|
|
2019-01-06 10:21:46 +00:00
|
|
|
from cellular_automaton.cellular_automaton import CellularAutomaton, CellularAutomatonProcessor
|
2018-12-09 10:20:16 +00:00
|
|
|
|
|
|
|
|
2019-01-05 16:38:21 +00:00
|
|
|
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
|
2018-12-09 10:20:16 +00:00
|
|
|
self.screen = screen
|
|
|
|
|
|
|
|
|
2019-01-05 16:38:21 +00:00
|
|
|
class DisplayFor2D:
|
|
|
|
def __init__(self, grid_rect: list, cellular_automaton: CellularAutomaton, screen):
|
|
|
|
self._cellular_automaton = cellular_automaton
|
|
|
|
cell_size = self._calculate_cell_display_size(grid_rect[-2:])
|
|
|
|
self._display_info = _DisplayInfo(grid_rect[-2:], grid_rect[:2], cell_size, screen)
|
2018-12-09 10:20:16 +00:00
|
|
|
|
2019-02-03 16:17:57 +00:00
|
|
|
def redraw_cellular_automaton(self):
|
|
|
|
pygame.display.update(list(_cell_redraw_rectangles(self._cellular_automaton.cells,
|
|
|
|
0,
|
2019-01-05 16:38:21 +00:00
|
|
|
self._display_info)))
|
2018-12-09 10:20:16 +00:00
|
|
|
|
2019-01-05 16:38:21 +00:00
|
|
|
def _calculate_cell_display_size(self, grid_size):
|
2019-02-03 16:17:57 +00:00
|
|
|
grid_dimension = self._cellular_automaton.dimension
|
2019-01-05 16:38:21 +00:00
|
|
|
return list(map(operator.truediv, grid_size, grid_dimension))
|
2018-12-09 10:20:16 +00:00
|
|
|
|
|
|
|
|
|
|
|
class PyGameFor2D:
|
2019-01-06 10:21:46 +00:00
|
|
|
def __init__(self, window_size: list, cellular_automaton: CellularAutomaton):
|
|
|
|
self._window_size = window_size
|
2018-12-09 10:20:16 +00:00
|
|
|
self._cellular_automaton = cellular_automaton
|
|
|
|
pygame.init()
|
|
|
|
pygame.display.set_caption("Cellular Automaton")
|
2019-01-05 14:12:07 +00:00
|
|
|
self._screen = pygame.display.set_mode(self._window_size)
|
|
|
|
self._font = pygame.font.SysFont("monospace", 15)
|
2018-12-09 10:20:16 +00:00
|
|
|
|
2019-01-06 10:21:46 +00:00
|
|
|
self.ca_display = DisplayFor2D([0, 30, window_size[0], window_size[1] - 30], cellular_automaton, self._screen)
|
2018-12-09 10:20:16 +00:00
|
|
|
|
|
|
|
def _print_process_duration(self, time_ca_end, time_ca_start, time_ds_end):
|
2019-01-05 14:12:07 +00:00
|
|
|
self._screen.fill([0, 0, 0], ((0, 0), (self._window_size[0], 30)))
|
2018-12-09 10:20:16 +00:00
|
|
|
self._write_text((10, 5), "CA: " + "{0:.4f}".format(time_ca_end - time_ca_start) + "s")
|
|
|
|
self._write_text((310, 5), "Display: " + "{0:.4f}".format(time_ds_end - time_ca_end) + "s")
|
|
|
|
|
|
|
|
def _write_text(self, pos, text, color=(0, 255, 0)):
|
2019-01-05 14:12:07 +00:00
|
|
|
label = self._font.render(text, 1, color)
|
|
|
|
update_rect = self._screen.blit(label, pos)
|
2018-12-09 10:20:16 +00:00
|
|
|
pygame.display.update(update_rect)
|
|
|
|
|
2019-01-06 10:21:46 +00:00
|
|
|
def main_loop(self, cellular_automaton_processor: CellularAutomatonProcessor, ca_iterations_per_draw):
|
2018-12-09 10:20:16 +00:00
|
|
|
running = True
|
2019-02-03 16:17:57 +00:00
|
|
|
cellular_automaton_processor.evolve()
|
|
|
|
first = True
|
2019-02-09 17:16:19 +00:00
|
|
|
|
2018-12-09 10:20:16 +00:00
|
|
|
while running:
|
2019-02-03 16:17:57 +00:00
|
|
|
pygame.event.get()
|
2018-12-09 10:20:16 +00:00
|
|
|
time_ca_start = time.time()
|
2019-02-03 16:17:57 +00:00
|
|
|
if first:
|
2019-02-09 17:16:19 +00:00
|
|
|
self._evolve_with_performance(cellular_automaton_processor)
|
2019-02-03 16:17:57 +00:00
|
|
|
first = False
|
|
|
|
else:
|
2019-02-10 10:00:57 +00:00
|
|
|
cellular_automaton_processor.evolve_x_times(ca_iterations_per_draw)
|
2018-12-09 10:20:16 +00:00
|
|
|
time_ca_end = time.time()
|
2019-02-03 16:17:57 +00:00
|
|
|
self.ca_display.redraw_cellular_automaton()
|
2018-12-09 10:20:16 +00:00
|
|
|
time_ds_end = time.time()
|
|
|
|
self._print_process_duration(time_ca_end, time_ca_start, time_ds_end)
|
|
|
|
|
2019-02-09 17:16:19 +00:00
|
|
|
def _evolve_with_performance(self, cap):
|
2019-02-03 16:17:57 +00:00
|
|
|
size = asizeof.asizeof(self._cellular_automaton)
|
2019-02-09 17:16:19 +00:00
|
|
|
time_ca_start = time.time()
|
2019-02-03 16:17:57 +00:00
|
|
|
cProfile.runctx("cap.evolve_x_times(10)", None, locals(), "performance_test")
|
2019-02-09 17:16:19 +00:00
|
|
|
time_ca_end = time.time()
|
2019-02-03 16:17:57 +00:00
|
|
|
print("PERFORMANCE")
|
2019-02-03 17:26:31 +00:00
|
|
|
p = pstats.Stats('performance_test')
|
2019-02-03 16:17:57 +00:00
|
|
|
p.strip_dirs()
|
|
|
|
# sort by cumulative time in a function
|
|
|
|
p.sort_stats('cumulative').print_stats(10)
|
|
|
|
# sort by time spent in a function
|
|
|
|
p.sort_stats('time').print_stats(10)
|
|
|
|
print("TOTAL TIME: " + "{0:.4f}".format(time_ca_end - time_ca_start) + "s")
|
|
|
|
print("SIZE: " + "{0:.4f}".format(size / (1024 * 1024)) + "MB")
|
2018-12-09 10:20:16 +00:00
|
|
|
|
2019-01-05 16:38:21 +00:00
|
|
|
|
|
|
|
def _cell_redraw_rectangles(cells, evolution_index, display_info):
|
|
|
|
for cell in cells:
|
2019-02-09 18:06:18 +00:00
|
|
|
if cell.state.is_set_for_redraw():
|
|
|
|
cell_color = cell.state.get_state_draw_color(evolution_index)
|
2019-01-05 16:38:21 +00:00
|
|
|
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))
|
2019-02-09 18:06:18 +00:00
|
|
|
cell.state.was_redrawn()
|
2019-01-05 16:38:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
def _calculate_cell_position(cell_size, cell):
|
2019-02-09 18:06:18 +00:00
|
|
|
return list(map(operator.mul, cell_size, cell.coordinate))
|