To learn python, I've been trying to write a simple graphics program which displays a 1D cellular automaton's evolution. The last time I wrote this program, it was in C for a CGA adaptor (!) in which the display was mapped to two interlaced blocks of memory, and scrolling up two lines of pixels was very simple and very smooth. The code below works, and uses pygame for the graphics. But the scrolling is quite flickery when using large windows. I'm sure that the code contains various neophyte python errors, and I'd appreciate any comments on that, but my main question is how I ought to have coded it in order to have the scrolling be smooth. I did see a comment on a pygame site saying that pygrame should not be used for side-scrollers, to which this is similar. Is there a better way with python?
p.s. It can be run without any args and will select an interesting rule. To change resolution to see the flickering get worse, change HEIGHT and WIDTH. # Simple 1D Cellular Automaton # # The world is a line of cells in which each cell has a state of 0 - 3 # The states change according to a rule that specifies a new state as a function # of the sum of a cell's state and those of its nearest neighbors # Since the sum can be between 0 = 0+0+0 and 9 = 3+3+3, the rule can be represented # by an array of 10 integers, each between 0 and 3. # # To represent this graphically, each state will correspond to a color on a row # of window. # # The first generation is initialized to have a single 1 in the middle of the bottom row # When a new generation is computed, the preceding generations will be scrolled up and the # new generation displayed on the bottom line. import pygame from pygame.locals import * import numpy import sys #import pdb WIDTH = 300 #width of screen HEIGHT = 300 #height of screen MIDDLE = WIDTH/2 COLORS = [ 0x000000, 0xFF0000, 0x00FF00, 0x0000FF ] COLORNUM = {} for i in range(len(COLORS)): COLORNUM[ COLORS[i]] = i #pdb.set_trace() pygame.surfarray.use_arraytype ('numpy') def main(): # Default to an interesting rule if none is given if len(sys.argv) < 2: rule_string = "0322301013" else: rule_string = sys.argv[1] # assume it's there rule = [ COLORS[int(d)] for d in rule_string ] pygame.display.init() screen = pygame.display.set_mode((WIDTH,HEIGHT),DOUBLEBUF) pixels = pygame.surfarray.pixels2d(screen) max_width = len(pixels)-1 max_height = len(pixels[0])-1 pixels[MIDDLE,-1] = COLORS[1] trpix = numpy.transpose( pixels ) old = trpix[-1] while True: new = numpy.zeros( max_width + 1) # Note wrap-around allows us to avoid having 0 be a special case for i in range(0, max_width): new[i] = rule [COLORNUM[ old[i-1] ] + COLORNUM[ old[i] ] + COLORNUM[ old[i+1] ]] new[max_width] = rule[COLORNUM[ old[max_width-1] ] + COLORNUM[ old[max_width] ] + COLORNUM[ old[0] ]] # Exit if 'q' is pressed for e in pygame.event.get(): if e.type == KEYDOWN: if e.key == K_q: exit(0) # Scroll and update the bottom row. Note that we don't have to assign # pixels to be transpose(trpix). trpix[0:-1] = trpix[1:] trpix[-1] = new pygame.display.update() main() -- http://mail.python.org/mailman/listinfo/python-list