2018-12-01 19:37:18 +00:00
|
|
|
from cellular_automaton.ca_grid import Grid
|
|
|
|
from cellular_automaton.ca_rule import Rule
|
2019-01-06 10:21:46 +00:00
|
|
|
from cellular_automaton.ca_cell_state import CellState
|
|
|
|
|
|
|
|
from multiprocessing import Process, Pipe, Array, Value
|
|
|
|
import multiprocessing
|
2018-12-01 14:14:22 +00:00
|
|
|
|
|
|
|
|
|
|
|
class CellularAutomaton:
|
2019-01-05 16:38:21 +00:00
|
|
|
def __init__(self, grid: Grid, evolution_rule: Rule):
|
|
|
|
self.grid = grid
|
2018-12-08 21:33:13 +00:00
|
|
|
self.evolution_rule = evolution_rule
|
2019-01-05 16:38:21 +00:00
|
|
|
self.evolution_iteration_index = 0
|
2018-12-01 14:14:22 +00:00
|
|
|
|
2018-12-01 19:37:18 +00:00
|
|
|
|
2019-01-06 10:21:46 +00:00
|
|
|
class _EvolutionProcess:
|
|
|
|
def __init__(self, process: Process, pipe: Pipe):
|
|
|
|
self.process = process
|
|
|
|
self.pipe = pipe
|
|
|
|
self.cell = None
|
|
|
|
|
|
|
|
|
|
|
|
class CellularAutomatonProcessor:
|
2019-01-05 16:38:21 +00:00
|
|
|
def __init__(self, process_count: int = 1):
|
2019-01-06 10:21:46 +00:00
|
|
|
self._processes = list(_create_processes(process_count))
|
2019-01-05 16:38:21 +00:00
|
|
|
self.__cellular_automaton = None
|
2018-12-02 16:45:08 +00:00
|
|
|
|
2019-01-05 16:38:21 +00:00
|
|
|
def evolve_x_times(self, cellular_automaton: CellularAutomaton, evolution_steps: int):
|
2018-12-08 21:33:13 +00:00
|
|
|
""" Evolve all cells for x time steps.
|
2019-01-06 10:21:46 +00:00
|
|
|
:param cellular_automaton: The cellular automaton to evolve.
|
|
|
|
:param evolution_steps: The count of evolutions done.
|
2018-12-08 21:33:13 +00:00
|
|
|
:return: True if all cells are inactive
|
|
|
|
"""
|
2019-01-05 16:38:21 +00:00
|
|
|
for evo in range(evolution_steps):
|
|
|
|
finished = self.evolve(cellular_automaton)
|
2018-12-08 21:33:13 +00:00
|
|
|
if finished:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
2019-01-05 16:38:21 +00:00
|
|
|
def evolve(self, cellular_automaton: CellularAutomaton):
|
2018-12-08 16:45:06 +00:00
|
|
|
""" Evolves all active cells for one time step.
|
2019-01-06 10:21:46 +00:00
|
|
|
:param cellular_automaton: The cellular automaton to evolve.
|
2018-12-08 16:45:06 +00:00
|
|
|
:return: True if all cells are inactive.
|
|
|
|
"""
|
2019-01-05 16:38:21 +00:00
|
|
|
self.__cellular_automaton = cellular_automaton
|
2018-12-08 21:33:13 +00:00
|
|
|
if self._is_evolution_finished():
|
2019-01-06 10:21:46 +00:00
|
|
|
print("finished")
|
2018-12-02 16:45:08 +00:00
|
|
|
return True
|
|
|
|
else:
|
2019-01-05 16:38:21 +00:00
|
|
|
cellular_automaton.evolution_iteration_index += 1
|
2018-12-08 21:33:13 +00:00
|
|
|
self._evolve_all_active_cells()
|
2018-12-02 16:45:08 +00:00
|
|
|
return False
|
|
|
|
|
2019-01-05 16:38:21 +00:00
|
|
|
def _is_evolution_finished(self):
|
|
|
|
return len(self.__cellular_automaton.grid.get_active_cell_names()) == 0
|
|
|
|
|
2018-12-08 21:33:13 +00:00
|
|
|
def _evolve_all_active_cells(self):
|
2019-01-05 16:38:21 +00:00
|
|
|
active_cells = self.__cellular_automaton.grid.get_active_cells()
|
|
|
|
self.__cellular_automaton.grid.clear_active_cells()
|
2018-12-09 14:25:12 +00:00
|
|
|
self._evolve_cells(active_cells.values())
|
2019-01-06 10:21:46 +00:00
|
|
|
print(len(self.__cellular_automaton.grid.get_active_cells()))
|
2018-12-08 16:45:06 +00:00
|
|
|
|
2019-01-06 10:21:46 +00:00
|
|
|
def _evolve_cells(self, cells):
|
2019-01-05 16:38:21 +00:00
|
|
|
cellular_automaton = self.__cellular_automaton
|
2019-01-06 10:21:46 +00:00
|
|
|
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
|
2018-12-08 16:45:06 +00:00
|
|
|
|
2019-01-06 10:21:46 +00:00
|
|
|
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:
|
2019-01-05 16:38:21 +00:00
|
|
|
cellular_automaton.grid.set_cells_active([cell] + cell.neighbours)
|
2019-01-06 10:21:46 +00:00
|
|
|
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):
|
|
|
|
for i in range(count):
|
|
|
|
parent_pipe_connection, child_pipe_connection = Pipe()
|
|
|
|
p = Process(target=process_routine, args=(child_pipe_connection, ))
|
|
|
|
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__()
|