second try
This commit is contained in:
parent
a8d17f6fe9
commit
be57f89e78
3
.gitignore
vendored
3
.gitignore
vendored
@ -2,4 +2,5 @@
|
|||||||
*.pyc__pycache__
|
*.pyc__pycache__
|
||||||
__pycache__
|
__pycache__
|
||||||
.coverage
|
.coverage
|
||||||
htmlcov/
|
htmlcov/
|
||||||
|
*.orig
|
@ -1,63 +1,51 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import random
|
|
||||||
|
|
||||||
from cellular_automaton.cellular_automaton import CellularAutomaton, CellularAutomatonProcessor
|
|
||||||
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_cell_state import CellState
|
||||||
from cellular_automaton.ca_grid import Grid
|
from cellular_automaton.ca_rule import Rule
|
||||||
|
|
||||||
|
|
||||||
class TestRule(Rule):
|
class TestRule(Rule):
|
||||||
def evolve_cell(self, cell, iteration_index):
|
|
||||||
if cell.state is None:
|
|
||||||
return self._init_state(cell)
|
|
||||||
else:
|
|
||||||
return self._evolve_state(cell, iteration_index)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _evolve_state(cell, iteration_index):
|
def evolve_cell(last_cell_state, last_neighbour_states):
|
||||||
try:
|
try:
|
||||||
left_neighbour_state = cell.neighbours[0].state.get_status_of_iteration(iteration_index - 1)
|
return last_neighbour_states[0]
|
||||||
active = cell.state.set_status_of_iteration(left_neighbour_state, iteration_index)
|
|
||||||
if active:
|
|
||||||
cell.is_set_for_redraw = True
|
|
||||||
return active
|
|
||||||
except IndexError:
|
except IndexError:
|
||||||
return False
|
pass
|
||||||
|
return False
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _init_state(cell):
|
class MyState(CellState):
|
||||||
|
def __init__(self):
|
||||||
rand = random.randrange(0, 101, 1)
|
rand = random.randrange(0, 101, 1)
|
||||||
if rand <= 99:
|
init = 0
|
||||||
cell.state = MyStatus(0)
|
if rand > 99:
|
||||||
return False
|
init = 1
|
||||||
else:
|
|
||||||
cell.state = MyStatus(1)
|
|
||||||
cell.is_set_for_redraw = True
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
super().__init__(init, draw_first_state=False)
|
||||||
class MyStatus(CellState):
|
|
||||||
def __init__(self, initial_state):
|
|
||||||
super().__init__([initial_state])
|
|
||||||
|
|
||||||
def get_state_draw_color(self, iteration):
|
def get_state_draw_color(self, iteration):
|
||||||
red = 0
|
red = 0
|
||||||
if self._state_slots[iteration % 2][0]:
|
if self.get_state_of_last_iteration(iteration)[0]:
|
||||||
red = 255
|
red = 255
|
||||||
return [red, 0, 0]
|
return [red, 0, 0]
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
import random
|
||||||
|
from multiprocessing import freeze_support
|
||||||
|
|
||||||
|
from cellular_automaton.cellular_automaton import CellularAutomaton, CellularAutomatonProcessor
|
||||||
|
from cellular_automaton.ca_neighborhood import MooreNeighborhood, EdgeRule
|
||||||
|
from cellular_automaton.ca_display import PyGameFor2D
|
||||||
|
from cellular_automaton.ca_grid import Grid
|
||||||
|
freeze_support()
|
||||||
random.seed(1000)
|
random.seed(1000)
|
||||||
rule = TestRule()
|
rule = TestRule()
|
||||||
grid = Grid(dimension=[400, 400],
|
grid = Grid(dimension=[400, 400],
|
||||||
neighborhood=MooreNeighborhood(EdgeRule.FIRST_AND_LAST_CELL_OF_DIMENSION_ARE_NEIGHBORS))
|
neighborhood=MooreNeighborhood(EdgeRule.FIRST_AND_LAST_CELL_OF_DIMENSION_ARE_NEIGHBORS),
|
||||||
|
state_class=MyState)
|
||||||
ca = CellularAutomaton(grid, rule)
|
ca = CellularAutomaton(grid, rule)
|
||||||
ca_window = PyGameFor2D(window_size=[1000, 800], cellular_automaton=ca)
|
ca_window = PyGameFor2D(window_size=[1000, 800], cellular_automaton=ca)
|
||||||
ca_processor = CellularAutomatonProcessor(process_count=8)
|
ca_processor = CellularAutomatonProcessor(process_count=2, cellular_automaton=ca)
|
||||||
ca_window.main_loop(cellular_automaton_processor=ca_processor,
|
ca_window.main_loop(cellular_automaton_processor=ca_processor,
|
||||||
ca_iterations_per_draw=5)
|
ca_iterations_per_draw=5)
|
||||||
|
@ -1,7 +1,61 @@
|
|||||||
|
import multiprocessing
|
||||||
|
|
||||||
|
from cellular_automaton.ca_cell_state import CellState
|
||||||
|
|
||||||
|
|
||||||
class Cell:
|
class Cell:
|
||||||
def __init__(self, name, coordinate: list):
|
def __init__(self, name, state_class: CellState.__class__, coordinate: list):
|
||||||
self.name = name
|
self._name = name
|
||||||
self.coordinate = coordinate
|
self._coordinate = coordinate
|
||||||
self.neighbours = []
|
self._state = state_class()
|
||||||
self.state = None
|
self._neighbours = []
|
||||||
self.is_set_for_redraw = False
|
self._active = multiprocessing.Value('i', 1)
|
||||||
|
self._age = multiprocessing.Value('i', 0)
|
||||||
|
|
||||||
|
def set_neighbours(self, neighbours):
|
||||||
|
self._neighbours = neighbours
|
||||||
|
|
||||||
|
def get_coordinate(self):
|
||||||
|
return self._coordinate
|
||||||
|
|
||||||
|
def evolve_if_ready(self, rule):
|
||||||
|
if self._neighbours_are_younger():
|
||||||
|
if self._is_active():
|
||||||
|
new_state = rule(self.get_current_state(), self.get_neighbour_states())
|
||||||
|
self.set_new_state_and_activate(new_state)
|
||||||
|
|
||||||
|
self.increase_age()
|
||||||
|
|
||||||
|
def _neighbours_are_younger(self):
|
||||||
|
for n in self._neighbours:
|
||||||
|
if n.get_age() < self.get_age():
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_age(self):
|
||||||
|
return self._age.value
|
||||||
|
|
||||||
|
def _is_active(self):
|
||||||
|
return self._active.value > self._age.value
|
||||||
|
|
||||||
|
def get_current_state(self):
|
||||||
|
return self._state.get_state_of_iteration(self._age.value)
|
||||||
|
|
||||||
|
def get_neighbour_states(self):
|
||||||
|
return [n.get_state_from_iteration(self._age.value) for n in self._neighbours]
|
||||||
|
|
||||||
|
def set_new_state_and_activate(self, new_state: CellState):
|
||||||
|
changed = self._state.set_current_state(new_state, self._age.value + 1)
|
||||||
|
if changed:
|
||||||
|
self._set_active()
|
||||||
|
|
||||||
|
def _set_active(self):
|
||||||
|
self.set_active_for_next_iteration(self._age.value)
|
||||||
|
for n in self._neighbours:
|
||||||
|
n.set_active_for_next_iteration(self._age.value)
|
||||||
|
|
||||||
|
def set_active_for_next_iteration(self, iteration):
|
||||||
|
self._active.value = max(self._active.value, iteration + 1)
|
||||||
|
|
||||||
|
def increase_age(self):
|
||||||
|
with self._age.get_lock():
|
||||||
|
self._age += 1
|
||||||
|
@ -1,30 +1,65 @@
|
|||||||
|
from multiprocessing import Array, Value
|
||||||
|
|
||||||
|
|
||||||
class CellState:
|
class CellState:
|
||||||
"""
|
"""
|
||||||
This is the base class for all cell states.
|
This is the base class for all cell states.
|
||||||
When using the cellular automaton display, inherit this class and implement get_state_draw_color.
|
When using the cellular automaton display, inherit this class and implement get_state_draw_color.
|
||||||
"""
|
"""
|
||||||
def __init__(self, initial_state, state_save_slot_count=2):
|
def __init__(self, initial_state=(0., ), state_save_slot_count=2, draw_first_state=True):
|
||||||
self._state_save_slot_count = state_save_slot_count
|
self._state_save_slot_count = state_save_slot_count
|
||||||
self._state_slots = [initial_state] * state_save_slot_count
|
self._state_slots = [Array('d', initial_state)] * state_save_slot_count
|
||||||
|
if draw_first_state:
|
||||||
|
self._dirty = Value('i', 1)
|
||||||
|
else:
|
||||||
|
self._dirty = Value('i', 0)
|
||||||
|
|
||||||
def set_status_of_iteration(self, new_status, iteration):
|
def is_set_for_redraw(self):
|
||||||
""" Will set the new status for the iteration modulo number of saved states.
|
return self._dirty != 1
|
||||||
:param new_status: The new status to set.
|
|
||||||
|
def get_state_changes(self):
|
||||||
|
return self._dirty
|
||||||
|
|
||||||
|
def set_for_redraw(self):
|
||||||
|
self._dirty = 1
|
||||||
|
|
||||||
|
def was_redrawn(self):
|
||||||
|
self._dirty = 0
|
||||||
|
|
||||||
|
def set_current_state(self, new_state, current_iteration_index):
|
||||||
|
return self.set_state_of_iteration(new_state, current_iteration_index)
|
||||||
|
|
||||||
|
def get_state_of_last_iteration(self, current_iteration_index):
|
||||||
|
return self.get_state_of_iteration(current_iteration_index - 1)
|
||||||
|
|
||||||
|
def set_state_of_iteration(self, new_state, iteration):
|
||||||
|
""" Will set the new state for the iteration modulo number of saved states.
|
||||||
|
:param new_state: The new state to set.
|
||||||
:param iteration: Uses the iteration index, to differ between concurrent states.
|
:param iteration: Uses the iteration index, to differ between concurrent states.
|
||||||
:return True if status has changed.
|
:return True if state has changed.
|
||||||
"""
|
"""
|
||||||
slot_count = self._state_save_slot_count
|
slot_count = self._state_save_slot_count
|
||||||
states = self._state_slots
|
states = self._state_slots
|
||||||
|
|
||||||
states[iteration % slot_count] = new_status
|
current_state = states[iteration % slot_count]
|
||||||
|
|
||||||
return states[(iteration - 1) % slot_count] \
|
changed = False
|
||||||
!= states[iteration % slot_count]
|
for i in range(len(current_state)):
|
||||||
|
try:
|
||||||
|
if current_state[i] != new_state[i]:
|
||||||
|
changed = True
|
||||||
|
|
||||||
def get_status_of_iteration(self, iteration):
|
current_state[i] = new_state[i]
|
||||||
""" Will return the status for the iteration modulo number of saved states.
|
except IndexError:
|
||||||
|
raise IndexError("New State length or type is invalid!")
|
||||||
|
|
||||||
|
self._dirty |= changed
|
||||||
|
return changed
|
||||||
|
|
||||||
|
def get_state_of_iteration(self, iteration):
|
||||||
|
""" Will return the state for the iteration modulo number of saved states.
|
||||||
:param iteration: Uses the iteration index, to differ between concurrent states.
|
:param iteration: Uses the iteration index, to differ between concurrent states.
|
||||||
:return The status for this iteration.
|
:return The state for this iteration.
|
||||||
"""
|
"""
|
||||||
return self._state_slots[iteration % self._state_save_slot_count]
|
return self._state_slots[iteration % self._state_save_slot_count]
|
||||||
|
|
||||||
|
@ -59,25 +59,27 @@ class PyGameFor2D:
|
|||||||
|
|
||||||
while running:
|
while running:
|
||||||
time_ca_start = time.time()
|
time_ca_start = time.time()
|
||||||
cellular_automaton_processor.evolve_x_times(self._cellular_automaton, ca_iterations_per_draw)
|
|
||||||
time_ca_end = time.time()
|
time_ca_end = time.time()
|
||||||
self.ca_display._redraw_cellular_automaton()
|
self.ca_display._redraw_cellular_automaton()
|
||||||
time_ds_end = time.time()
|
time_ds_end = time.time()
|
||||||
self._print_process_duration(time_ca_end, time_ca_start, time_ds_end)
|
self._print_process_duration(time_ca_end, time_ca_start, time_ds_end)
|
||||||
|
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
for event in pygame.event.get():
|
for event in pygame.event.get():
|
||||||
if event.type == pygame.QUIT:
|
if event.type == pygame.QUIT:
|
||||||
|
cellular_automaton_processor.stop()
|
||||||
running = False
|
running = False
|
||||||
|
|
||||||
|
|
||||||
def _cell_redraw_rectangles(cells, evolution_index, display_info):
|
def _cell_redraw_rectangles(cells, evolution_index, display_info):
|
||||||
for cell in cells:
|
for cell in cells:
|
||||||
if cell.is_set_for_redraw:
|
if cell.state.is_set_for_redraw():
|
||||||
cell_color = cell.state.get_state_draw_color(evolution_index)
|
cell_color = cell.state.get_state_draw_color(evolution_index)
|
||||||
cell_pos = _calculate_cell_position(display_info.cell_size, cell)
|
cell_pos = _calculate_cell_position(display_info.cell_size, cell)
|
||||||
surface_pos = list(map(operator.add, cell_pos, display_info.grid_pos))
|
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))
|
yield display_info.screen.fill(cell_color, (surface_pos, display_info.cell_size))
|
||||||
cell.is_set_for_redraw = False
|
cell.state.was_redrawn()
|
||||||
|
|
||||||
|
|
||||||
def _calculate_cell_position(cell_size, cell):
|
def _calculate_cell_position(cell_size, cell):
|
||||||
|
@ -3,10 +3,11 @@ from cellular_automaton.ca_neighborhood import Neighborhood
|
|||||||
|
|
||||||
|
|
||||||
class Grid:
|
class Grid:
|
||||||
def __init__(self, dimension: list, neighborhood: Neighborhood):
|
def __init__(self, dimension: list, neighborhood: Neighborhood, state_class):
|
||||||
self._dimension = dimension
|
self._dimension = dimension
|
||||||
self._cells = {}
|
self._cells = {}
|
||||||
self._active_cells = {}
|
self._active_cells = {}
|
||||||
|
self._state_class = state_class
|
||||||
|
|
||||||
self._init_cells(neighborhood)
|
self._init_cells(neighborhood)
|
||||||
|
|
||||||
@ -58,7 +59,7 @@ class Grid:
|
|||||||
self._recursive_step_down_dimensions(coordinate, dimension_index, self._create_cells)
|
self._recursive_step_down_dimensions(coordinate, dimension_index, self._create_cells)
|
||||||
except IndexError:
|
except IndexError:
|
||||||
coordinate_string = _join_coordinate(coordinate)
|
coordinate_string = _join_coordinate(coordinate)
|
||||||
self._cells[coordinate_string] = Cell(coordinate_string, coordinate)
|
self._cells[coordinate_string] = Cell(coordinate_string, self._state_class, coordinate)
|
||||||
|
|
||||||
def _recursive_step_down_dimensions(self, coordinate, dimension_index, recursion_method):
|
def _recursive_step_down_dimensions(self, coordinate, dimension_index, recursion_method):
|
||||||
""" For the range of the current dimension, recalls the recursion method.
|
""" For the range of the current dimension, recalls the recursion method.
|
||||||
@ -72,9 +73,9 @@ class Grid:
|
|||||||
|
|
||||||
def _set_cell_neighbours(self, neighborhood):
|
def _set_cell_neighbours(self, neighborhood):
|
||||||
for cell in self._cells.values():
|
for cell in self._cells.values():
|
||||||
neighbours_coordinates = neighborhood.calculate_cell_neighbor_coordinates(cell.coordinate,
|
neighbours_coordinates = neighborhood.calculate_cell_neighbor_coordinates(cell.get_coordinate(),
|
||||||
self._dimension)
|
self._dimension)
|
||||||
cell.neighbours = list(map(self._get_cell_by_coordinate, neighbours_coordinates))
|
cell.set_neighbours(list(map(self._get_cell_by_coordinate, neighbours_coordinates)))
|
||||||
|
|
||||||
def _get_cell_by_coordinate(self, coordinate):
|
def _get_cell_by_coordinate(self, coordinate):
|
||||||
return self._cells[_join_coordinate(coordinate)]
|
return self._cells[_join_coordinate(coordinate)]
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
from cellular_automaton.ca_cell import Cell
|
|
||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
|
|
||||||
|
|
||||||
@ -6,11 +5,12 @@ class Rule:
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def evolve_cell(self, cell: Cell, iteration_index: int):
|
def evolve_cell(last_cell_state, last_neighbour_states):
|
||||||
""" Calculates and sets new state of 'cell'.
|
""" Calculates and sets new state of 'cell'.
|
||||||
:param cell: The cell to calculate new state for.
|
:param last_cell_state: The cells current state to calculate new state for.
|
||||||
:param iteration_index: The current iteration index, to choose the correct state.
|
:param last_neighbour_states: The cells neighbours current states.
|
||||||
:return: True if state changed, False if not.
|
:return: True if state changed, False if not.
|
||||||
A cells evolution will only be called if it or at least one of its neighbours has changed last iteration cycle.
|
A cells evolution will only be called if it or at least one of its neighbours has changed last iteration cycle.
|
||||||
"""
|
"""
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
|
import multiprocessing
|
||||||
|
|
||||||
from cellular_automaton.ca_grid import Grid
|
from cellular_automaton.ca_grid import Grid
|
||||||
from cellular_automaton.ca_rule import Rule
|
from cellular_automaton.ca_rule import Rule
|
||||||
from cellular_automaton.ca_cell_state import CellState
|
|
||||||
|
|
||||||
from multiprocessing import Process, Pipe, Array, Value
|
|
||||||
import multiprocessing
|
|
||||||
|
|
||||||
|
|
||||||
class CellularAutomaton:
|
class CellularAutomaton:
|
||||||
@ -13,160 +11,29 @@ class CellularAutomaton:
|
|||||||
self.evolution_iteration_index = 0
|
self.evolution_iteration_index = 0
|
||||||
|
|
||||||
|
|
||||||
class _EvolutionProcess:
|
|
||||||
def __init__(self, process: Process, pipe: Pipe):
|
|
||||||
self.process = process
|
|
||||||
self.pipe = pipe
|
|
||||||
self.cell = None
|
|
||||||
|
|
||||||
|
|
||||||
class CellularAutomatonProcessor:
|
class CellularAutomatonProcessor:
|
||||||
def __init__(self, process_count: int = 1):
|
def __init__(self, cellular_automaton, process_count: int = 1):
|
||||||
self._processes = list(_create_processes(process_count))
|
self.active = multiprocessing.Value('i', 1)
|
||||||
|
cells = list(cellular_automaton.grid.get_cells().values())
|
||||||
|
chunk_size = int(len(cells) / process_count)
|
||||||
|
self._processes = [multiprocessing.Process(target=_process_routine,
|
||||||
|
name=str(i),
|
||||||
|
args=(cells[i*chunk_size:i*chunk_size + chunk_size],
|
||||||
|
cellular_automaton.evolution_rule,
|
||||||
|
self.active))
|
||||||
|
for i in range(process_count)]
|
||||||
|
for p in self._processes:
|
||||||
|
p.start()
|
||||||
self.__cellular_automaton = None
|
self.__cellular_automaton = None
|
||||||
|
|
||||||
def evolve_x_times(self, cellular_automaton: CellularAutomaton, evolution_steps: int):
|
def stop(self):
|
||||||
""" Evolve all cells for x time steps.
|
self.active.value = 0
|
||||||
:param cellular_automaton: The cellular automaton to evolve.
|
for p in self._processes:
|
||||||
:param evolution_steps: The count of evolutions done.
|
p.join()
|
||||||
:return: True if all cells are inactive
|
|
||||||
"""
|
|
||||||
for evo in range(evolution_steps):
|
|
||||||
finished = self.evolve(cellular_automaton)
|
|
||||||
if finished:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def evolve(self, cellular_automaton: CellularAutomaton):
|
|
||||||
""" Evolves all active cells for one time step.
|
|
||||||
:param cellular_automaton: The cellular automaton to evolve.
|
|
||||||
:return: True if all cells are inactive.
|
|
||||||
"""
|
|
||||||
self.__cellular_automaton = cellular_automaton
|
|
||||||
if self._is_evolution_finished():
|
|
||||||
print("finished")
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
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.__cellular_automaton.grid.get_active_cells()
|
|
||||||
self.__cellular_automaton.grid.clear_active_cells()
|
|
||||||
self._evolve_cells(active_cells.values())
|
|
||||||
print(len(self.__cellular_automaton.grid.get_active_cells()))
|
|
||||||
|
|
||||||
def _evolve_cells(self, cells):
|
|
||||||
cellular_automaton = self.__cellular_automaton
|
|
||||||
processes = self._processes
|
|
||||||
process_count = len(processes)
|
|
||||||
for i, cell in enumerate(cells):
|
|
||||||
evolution_process = processes[i % process_count]
|
|
||||||
if evolution_process.cell:
|
|
||||||
response = evolution_process.pipe.recv()
|
|
||||||
evolved_cell = evolution_process.cell
|
|
||||||
evolved_cell.state = response[0]
|
|
||||||
evolved_cell.is_set_for_redraw |= response[1]
|
|
||||||
if evolved_cell.is_set_for_redraw:
|
|
||||||
cellular_automaton.grid.set_cells_active([evolved_cell] + evolved_cell.neighbours)
|
|
||||||
evolution_process.cell = None
|
|
||||||
|
|
||||||
cell_info = self.read_cell_info(cell, cellular_automaton.evolution_iteration_index)
|
|
||||||
evolution_process.pipe.send(cell_info)
|
|
||||||
evolution_process.cell = cell
|
|
||||||
|
|
||||||
for evolution_process in processes:
|
|
||||||
response = evolution_process.pipe.recv()
|
|
||||||
cell = evolution_process.cell
|
|
||||||
cell.state = response[0]
|
|
||||||
cell.is_set_for_redraw |= response[1]
|
|
||||||
if cell.is_set_for_redraw:
|
|
||||||
cellular_automaton.grid.set_cells_active([cell] + cell.neighbours)
|
|
||||||
evolution_process.cell = None
|
|
||||||
|
|
||||||
# if cellular_automaton.evolution_rule.evolve_cell(cell.state, cellular_automaton.evolution_iteration_index):
|
|
||||||
# cellular_automaton.grid.set_cells_active([cell] + cell.neighbours)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def read_cell_info(cell, iteration):
|
|
||||||
coordinate = cell.coordinate
|
|
||||||
return [coordinate, cell.state, [n.state for n in cell.neighbours], iteration]
|
|
||||||
|
|
||||||
# if cell.state is not None:
|
|
||||||
# cell_state = cell.state.get_status_of_iteration(iteration - 1)
|
|
||||||
# else:
|
|
||||||
# cell_state = None
|
|
||||||
#
|
|
||||||
# neighbor_states = []
|
|
||||||
# for neighbor in cell.neighbours:
|
|
||||||
# if neighbor.state is not None:
|
|
||||||
# neighbor_state = neighbor.state.get_status_of_iteration(iteration - 1)
|
|
||||||
# else:
|
|
||||||
# neighbor_state = None
|
|
||||||
# neighbor_states.append(neighbor_state)
|
|
||||||
#
|
|
||||||
# return [coordinate, cell_state, neighbor_states]
|
|
||||||
|
|
||||||
|
|
||||||
def _create_processes(count):
|
def _process_routine(cells, rule, active):
|
||||||
for i in range(count):
|
while active.value == 1:
|
||||||
parent_pipe_connection, child_pipe_connection = Pipe()
|
for cell in cells:
|
||||||
p = Process(target=process_routine, args=(child_pipe_connection, ))
|
cell.evolve_if_ready(rule)
|
||||||
p.start()
|
|
||||||
yield _EvolutionProcess(p, parent_pipe_connection)
|
|
||||||
|
|
||||||
|
|
||||||
def process_routine(pipe_conn: Pipe):
|
|
||||||
while True:
|
|
||||||
info = pipe_conn.recv()
|
|
||||||
pipe_conn.send(evolve_cell(*info))
|
|
||||||
|
|
||||||
|
|
||||||
def evolve_cell(coordinate, cell_state, neighbor_states, index):
|
|
||||||
if cell_state is None:
|
|
||||||
return _init_state()
|
|
||||||
else:
|
|
||||||
new_state = _evolve_state(cell_state, neighbor_states, index)
|
|
||||||
if new_state is None:
|
|
||||||
print(",".join([str(x) for x in neighbor_states]))
|
|
||||||
return [cell_state, False]
|
|
||||||
else:
|
|
||||||
changed = cell_state.set_status_of_iteration(new_state, index)
|
|
||||||
return [cell_state, changed]
|
|
||||||
|
|
||||||
|
|
||||||
def _evolve_state(cell_state, neighbor_states, index):
|
|
||||||
try:
|
|
||||||
left_neighbour_state = neighbor_states[0].get_status_of_iteration(index - 1)
|
|
||||||
return left_neighbour_state
|
|
||||||
except (IndexError, AttributeError):
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
import random
|
|
||||||
|
|
||||||
|
|
||||||
def _init_state():
|
|
||||||
rand = random.randrange(0, 101, 1)
|
|
||||||
if rand <= 99:
|
|
||||||
return [MyStatus(0), False]
|
|
||||||
else:
|
|
||||||
return [MyStatus(1), True]
|
|
||||||
|
|
||||||
|
|
||||||
class MyStatus(CellState):
|
|
||||||
def __init__(self, initial_state):
|
|
||||||
super().__init__(initial_state)
|
|
||||||
|
|
||||||
def get_state_draw_color(self, iteration):
|
|
||||||
red = 0
|
|
||||||
if self._state_slots[iteration % 2][0]:
|
|
||||||
red = 255
|
|
||||||
return [red, 0, 0]
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return super().__str__()
|
|
||||||
|
Loading…
Reference in New Issue
Block a user