patternpythonMinor
Generating a 1D cellular automata in Python
Viewed 0 times
cellulargeneratingautomatapython
Problem
I wrote a program that generates a set of 1D cellular automaton. Basically, it generates this (rule 150):
...and rotates it to form this:
I then introduced an element of randomness to it, so it could form images like this:
I was hoping I could get reviews for the code I have, focusing around how to optimize it and improve its performance. This program feels like it takes a second or two to generate a 511x511 square on my machine, which makes it feel a bit laggy.
Here's the complete code:
``
will be generated.'''
to_int = lambda item : int(''.join([str(ord(x)) for x in str(item)]))
if
...and rotates it to form this:
I then introduced an element of randomness to it, so it could form images like this:
I was hoping I could get reviews for the code I have, focusing around how to optimize it and improve its performance. This program feels like it takes a second or two to generate a 511x511 square on my machine, which makes it feel a bit laggy.
Here's the complete code:
``
#!/usr/bin/env python
'''
Code that will generate a fractal or a pseudo-random fractal
based on an initial seed and any acceptable 1-d cellular automata
algorithm.
'''
import sys
import random
import time
import pygame
class Rules(object):
'''Contains a variety of rules that determines if a cell should turn black
based on the cells in the row above. Each function is namespaced inside
the 'Rules' class for convenience.
'''
@staticmethod
def rule150(above):
'''Colors a cell black if there is an odd number of black cells
above it.'''
return sum(above) in (1, 3)
@staticmethod
def rule150randomized(above):
'''Colors a cell black if there's an odd number of black cells above it
(although this rule will be ignored 0.05% of the time.'''
if sum(above) in (1, 3):
return random.randint(0, 2000) != 0
else:
return False
class Generator(object):
'''An object which generates a single wedge based on an initial seed
and a rule. If the seed is None, a random one will be generated.'''
def __init__(self, seed=None, rule=Rules.rule150):
self.seed = seed
self.rule = rule
def _generate_seed(self, seed=None):
'''Takes a seed and converts it into an integer.
If the seed is None`, a random seed based on system timewill be generated.'''
to_int = lambda item : int(''.join([str(ord(x)) for x in str(item)]))
if
Solution
Warning: this hasn't been rigorously tested (i.e., with a known seed)!
There are a couple of things that can be tried without majorly changing things:
-
Grid.center - you already know what it is on initialisation, so create a normal variable for it and remove the @property version. This avoids calculating it several hundred thousand times.
-
Enumerate over the array/columns when displaying as you do in other places. This will stop you doing an list index that's repeated:
-
The lambdas in Generator.create_grid can be removed (function calls)
-
Changing the rules. rather than doing
All these might give you ~60-65% of the original.
There are a couple of things that can be tried without majorly changing things:
-
Grid.center - you already know what it is on initialisation, so create a normal variable for it and remove the @property version. This avoids calculating it several hundred thousand times.
self.center = (int(x / 2), int(y / 2))-
Enumerate over the array/columns when displaying as you do in other places. This will stop you doing an list index that's repeated:
def render(self, grid):
'''Renders the grid, and prints the current seed to stdout.'''
self.grid = grid
self.surface.fill(self.background)
for x,col in enumerate( grid.array ):
xc = x * self.pixel_size
for y,cell in enumerate( col ):
if cell:
self.surface.blit(
self.ftile,
(xc, y * self.pixel_size)
)
pygame.display.flip()-
The lambdas in Generator.create_grid can be removed (function calls)
xc,yc = grid.center
for index, row in enumerate(self.generate(n)):
raw_x = index
for i, cell in enumerate(row):
if cell:
raw_y = i - index
# Rotates a wedge four times to form a square.
grid.set( xc + raw_x, yc + raw_y )
grid.set( xc - raw_x, yc - raw_y )
grid.set( xc - raw_y, yc + raw_x )
grid.set( xc + raw_y, yc - raw_x )-
Changing the rules. rather than doing
sum(above) in (1,3), why not explicitly state the combinations?black_set = ( [False, False, True], [False, True, False], [True, False, False], [True, True, True] )
...
if above in Rules.black_set:
#etcAll these might give you ~60-65% of the original.
Code Snippets
self.center = (int(x / 2), int(y / 2))def render(self, grid):
'''Renders the grid, and prints the current seed to stdout.'''
self.grid = grid
self.surface.fill(self.background)
for x,col in enumerate( grid.array ):
xc = x * self.pixel_size
for y,cell in enumerate( col ):
if cell:
self.surface.blit(
self.ftile,
(xc, y * self.pixel_size)
)
pygame.display.flip()xc,yc = grid.center
for index, row in enumerate(self.generate(n)):
raw_x = index
for i, cell in enumerate(row):
if cell:
raw_y = i - index
# Rotates a wedge four times to form a square.
grid.set( xc + raw_x, yc + raw_y )
grid.set( xc - raw_x, yc - raw_y )
grid.set( xc - raw_y, yc + raw_x )
grid.set( xc + raw_y, yc - raw_x )black_set = ( [False, False, True], [False, True, False], [True, False, False], [True, True, True] )
...
if above in Rules.black_set:
#etcContext
StackExchange Code Review Q#15304, answer score: 4
Revisions (0)
No revisions yet.