added cell state and display class
This commit is contained in:
parent
0960991e47
commit
1042c2ae34
@ -7,6 +7,8 @@ import time
|
||||
from cellular_automaton.cellular_automaton import CellularAutomaton
|
||||
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
|
||||
|
||||
|
||||
class WorldGeneratorWindow:
|
||||
@ -17,7 +19,7 @@ class WorldGeneratorWindow:
|
||||
|
||||
pygame.init()
|
||||
pygame.display.set_caption("World Generator")
|
||||
self.screen = pygame.display.set_mode(self.grid_size)
|
||||
self.screen = pygame.display.set_mode(self.window_size)
|
||||
|
||||
self._cellular_automaton = cellular_automaton
|
||||
self.font = pygame.font.SysFont("monospace", 15)
|
||||
@ -78,25 +80,35 @@ class TestRule(Rule):
|
||||
def evolve_cell(self, cell, neighbors, iteration_index):
|
||||
active = False
|
||||
last_iteration = iteration_index - 1
|
||||
if cell.get_status_for_iteration(last_iteration) is None:
|
||||
if cell.state is None:
|
||||
rand = random.randrange(0, 101, 1)
|
||||
if rand <= 99:
|
||||
rand = 0
|
||||
cell.set_status_for_iteration([rand], iteration_index)
|
||||
cell.set_status_for_iteration([rand], iteration_index + 1)
|
||||
if rand != 0:
|
||||
active = True
|
||||
cell.state = MyStatus(0)
|
||||
else:
|
||||
cell.state = MyStatus(1)
|
||||
cell.set_for_redraw()
|
||||
active = True
|
||||
elif len(neighbors) == 8:
|
||||
left_neighbour_status = neighbors[3].get_status_for_iteration(last_iteration)
|
||||
active = cell.set_status_for_iteration(left_neighbour_status, iteration_index)
|
||||
left_neighbour_status = neighbors[3].state.get_status_of_iteration(last_iteration)
|
||||
active = cell.state.set_status_of_iteration(left_neighbour_status, iteration_index)
|
||||
if active:
|
||||
cell.set_for_redraw()
|
||||
return active
|
||||
|
||||
|
||||
class MyStatus(CellState):
|
||||
def __init__(self, initial_state):
|
||||
super().__init__(initial_state)
|
||||
|
||||
def get_state_draw_color(self, iteration):
|
||||
red = 0
|
||||
if self._state[iteration % 2][0]:
|
||||
red = 255
|
||||
return [red, 0, 0]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
rule = TestRule()
|
||||
ca = CellularAutomaton([400, 400], MooreNeighborhood(EdgeRule.IGNORE_EDGE_CELLS), rule)
|
||||
ca_window = WorldGeneratorWindow([1000, 730], ca)
|
||||
ca_window = PyGameFor2D([1000, 730], ca)
|
||||
ca_window.main_loop()
|
||||
|
@ -3,7 +3,7 @@ class Cell:
|
||||
self.name = name
|
||||
self.coordinate = coordinate
|
||||
self.neighbours = []
|
||||
self._status = [None, None]
|
||||
self.state = None
|
||||
self._dirty = False
|
||||
|
||||
def set_neighbours(self, neighbours: list):
|
||||
@ -20,20 +20,3 @@ class Cell:
|
||||
|
||||
def release_from_redraw(self):
|
||||
self._dirty = False
|
||||
|
||||
def set_status_of_iteration(self, new_status, iteration):
|
||||
""" Will set the new status for the iteration modulo two.
|
||||
:param new_status: The new status to set.
|
||||
:param iteration: Uses the iteration index, to differ between current and next state.
|
||||
:return True if status has changed.
|
||||
"""
|
||||
self._status[iteration % 2] = new_status
|
||||
|
||||
return self._status[0] != self._status[1]
|
||||
|
||||
def get_status_of_iteration(self, iteration):
|
||||
""" Will return the status for the iteration modulo two.
|
||||
:param iteration: Uses the iteration index, to differ between current and next state.
|
||||
:return The status for this iteration.
|
||||
"""
|
||||
return self._status[iteration % 2]
|
||||
|
27
src/cellular_automaton/ca_cell_state.py
Normal file
27
src/cellular_automaton/ca_cell_state.py
Normal file
@ -0,0 +1,27 @@
|
||||
class CellState:
|
||||
"""
|
||||
This is the base class for all cell states.
|
||||
When using the cellular automaton display, inherit this class and implement get_state_draw_color.
|
||||
"""
|
||||
def __init__(self, initial_state):
|
||||
self._state = [[initial_state], [initial_state]]
|
||||
|
||||
def set_status_of_iteration(self, new_status, iteration):
|
||||
""" Will set the new status for the iteration modulo two.
|
||||
:param new_status: The new status to set.
|
||||
:param iteration: Uses the iteration index, to differ between current and next state.
|
||||
:return True if status has changed.
|
||||
"""
|
||||
self._state[iteration % 2] = new_status
|
||||
|
||||
return self._state[0] != self._state[1]
|
||||
|
||||
def get_status_of_iteration(self, iteration):
|
||||
""" Will return the status for the iteration modulo two.
|
||||
:param iteration: Uses the iteration index, to differ between current and next state.
|
||||
:return The status for this iteration.
|
||||
"""
|
||||
return self._state[iteration % 2]
|
||||
|
||||
def get_state_draw_color(self, iteration):
|
||||
raise NotImplementedError
|
80
src/cellular_automaton/ca_display.py
Normal file
80
src/cellular_automaton/ca_display.py
Normal file
@ -0,0 +1,80 @@
|
||||
import pygame
|
||||
import time
|
||||
import operator
|
||||
|
||||
from cellular_automaton.cellular_automaton import CellularAutomaton
|
||||
|
||||
|
||||
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 = []
|
||||
|
||||
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 = []
|
||||
|
||||
def _redraw_cell(self, cell):
|
||||
if cell.is_set_for_redrawing():
|
||||
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.release_from_redraw()
|
||||
|
||||
def _calculate_cell_position(self, cell):
|
||||
return list(map(operator.mul, self.cell_size, cell.coordinate))
|
||||
|
||||
def _calculate_cell_display_size(self):
|
||||
grid_dimension = self._cellular_automaton.grid.get_dimension()
|
||||
return list(map(operator.truediv, self.grid_size, grid_dimension))
|
||||
|
||||
|
||||
class PyGameFor2D:
|
||||
def __init__(self, windows_size: list, cellular_automaton: CellularAutomaton):
|
||||
self.window_size = windows_size
|
||||
self._cellular_automaton = cellular_automaton
|
||||
|
||||
pygame.init()
|
||||
pygame.display.set_caption("Cellular Automaton")
|
||||
self.screen = pygame.display.set_mode(self.window_size)
|
||||
self.font = pygame.font.SysFont("monospace", 15)
|
||||
|
||||
self.ca_display = DisplayFor2D([0, 30, windows_size[0], windows_size[1]-30], cellular_automaton, self.screen)
|
||||
|
||||
def _print_process_duration(self, time_ca_end, time_ca_start, time_ds_end):
|
||||
self.screen.fill([0, 0, 0], ((0, 0), (self.window_size[0], 30)))
|
||||
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)):
|
||||
label = self.font.render(text, 1, color)
|
||||
update_rect = self.screen.blit(label, pos)
|
||||
pygame.display.update(update_rect)
|
||||
|
||||
def main_loop(self):
|
||||
running = True
|
||||
|
||||
while running:
|
||||
time_ca_start = time.time()
|
||||
self._cellular_automaton.evolve_x_times(1)
|
||||
time_ca_end = time.time()
|
||||
self.ca_display._redraw_cellular_automaton()
|
||||
time_ds_end = time.time()
|
||||
self._print_process_duration(time_ca_end, time_ca_start, time_ds_end)
|
||||
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
running = False
|
||||
|
@ -59,4 +59,4 @@ class CellularAutomaton:
|
||||
active = self.evolution_rule.evolve_cell(cell_info[0], cell_info[1], self.iteration)
|
||||
|
||||
if active:
|
||||
self.grid.set_cells_active(cell_info[0] + cell_info[1])
|
||||
self.grid.set_cells_active([cell_info[0]] + cell_info[1])
|
||||
|
Loading…
Reference in New Issue
Block a user