#!/usr/bin/env python # life.py ''' Conway's Game of Life ''' import random import itertools import pygame # Set Up pygame.init() colors = pygame.color.THECOLORS ON, OFF = 1, 0 # The Plan: # Put the cells in a dict from {relative location : cell} # That way neighbors can be looked-up easily in a flat list. # # # Helper Functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! def randcolor (lower=40, upper=230): cvals = range(lower, upper) r, g, b = [random.choice(cvals) for i in range(3)] return pygame.Color(r, g, b) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! class Cell (object): def __init__ (self, **kwargs): # defaults self.size = (25, 25) self.oncolor = colors['green'] self.offcolor = colors['black'] self.state = OFF # absolute topleft pixel position. self.position = None # unpack kwargs for k in kwargs: setattr(self, k, kwargs[k]) self._init_default_config() @property def width (self): return self.size[0] @property def height (self): return self.size[1] def _init_default_config (self): self.image = pygame.Surface(self.size) self.image.set_alpha(0) self.rect = self.image.get_rect() if self.state: self.image.fill(self.oncolor) else: self.image.fill(self.offcolor) if hasattr(self, 'position'): self.rect.topleft = self.position def update (self): if self.state: self.image.fill(self.oncolor) self.image.set_alpha(70) else: self.image.fill(self.offcolor) def __repr__ (self): return "" #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! class Grid (object): def __init__ (self, gridsize, cellsize): self.cell_w, self.cell_h = cellsize # cell w, h self.w, self.h = gridsize # grid w, h self.n = self.w * self.h # n cells self.cells = [] # Initial Configuration self._do_init_config() def _do_init_config (self): absx = absy = 0 for i in xrange(self.h): row = [] for j in xrange(self.w): initstate = random.choice([ON,OFF]) nhood = self.get_neighbors(i, j) cell = Cell( nhood = [n for n in nhood], size=(self.cell_w, self.cell_h), position=(absx, absy), state=initstate, history=initstate ) row.append(cell) absx += cell.width self.cells.append(row) absy += cell.height absx = 0 def update (self): newcolor = randcolor() for row in self.cells: for cell in row: cell.history = cell.state # stores previous state cell.update() # sets cell state color states = [ON for (i,j) in cell.nhood if self.cells[i][j].history] score = sum( states ) # set new cell state if score < 4 and score > 1 and cell.history: cell.state = ON elif score == 3 and not cell.history: cell.state = ON cell.oncolor = newcolor else: cell.state = OFF # draw to screen screen.blit(cell.image, cell.position) def get_neighbors (self, x, y): for point in itertools.product(range(-1,2), range(-1,2)): _x, _y = point[0]+x, point[1]+y if (x, y) == (_x, _y): continue _x %= self.w _y %= self.h yield (_x, _y) def __getitem__ (self, i): i, j = divmod(i, self.w) return self.cells[i][j] # ///////////////////////! if __name__ == '__main__': grid = Grid((120, 120), (2,2)) screen = pygame.display.set_mode((grid.w*grid.cell_w, grid.h*grid.cell_h)) clock = pygame.time.Clock() running = True while running: clock.tick(36) for e in pygame.event.get(): if not hasattr(e, 'key'): continue if e.key == pygame.K_q or e.key == pygame.K_ESCAPE: running = False grid.update() #pygame.display.update([cell.rect for cell in grid if cell.state]) pygame.display.flip()