2019-02-03 16:17:57 +00:00
|
|
|
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:
|
2019-02-02 08:11:48 +00:00
|
|
|
_state_save_slot_count = 2
|
2018-12-09 10:20:16 +00:00
|
|
|
"""
|
|
|
|
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-02 08:11:48 +00:00
|
|
|
def __init__(self, initial_state=(0., ), draw_first_state=True):
|
2019-02-03 16:17:57 +00:00
|
|
|
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
|
2019-01-31 12:38:48 +00:00
|
|
|
if draw_first_state:
|
2019-02-03 16:17:57 +00:00
|
|
|
self._dirty = RawValue(c_bool, True)
|
2019-01-31 12:38:48 +00:00
|
|
|
else:
|
2019-02-03 16:17:57 +00:00
|
|
|
self._dirty = RawValue(c_bool, False)
|
2019-02-02 08:11:48 +00:00
|
|
|
|
2019-02-03 16:17:57 +00:00
|
|
|
def is_active(self, iteration):
|
|
|
|
return self._active[self.__calculate_slot(iteration)]
|
2019-01-31 12:38:48 +00:00
|
|
|
|
2019-02-03 16:17:57 +00:00
|
|
|
def set_active_for_next_iteration(self, iteration):
|
|
|
|
self._active[self.__calculate_slot(iteration + 1)].value = True
|
2019-02-02 08:11:48 +00:00
|
|
|
|
|
|
|
def is_set_for_redraw(self):
|
2019-02-03 16:17:57 +00:00
|
|
|
return self._dirty.value
|
2018-12-09 10:20:16 +00:00
|
|
|
|
2019-01-31 12:38:48 +00:00
|
|
|
def was_redrawn(self):
|
2019-02-03 16:17:57 +00:00
|
|
|
self._dirty.value = 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.
|
|
|
|
"""
|
|
|
|
return self._state_slots[self.__calculate_slot(iteration)]
|
|
|
|
|
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-01-05 14:42:37 +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-02 08:11:48 +00:00
|
|
|
current_state = self.get_state_of_iteration(iteration)
|
2019-01-31 12:38:48 +00:00
|
|
|
|
|
|
|
changed = False
|
|
|
|
for i in range(len(current_state)):
|
|
|
|
try:
|
|
|
|
if current_state[i] != new_state[i]:
|
|
|
|
changed = True
|
2019-02-03 16:17:57 +00:00
|
|
|
current_state[i] = new_state[i]
|
2019-01-31 12:38:48 +00:00
|
|
|
except IndexError:
|
|
|
|
raise IndexError("New State length or type is invalid!")
|
2019-01-05 14:45:09 +00:00
|
|
|
|
2019-02-02 08:11:48 +00:00
|
|
|
self._dirty.value |= changed
|
2019-02-03 16:17:57 +00:00
|
|
|
self._active[self.__calculate_slot(iteration)].value = False
|
2019-01-31 12:38:48 +00:00
|
|
|
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
|
|
|
|
def __calculate_slot(cls, iteration):
|
|
|
|
return iteration % cls._state_save_slot_count
|