Created
December 13, 2010 03:38
-
-
Save lonnen/738622 to your computer and use it in GitHub Desktop.
Processing.py demo of 1D Cellular Automata
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'''ca.py | |
Wolfram Cellular Automata by Chris Lonnen | |
Demonstration of Processing.py features (in both the traditional and Microsoft | |
sense) in the form of a Wolfram 1-dimensional cellular automata. | |
Compare to Shiffman's pure Processing implementation: | |
http://processing.org/learning/topics/wolfram.html | |
''' | |
# like a Python script, this executes first | |
# Python print statements are used instead of Processing println | |
print __doc__ | |
# init global state | |
ca = None | |
def setup(): | |
size(640, 360, P2D) | |
frameRate(30) | |
background(0) | |
ruleset = [0,1,0,1,1,0,1,0] | |
# Processing relies on muddying the global namespace between | |
# setup() and draw(), so the global keyword is needed | |
global ca | |
ca = CA(ruleset) | |
def draw(): | |
global ca | |
ca.render() | |
ca.generate() | |
if ca.finished(): | |
background(0) | |
ca.randomize() | |
ca.restart() | |
def mousePressed(): | |
# It handles mouse events! | |
background(0) | |
ca.randomize() | |
ca.restart() | |
class CA(object): | |
'''A Cellular Automata Python class with Processing keywords and methods. | |
This is a Python class, so the self keyword appears a lot here. | |
Like the parent.method() annoyances of Processing-Java alchemy, this | |
is an implementation quirk you'll need to be aware of if you write | |
your own classes.''' | |
def __init__(self, ruleset=None, scale=1): | |
if ruleset: | |
self.set_rules(ruleset) | |
else: | |
self.randomize() | |
self.scale = scale | |
self.cells = [0] * (width / self.scale) | |
self.restart() | |
def set_rules(self, ruleset): | |
'''Set the rules of the CA, and print them to screen''' | |
# Python builtins! | |
rules = [(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0), | |
(1, 0, 1), (1, 1, 0), (1, 1, 1)] | |
self.rules = dict(zip(rules,ruleset)) | |
print self.rules | |
def randomize(self): | |
'''Make a random ruleset''' | |
# mixing processing functions and list comprehensions | |
r = [int(random(2)) for x in range(8)] | |
self.set_rules(r) | |
def restart(self): | |
'''Reset to generation 0''' | |
# map() and lambda! oh my! | |
self.cells = map(lambda k: 0, self.cells) | |
self.generation = 0 | |
self.cells[len(self.cells)/2] = 1 | |
def generate(self): | |
'''The process of creating the new generation''' | |
# directish reimplementation! | |
# be aware of the difference between range and a java-like for loop! | |
# also, that this is recreating i = 1; i < cells.length-1 | |
nextgen = [0] * len(self.cells) | |
for i in range(len(self.cells)-2): | |
left = self.cells[i] | |
me = self.cells[i+1] | |
right = self.cells[i+2] | |
nextgen[i] = self.rules[(left,me,right)] | |
self.cells = list(nextgen) # copy | |
self.generation += 1 | |
def render(self): | |
'''Render the one line CA''' | |
# list comprehensions with Python builtins! | |
[self.render_cell(x) for x in zip(range(len(self.cells)), self.cells)] | |
def render_cell(self, packedCell): | |
'''Paint a tuple(position, cell value)''' | |
# contrived tuple unpacking example! | |
xpos, value = packedCell | |
if value: | |
fill(255) | |
else: | |
fill(0) | |
noStroke() | |
rect(xpos*self.scale, self.generation*self.scale, self.scale, self.scale) | |
def finished(self): | |
'''The CA is done if it reaches the bottom of the screen''' | |
return (self.generation > (height / self.scale)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment