increased api documentation
This commit is contained in:
parent
4507327bd5
commit
9964e3b483
@ -79,8 +79,9 @@ class MyRule(Rule):
|
|||||||
Just inherit from `cellular_automaton.rule:Rule` and define the evolution rule and initial state.
|
Just inherit from `cellular_automaton.rule:Rule` and define the evolution rule and initial state.
|
||||||
|
|
||||||
## Visualisation
|
## Visualisation
|
||||||
The module provides a pygame window for common two dimensional.
|
The package provides a module for visualization in a pygame window for common two dimensional automatons.
|
||||||
To add another kind of display option e.g. for other dimensions or hexagonal grids you can extrend the provided implementation or build you own.
|
|
||||||
|
To add another kind of display option e.g. for other dimensions or hexagonal grids you can extrend the provided implementation or build your own.
|
||||||
The visual part of this module is fully decoupled and thus should be easily replaceable.
|
The visual part of this module is fully decoupled and thus should be easily replaceable.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
@ -93,3 +94,6 @@ Those two example automaton implementations should provide a good start for your
|
|||||||
## Dependencies
|
## Dependencies
|
||||||
As mentioned above the module depends on [pygame](https://www.pygame.org/news) for visualisation.
|
As mentioned above the module depends on [pygame](https://www.pygame.org/news) for visualisation.
|
||||||
This is the only dependency however.
|
This is the only dependency however.
|
||||||
|
|
||||||
|
## Licence
|
||||||
|
This package is distributed under the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0), see [LICENSE](./LICENSE.txt)
|
@ -21,14 +21,20 @@ from ctypes import c_int
|
|||||||
|
|
||||||
|
|
||||||
class CellularAutomatonProcessor:
|
class CellularAutomatonProcessor:
|
||||||
|
""" This class is responsible for the evolution of the cells. """
|
||||||
|
|
||||||
def __init__(self, cellular_automaton):
|
def __init__(self, cellular_automaton):
|
||||||
self._ca = cellular_automaton
|
self._ca = cellular_automaton
|
||||||
|
|
||||||
def evolve_x_times(self, x):
|
def evolve_x_times(self, x):
|
||||||
|
""" Evolve all cells x times.
|
||||||
|
:param x: The number of evolution steps processed with the call of this method.
|
||||||
|
"""
|
||||||
for x in range(x):
|
for x in range(x):
|
||||||
self.evolve()
|
self.evolve()
|
||||||
|
|
||||||
def evolve(self):
|
def evolve(self):
|
||||||
|
""" Evolve all cells """
|
||||||
self._ca.current_evolution_step += 1
|
self._ca.current_evolution_step += 1
|
||||||
i = self._ca.current_evolution_step
|
i = self._ca.current_evolution_step
|
||||||
r = self._ca.evolution_rule.evolve_cell
|
r = self._ca.evolution_rule.evolve_cell
|
||||||
@ -48,6 +54,14 @@ class CellularAutomatonProcessor:
|
|||||||
|
|
||||||
|
|
||||||
class CellularAutomatonMultiProcessor(CellularAutomatonProcessor):
|
class CellularAutomatonMultiProcessor(CellularAutomatonProcessor):
|
||||||
|
""" This is a variant of CellularAutomatonProcessor that uses multi processing.
|
||||||
|
The evolution of the cells will be outsourced to new processes.
|
||||||
|
|
||||||
|
WARNING:
|
||||||
|
This variant has high memory use!
|
||||||
|
The inter process communication overhead can make this variant slower than single processing!
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, cellular_automaton, process_count: int = 2):
|
def __init__(self, cellular_automaton, process_count: int = 2):
|
||||||
multiprocessing.freeze_support()
|
multiprocessing.freeze_support()
|
||||||
if process_count < 1:
|
if process_count < 1:
|
||||||
@ -57,9 +71,9 @@ class CellularAutomatonMultiProcessor(CellularAutomatonProcessor):
|
|||||||
|
|
||||||
self.evolve_range = range(len(self._ca.cells))
|
self.evolve_range = range(len(self._ca.cells))
|
||||||
self._ca.current_evolution_step = RawValue(c_int, self._ca.current_evolution_step)
|
self._ca.current_evolution_step = RawValue(c_int, self._ca.current_evolution_step)
|
||||||
self.__init_processes_and_clean_cell_instances(process_count)
|
self.__init_processes(process_count)
|
||||||
|
|
||||||
def __init_processes_and_clean_cell_instances(self, process_count):
|
def __init_processes(self, process_count):
|
||||||
self.pool = multiprocessing.Pool(processes=process_count,
|
self.pool = multiprocessing.Pool(processes=process_count,
|
||||||
initializer=_init_process,
|
initializer=_init_process,
|
||||||
initargs=(tuple(self._ca.cells.values()),
|
initargs=(tuple(self._ca.cells.values()),
|
||||||
|
@ -23,22 +23,31 @@ class Cell:
|
|||||||
self._neighbor_states = neighbors
|
self._neighbor_states = neighbors
|
||||||
|
|
||||||
def is_set_for_redraw(self):
|
def is_set_for_redraw(self):
|
||||||
|
""" Flag indicating a change in the cells state since last call of 'was_redrawn'. """
|
||||||
return self._state.is_set_for_redraw()
|
return self._state.is_set_for_redraw()
|
||||||
|
|
||||||
def was_redrawn(self):
|
def was_redrawn(self):
|
||||||
|
""" Should be called after this cell was drawn to prevent unnecessary redraws. """
|
||||||
self._state.was_redrawn()
|
self._state.was_redrawn()
|
||||||
|
|
||||||
def get_current_state(self, evolution_step):
|
def get_current_state(self, evolution_step):
|
||||||
return self._state.get_state_of_evolution_step(evolution_step)
|
return self._state.get_state_of_evolution_step(evolution_step)
|
||||||
|
|
||||||
def evolve_if_ready(self, rule, evolution_step):
|
def evolve_if_ready(self, rule, evolution_step):
|
||||||
|
""" When there was a change in this cell or one of its neighbours,
|
||||||
|
evolution rule is called and the new state and redraw flag gets set if necessary.
|
||||||
|
If there was a change neighbours will be notified.
|
||||||
|
"""
|
||||||
if self._state.is_active(evolution_step):
|
if self._state.is_active(evolution_step):
|
||||||
new_state = rule(list(self._state.get_state_of_last_evolution_step(evolution_step)),
|
new_state = rule(list(self._state.get_state_of_last_evolution_step(evolution_step)),
|
||||||
[list(n.get_state_of_last_evolution_step(evolution_step)) for n in self._neighbor_states])
|
[list(n.get_state_of_last_evolution_step(evolution_step)) for n in self._neighbor_states])
|
||||||
self.set_new_state_and_activate(new_state, evolution_step)
|
self.__set_new_state_and_consider_activation(new_state, evolution_step)
|
||||||
|
|
||||||
def set_new_state_and_activate(self, new_state: cell_state.CellState, evolution_step):
|
def __set_new_state_and_consider_activation(self, new_state: cell_state.CellState, evolution_step):
|
||||||
changed = self._state.set_state_of_evolution_step(new_state, evolution_step)
|
changed = self._state.set_state_of_evolution_step(new_state, evolution_step)
|
||||||
|
self.__activate_if_necessary(changed, evolution_step)
|
||||||
|
|
||||||
|
def __activate_if_necessary(self, changed, evolution_step):
|
||||||
if changed:
|
if changed:
|
||||||
self._state.set_active_for_next_evolution_step(evolution_step)
|
self._state.set_active_for_next_evolution_step(evolution_step)
|
||||||
for n in self._neighbor_states:
|
for n in self._neighbor_states:
|
||||||
|
@ -35,20 +35,19 @@ class CellState:
|
|||||||
def is_active(self, current_evolution_step):
|
def is_active(self, current_evolution_step):
|
||||||
""" Returns the active status for the requested evolution_step
|
""" Returns the active status for the requested evolution_step
|
||||||
:param current_evolution_step: The evolution_step of interest.
|
:param current_evolution_step: The evolution_step of interest.
|
||||||
:return: True if the cell state is set active for this evolution_step.
|
:return: True if the cell or one of its neighbours changed in the last evolution step.
|
||||||
"""
|
"""
|
||||||
return self._active[self._calculate_slot(current_evolution_step)]
|
return self._active[self._calculate_slot(current_evolution_step)]
|
||||||
|
|
||||||
def set_active_for_next_evolution_step(self, current_evolution_step):
|
def set_active_for_next_evolution_step(self, current_evolution_step):
|
||||||
""" Sets the cell active for the next evolution_step, so it will be evolved.
|
""" Sets the cell active for the next evolution_step, so it will be evolved.
|
||||||
:param current_evolution_step: The current evolution_step index.
|
:param current_evolution_step: The current evolution_step index.
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
self._active[self._calculate_slot(current_evolution_step + 1)] = True
|
self._active[self._calculate_slot(current_evolution_step + 1)] = True
|
||||||
|
|
||||||
def is_set_for_redraw(self):
|
def is_set_for_redraw(self):
|
||||||
""" States if this state should be redrawn.
|
""" States if this state should be redrawn.
|
||||||
:return: True if redraw is needed.
|
:return: True if state changed since last call of 'was_redrawn'.
|
||||||
"""
|
"""
|
||||||
return self._dirty
|
return self._dirty
|
||||||
|
|
||||||
@ -62,7 +61,7 @@ class CellState:
|
|||||||
def get_state_of_evolution_step(self, evolution_step):
|
def get_state_of_evolution_step(self, evolution_step):
|
||||||
""" Returns the state of the evolution_step.
|
""" Returns the state of the evolution_step.
|
||||||
:param evolution_step: Uses the evolution_step index, to differ between concurrent states.
|
:param evolution_step: Uses the evolution_step index, to differ between concurrent states.
|
||||||
:return The state of this evolution_step.
|
:return The state of the requested evolution_step.
|
||||||
"""
|
"""
|
||||||
return self._state_slots[self._calculate_slot(evolution_step)]
|
return self._state_slots[self._calculate_slot(evolution_step)]
|
||||||
|
|
||||||
@ -71,6 +70,7 @@ class CellState:
|
|||||||
:param new_state: The new state to set.
|
:param new_state: The new state to set.
|
||||||
:param evolution_step: The evolution_step index, to differ between concurrent states.
|
:param evolution_step: The evolution_step index, to differ between concurrent states.
|
||||||
:return True if the state really changed.
|
:return True if the state really changed.
|
||||||
|
:raises IndexError: If the state length changed.
|
||||||
"""
|
"""
|
||||||
changed = self._set_new_state_if_valid(new_state, evolution_step)
|
changed = self._set_new_state_if_valid(new_state, evolution_step)
|
||||||
self._dirty |= changed
|
self._dirty |= changed
|
||||||
@ -111,9 +111,8 @@ class CellState:
|
|||||||
|
|
||||||
|
|
||||||
class SynchronousCellState(CellState):
|
class SynchronousCellState(CellState):
|
||||||
"""
|
""" CellState version using shared values for multi processing purpose. """
|
||||||
CellState version using shared values for multi processing purpose.
|
|
||||||
"""
|
|
||||||
def __init__(self, initial_state=(0., ), draw_first_state=True):
|
def __init__(self, initial_state=(0., ), draw_first_state=True):
|
||||||
super().__init__(initial_state, draw_first_state)
|
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._state_slots = [RawArray(c_float, initial_state) for i in range(self.__class__._state_save_slot_count)]
|
||||||
|
@ -33,10 +33,11 @@ class _CASurface:
|
|||||||
return [self.__rect.width / grid_dimension[0], self.__rect.height / grid_dimension[1]]
|
return [self.__rect.width / grid_dimension[0], self.__rect.height / grid_dimension[1]]
|
||||||
|
|
||||||
def redraw_cellular_automaton(self):
|
def redraw_cellular_automaton(self):
|
||||||
update_rectangles = list(self.__cell_redraw_dirty_rectangles())
|
""" Redraws those cells which changed their state since last redraw. """
|
||||||
|
update_rectangles = list(self.__redraw_dirty_cells())
|
||||||
pygame.display.update(update_rectangles)
|
pygame.display.update(update_rectangles)
|
||||||
|
|
||||||
def __cell_redraw_dirty_rectangles(self):
|
def __redraw_dirty_cells(self):
|
||||||
for coordinate, cell in self._cellular_automaton.get_cells().items():
|
for coordinate, cell in self._cellular_automaton.get_cells().items():
|
||||||
if cell.is_set_for_redraw():
|
if cell.is_set_for_redraw():
|
||||||
yield from self.__redraw_cell(cell, coordinate)
|
yield from self.__redraw_cell(cell, coordinate)
|
||||||
|
@ -26,6 +26,8 @@ from .cell_state import CellState, SynchronousCellState
|
|||||||
|
|
||||||
|
|
||||||
class CAFactory:
|
class CAFactory:
|
||||||
|
""" This factory provides an easy way to create cellular automatons with single or multi processing. """
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def make_single_process_cellular_automaton(dimension,
|
def make_single_process_cellular_automaton(dimension,
|
||||||
neighborhood: Neighborhood,
|
neighborhood: Neighborhood,
|
||||||
@ -67,7 +69,7 @@ class CAFactory:
|
|||||||
cells = {}
|
cells = {}
|
||||||
for coordinate, cell_state in cell_states.items():
|
for coordinate, cell_state in cell_states.items():
|
||||||
n_coordinates = neighborhood.calculate_cell_neighbor_coordinates(coordinate, dimension)
|
n_coordinates = neighborhood.calculate_cell_neighbor_coordinates(coordinate, dimension)
|
||||||
neighbor_states = [cell_states[tuple(nc)] for nc in n_coordinates]
|
neighbor_states = tuple([cell_states[tuple(nc)] for nc in n_coordinates])
|
||||||
cells[coordinate] = Cell(cell_state, neighbor_states)
|
cells[coordinate] = Cell(cell_state, neighbor_states)
|
||||||
return cells
|
return cells
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ class Neighborhood:
|
|||||||
self.__grid_dimensions = grid_dimensions
|
self.__grid_dimensions = grid_dimensions
|
||||||
return list(self.__neighbors_generator(cell_coordinate))
|
return list(self.__neighbors_generator(cell_coordinate))
|
||||||
|
|
||||||
def get_neighbor_id_from_rel(self, rel_coordinate):
|
def get_id_of_neighbor_from_relative_coordinate(self, rel_coordinate):
|
||||||
return self._rel_neighbors.index(rel_coordinate)
|
return self._rel_neighbors.index(rel_coordinate)
|
||||||
|
|
||||||
def __neighbors_generator(self, cell_coordinate):
|
def __neighbors_generator(self, cell_coordinate):
|
||||||
@ -70,12 +70,45 @@ class Neighborhood:
|
|||||||
|
|
||||||
|
|
||||||
class MooreNeighborhood(Neighborhood):
|
class MooreNeighborhood(Neighborhood):
|
||||||
|
""" Defines a Moore neighborhood:
|
||||||
|
Moore defined a neighborhood with a radius applied on a the non euclidean distance to other cells in the grid.
|
||||||
|
Example:
|
||||||
|
Moor neighborhood in 2 dimensions with radius 1 and 2
|
||||||
|
C = cell of interest
|
||||||
|
N = neighbour of cell
|
||||||
|
X = no neighbour of cell
|
||||||
|
|
||||||
|
Radius 1 Radius 2
|
||||||
|
X X X X X N N N N N
|
||||||
|
X N N N X N N N N N
|
||||||
|
X N C N X N N C N N
|
||||||
|
X N N N X N N N N N
|
||||||
|
X X X X X N N N N N
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, edge_rule: EdgeRule = EdgeRule.IGNORE_EDGE_CELLS, range_=1, dimension=2):
|
def __init__(self, edge_rule: EdgeRule = EdgeRule.IGNORE_EDGE_CELLS, range_=1, dimension=2):
|
||||||
super().__init__(tuple(_rel_neighbor_generator(dimension, range_, lambda rel_n: True)),
|
super().__init__(tuple(_rel_neighbor_generator(dimension, range_, lambda rel_n: True)),
|
||||||
edge_rule)
|
edge_rule)
|
||||||
|
|
||||||
|
|
||||||
class VonNeumannNeighborhood(Neighborhood):
|
class VonNeumannNeighborhood(Neighborhood):
|
||||||
|
""" Defines a Von Neumann neighborhood:
|
||||||
|
Von Neumann defined a neighborhood with a radius applied to Manhatten distance
|
||||||
|
(steps between cells without diagonal movement).
|
||||||
|
Example:
|
||||||
|
Von Neumann neighborhood in 2 dimensions with radius 1 and 2
|
||||||
|
C = cell of interest
|
||||||
|
N = neighbour of cell
|
||||||
|
X = no neighbour of cell
|
||||||
|
|
||||||
|
Radius 1 Radius 2
|
||||||
|
X X X X X X X N X X
|
||||||
|
X X N X X X N N N X
|
||||||
|
X N C N X N N C N N
|
||||||
|
X X N X X X N N N X
|
||||||
|
X X X X X X X N X X
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, edge_rule: EdgeRule = EdgeRule.IGNORE_EDGE_CELLS, range_=1, dimension=2):
|
def __init__(self, edge_rule: EdgeRule = EdgeRule.IGNORE_EDGE_CELLS, range_=1, dimension=2):
|
||||||
self.range_ = range_
|
self.range_ = range_
|
||||||
super().__init__(tuple(_rel_neighbor_generator(dimension, range_, self.neighbor_rule)),
|
super().__init__(tuple(_rel_neighbor_generator(dimension, range_, self.neighbor_rule)),
|
||||||
|
@ -20,30 +20,36 @@ from . import neighborhood
|
|||||||
|
|
||||||
|
|
||||||
class Rule:
|
class Rule:
|
||||||
|
""" Base class for evolution rules.
|
||||||
|
This class has to be inherited if the cellular automaton is supposed to have any effect.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, neighborhood_: neighborhood.Neighborhood):
|
def __init__(self, neighborhood_: neighborhood.Neighborhood):
|
||||||
self._neighborhood = neighborhood_
|
self._neighborhood = neighborhood_
|
||||||
|
|
||||||
def _get_neighbor_by_relative_coordinate(self, neighbours, rel_coordinate):
|
def _get_neighbor_by_relative_coordinate(self, neighbours, rel_coordinate):
|
||||||
return neighbours[self._neighborhood.get_neighbor_id_from_rel(rel_coordinate)]
|
return neighbours[self._neighborhood.get_id_of_neighbor_from_relative_coordinate(rel_coordinate)]
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def evolve_cell(self, last_cell_state, neighbors_last_states):
|
def evolve_cell(self, last_cell_state, neighbors_last_states):
|
||||||
""" Calculates and sets new state of 'cell'.
|
""" Calculates and sets new state of 'cell'.
|
||||||
:param last_cell_state: The cells current state to calculate new state for.
|
A cells evolution will only be called if it or at least one of its neighbors has changed last evolution_step.
|
||||||
|
:param last_cell_state: The cells state previous to the evolution step.
|
||||||
:param neighbors_last_states: The cells neighbors current states.
|
:param neighbors_last_states: The cells neighbors current states.
|
||||||
:return: New state.
|
:return: New state. The state after this evolution step
|
||||||
A cells evolution will only be called if it or at least one of its neighbors has changed last evolution_step cycle.
|
|
||||||
"""
|
"""
|
||||||
return last_cell_state
|
return last_cell_state
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def init_state(self, cell_coordinate):
|
def init_state(self, cell_coordinate):
|
||||||
""" Set the initial state for the cell with the given coordinate.
|
""" Will be called to initialize a cells state.
|
||||||
:param cell_coordinate: Cells coordinate.
|
:param cell_coordinate: Cells coordinate.
|
||||||
:return: Iterable that represents the state
|
:return: Iterable that represents the initial cell state
|
||||||
|
Has to be compatible with 'multiprocessing.sharedctype.RawArray' when using multi processing.
|
||||||
"""
|
"""
|
||||||
return [0]
|
return [0]
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def get_state_draw_color(self, current_state):
|
def get_state_draw_color(self, current_state):
|
||||||
|
""" Return the draw color for the current state """
|
||||||
return [0, 0, 0]
|
return [0, 0, 0]
|
||||||
|
@ -18,6 +18,8 @@ from . import Rule
|
|||||||
|
|
||||||
|
|
||||||
class CellularAutomatonState:
|
class CellularAutomatonState:
|
||||||
|
""" Holds all relevant information about the cellular automaton """
|
||||||
|
|
||||||
def __init__(self, cells, dimension, evolution_rule: Rule):
|
def __init__(self, cells, dimension, evolution_rule: Rule):
|
||||||
self.cells = cells
|
self.cells = cells
|
||||||
self.dimension = dimension
|
self.dimension = dimension
|
||||||
|
@ -1,4 +1,19 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Copyright 2019 Richard Feistenauer
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
"""
|
||||||
|
|
||||||
import random
|
import random
|
||||||
from cellular_automaton import *
|
from cellular_automaton import *
|
||||||
@ -8,7 +23,7 @@ ALIVE = [1.0]
|
|||||||
DEAD = [0]
|
DEAD = [0]
|
||||||
|
|
||||||
|
|
||||||
class TestRule(Rule):
|
class ConwaysRule(Rule):
|
||||||
random_seed = random.seed(13)
|
random_seed = random.seed(13)
|
||||||
|
|
||||||
def init_state(self, cell_coordinate):
|
def init_state(self, cell_coordinate):
|
||||||
@ -45,6 +60,6 @@ if __name__ == "__main__":
|
|||||||
neighborhood = MooreNeighborhood(EdgeRule.FIRST_AND_LAST_CELL_OF_DIMENSION_ARE_NEIGHBORS)
|
neighborhood = MooreNeighborhood(EdgeRule.FIRST_AND_LAST_CELL_OF_DIMENSION_ARE_NEIGHBORS)
|
||||||
ca = CAFactory.make_multi_process_cellular_automaton(dimension=[100, 100],
|
ca = CAFactory.make_multi_process_cellular_automaton(dimension=[100, 100],
|
||||||
neighborhood=neighborhood,
|
neighborhood=neighborhood,
|
||||||
rule=TestRule,
|
rule=ConwaysRule,
|
||||||
processes=4)
|
processes=4)
|
||||||
ca_window = CAWindow(cellular_automaton=ca, evolution_steps_per_draw=1)
|
ca_window = CAWindow(cellular_automaton=ca, evolution_steps_per_draw=1)
|
||||||
|
@ -1,10 +1,26 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Copyright 2019 Richard Feistenauer
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
"""
|
||||||
|
|
||||||
import random
|
import random
|
||||||
from cellular_automaton import *
|
from cellular_automaton import *
|
||||||
|
|
||||||
|
|
||||||
class TestRule(Rule):
|
class StarfallRule(Rule):
|
||||||
|
""" A basic cellular automaton that just copies one neighbour state so get some motion in the grid. """
|
||||||
random_seed = random.seed(1000)
|
random_seed = random.seed(1000)
|
||||||
|
|
||||||
def init_state(self, cell_coordinate):
|
def init_state(self, cell_coordinate):
|
||||||
@ -23,5 +39,5 @@ if __name__ == "__main__":
|
|||||||
neighborhood = MooreNeighborhood(EdgeRule.FIRST_AND_LAST_CELL_OF_DIMENSION_ARE_NEIGHBORS)
|
neighborhood = MooreNeighborhood(EdgeRule.FIRST_AND_LAST_CELL_OF_DIMENSION_ARE_NEIGHBORS)
|
||||||
ca = CAFactory.make_single_process_cellular_automaton(dimension=[100, 100],
|
ca = CAFactory.make_single_process_cellular_automaton(dimension=[100, 100],
|
||||||
neighborhood=neighborhood,
|
neighborhood=neighborhood,
|
||||||
rule=TestRule)
|
rule=StarfallRule)
|
||||||
ca_window = CAWindow(cellular_automaton=ca, evolution_steps_per_draw=1)
|
ca_window = CAWindow(cellular_automaton=ca, evolution_steps_per_draw=1)
|
||||||
|
Loading…
Reference in New Issue
Block a user