r
/
fifth
1
Fork 0

Setup updating of cells in CAM

master
jrpotter 2015-05-31 18:27:47 -04:00
parent f0790de0e3
commit 774cb8243d
2 changed files with 43 additions and 18 deletions

View File

@ -2,35 +2,34 @@
""" """
from bitplane import Bitplane from cell_plane import CellPlane
class CAM: class CAM:
""" """
Represents a Cellular Automata Machine (CAM). Represents a Cellular Automata Machine (CAM).
The CAM consists of any number of bit planes that allow for increasingly complex cellular automata. The CAM consists of any number of cell planes that allow for increasingly complex cellular automata.
This is the top-level module that should be used by anyone wanting to work with fifth, and provides This is the top-level module that should be used by anyone wanting to work with fifth, and provides
all methods needed (i.e. supported) to interact/configure the cellular automata as desired. all methods needed (i.e. supported) to interact/configure the cellular automata as desired.
""" """
def __init__(self, bps=1, dimen=(100,100)): def __init__(self, cps=1, dimen=(100,100)):
""" """
""" """
self._dimen = dimen self._dimen = dimen
self._bitplanes = [BitPlane(dimen) for i in bps] self._planes = [CellPlane(dimen) for i in cps]
self._master = self._bitplanes[0].grid if bps > 0 else None self._master = self._planes[0].grid if cps > 0 else None
def tick(self, ruleset, neighborhood): def tick(self, ruleset, neighborhood, *args):
""" """
The tick function should be called whenever we want to change the current status of the grid. The tick function should be called whenever we want to change the current status of the grid.
Every time the tick is called, the ruleset is applied to each cell and the next configuration Every time the tick is called, the ruleset is applied to each cell and the next configuration
is placed into the master grid. Depending on the timing specifications set by the user, this is placed into the master grid. Depending on the timing specifications set by the user, this
may also change secondary bitplanes (the master is always updated on each tick). may also change secondary cell planes (the master is always updated on each tick).
""" """
pass self._master = ruleset.update(self._master, self.master, neighborhood, *args)

View File

@ -5,6 +5,13 @@
@author: jrpotter @author: jrpotter
@date: May 31st, 2015 @date: May 31st, 2015
""" """
from enum import Enum
class Rule(Enum):
MATCH = 0
TOLERATE = 1
SATISFY = 2
class Ruleset: class Ruleset:
""" """
@ -19,22 +26,22 @@ class Ruleset:
a neighborhood instance's offsets member. a neighborhood instance's offsets member.
""" """
def __init__(self, grid, wrap_around=True): def __init__(self, method, wrap_around=True):
""" """
""" """
self.grid = grid self.method = method
self.wrap_around = wrap_around self.wrap_around = wrap_around
def matches(self, cell, neighborhood): def _matches(self, cell, grid, neighborhood):
""" """
Determines that neighborhood matches expectation exactly. Determines that neighborhood matches expectation exactly.
Note this is just like the tolerate method with a tolerance of 1, but Note this is just like the tolerate method with a tolerance of 1, but
recoding allows for short circuiting. recoding allows for short circuiting.
""" """
residents = neighborhood.neighbors(cell, self.grid, self.wrap_around) residents = neighborhood.neighbors(cell, grid, self.wrap_around)
for resident in residents: for resident in residents:
if resident[0].value != resident[1]: if resident[0].value != resident[1]:
return False return False
@ -42,7 +49,7 @@ class Ruleset:
return True return True
def tolerate(self, cell, neighborhood, tolerance): def _tolerate(self, cell, grid, neighborhood, tolerance):
""" """
Determines that neighborhood matches expectation within tolerance. Determines that neighborhood matches expectation within tolerance.
@ -50,7 +57,7 @@ class Ruleset:
consider this cell to be alive. Note tolerance must be a value 0 <= t <= 1. consider this cell to be alive. Note tolerance must be a value 0 <= t <= 1.
""" """
matches = 0 matches = 0
residents = neighborhood.neighbors(cell, self.grid, self.wrap_around) residents = neighborhood.neighbors(cell, grid, self.wrap_around)
for resident in residents: for resident in residents:
if resident[0].value == resident[1]: if resident[0].value == resident[1]:
matches += 1 matches += 1
@ -58,13 +65,32 @@ class Ruleset:
return (matches / len(residents)) >= tolerance return (matches / len(residents)) >= tolerance
def satisfies(self, cell, neighborhood, valid_func): def _satisfies(self, cell, grid, neighborhood, valid_func):
""" """
Allows custom function to relay next state of given cell. Allows custom function to relay next state of given cell.
The passed function is supplied the list of 2-tuple elements, of which the first is a Cell and the second is The passed function is supplied the list of 2-tuple elements, of which the first is a Cell and the second is
the expected state as declared in the Neighborhood, as well as the grid and cell in question. the expected state as declared in the Neighborhood, as well as the grid and cell in question.
""" """
residents = neighborhood.neighbors(cell, self.grid, self.wrap_around) residents = neighborhood.neighbors(cell, grid, self.wrap_around)
return valid_func(cell, grid, residents)
@np.vectorize
def update(self, cell, *args):
"""
Allow for batch processing of rules.
We choose our processing function based on the specified rule and update every cell in the grid simultaneously
via a vectorization.
"""
if self.method == Rule.MATCH:
cell.value = self._matches(cell, *args)
elif self.method == Rule.TOLERATE:
cell.value = self._tolerate(cell, *args)
elif self.method == Rule.SATISFY:
cell.value = self._satisfy(cell, *args)
return cell
return valid_func(cell, self.grid, residents)