neuropercolation/src/cellular_automaton/ca_cell_state.py

94 lines
3.5 KiB
Python
Raw Normal View History

from multiprocessing import RawArray, RawValue
from ctypes import c_float, c_bool
2019-01-31 12:38:48 +00:00
2018-12-09 10:20:16 +00:00
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.
"""
2019-02-10 10:54:42 +00:00
_state_save_slot_count = 2
def __init__(self, initial_state=(0., ), draw_first_state=True):
2019-02-10 10:54:42 +00:00
self._state_slots = [list(initial_state) for i in range(self.__class__._state_save_slot_count)]
self._active = [False for i in range(self.__class__._state_save_slot_count)]
self._active[0] = True
self._dirty = draw_first_state
def is_active(self, iteration):
2019-02-10 10:54:42 +00:00
return self._active[self._calculate_slot(iteration)]
2019-01-31 12:38:48 +00:00
def set_active_for_next_iteration(self, iteration):
2019-02-10 10:54:42 +00:00
self._active[self._calculate_slot(iteration + 1)] = True
def is_set_for_redraw(self):
2019-02-10 10:54:42 +00:00
return self._dirty
2018-12-09 10:20:16 +00:00
2019-01-31 12:38:48 +00:00
def was_redrawn(self):
2019-02-10 10:54:42 +00:00
self._dirty = False
2019-01-31 12:38:48 +00:00
def get_state_of_last_iteration(self, current_iteration_index):
return self.get_state_of_iteration(current_iteration_index - 1)
2019-02-09 18:06:18 +00:00
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.
:return The state for this iteration.
"""
2019-02-10 10:54:42 +00:00
return self._state_slots[self._calculate_slot(iteration)]
2019-02-09 18:06:18 +00:00
2019-01-31 12:38:48 +00:00
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.
2019-02-10 10:00:57 +00:00
:param iteration: Uses the iteration index, to differ between concurrent states.
2019-01-31 12:38:48 +00:00
:return True if state has changed.
2018-12-09 10:20:16 +00:00
"""
2019-02-10 10:54:42 +00:00
changed = self._change_state(new_state, iteration)
self._dirty |= changed
self._active[self._calculate_slot(iteration)] = False
return changed
2018-12-09 10:20:16 +00:00
2019-02-10 10:54:42 +00:00
def _change_state(self, new_state, iteration):
current_state = self.get_state_of_iteration(iteration)
2019-01-31 12:38:48 +00:00
changed = False
2019-02-10 10:54:42 +00:00
for i, ns in enumerate(new_state):
2019-01-31 12:38:48 +00:00
try:
2019-02-10 10:54:42 +00:00
if current_state[i] != ns:
2019-01-31 12:38:48 +00:00
changed = True
2019-02-10 10:54:42 +00:00
current_state[i] = ns
2019-01-31 12:38:48 +00:00
except IndexError:
raise IndexError("New State length or type is invalid!")
return changed
2018-12-09 10:20:16 +00:00
def get_state_draw_color(self, iteration):
raise NotImplementedError
2019-02-09 18:06:18 +00:00
@classmethod
2019-02-10 10:54:42 +00:00
def _calculate_slot(cls, iteration):
2019-02-09 18:06:18 +00:00
return iteration % cls._state_save_slot_count
2019-02-10 10:54:42 +00:00
class SynchronousCellState(CellState):
def __init__(self, initial_state=(0., ), draw_first_state=True):
super().__init__(initial_state, draw_first_state)
self._state_slots = [RawArray(c_float, initial_state) for i in range(self.__class__._state_save_slot_count)]
self._active = [RawValue(c_bool, False) for i in range(self.__class__._state_save_slot_count)]
self._active[0].value = True
self._dirty = RawValue(c_bool, draw_first_state)
def set_active_for_next_iteration(self, iteration):
self._active[self._calculate_slot(iteration + 1)].value = True
def is_set_for_redraw(self):
return self._dirty.value
def was_redrawn(self):
self._dirty.value = False
def set_state_of_iteration(self, new_state, iteration):
changed = self._change_state(new_state, iteration)
self._dirty.value |= changed
self._active[self._calculate_slot(iteration)].value = False
return changed