#!/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. # # #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! class Cell (object): def __init__ (self, **kwargs): self.size = (25, 25) self.oncolor = colors['green'] self.offcolor = colors['black'] self.state = OFF # absolute topleft pixel position. # IE: (25,0), (50,0), (75,0), ... self.position = None # relative position in grid. # IE: (0,0), (1,0), (2,0), ... self.relpos = 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(255) else: self.image.fill(self.offcolor) def __repr__ (self): return "" #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! class Grid (object): def __init__ (self, gridsize, cellsize): self.w, self.h = gridsize # grid w, h self.cw, self.ch = cellsize # cell w, h self.n = self.w * self.h # n cells self.cells = {} # relpos:cell look-up ##### Initial Configuration ##### relx = rely = 0 # relative (x,y) coordinates absx = absy = 0 # absolute pixel coordinates # populate grid, setting positions for i in xrange(self.n): cell = Cell( size=(self.cw, self.ch), position=(absx, absy), relpos=(relx, rely), ) if i % 2 == 0 or i % 5.5 == 0: cell.state = ON # stores previous state cell.history = cell.state # {relpos:cell} self.cells[(relx, rely)] = cell absx += cell.width rely += 1 # wraps coordinate counts to new row if (i + 1) % self.w == 0 and i != 0: absx = 0 relx += 1 absy += cell.height rely = 0 def update (self): for cell in self.cells.itervalues(): cell.history = cell.state # stores previous state cell.update() # sets cell state color x, y = cell.relpos # relative position in grid neighbors = self.get_neighbors(x, y) # sum neighboring history states + self's history state cell.nhood = sum([1 for n in neighbors if self.cells[n].history]) #cell.nhood += cell.history # set new cell state if cell.nhood < 4 and cell.nhood > 1 and cell.history: cell.state = ON elif cell.nhood == 3 and not cell.history: cell.state = ON elif cell.nhood == 4 or cell.nhood < 2 and cell.history: 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 if _x < 0: _x = self.w-1 elif _x == self.w: _x = self.w-1 if _y < 0: _y = self.h-1 elif _y == self.h: _y = self.h-1 yield (_x, _y) def randcolor (self, lower=180, upper=240, alpha=255): cvals = range(lower, upper) r, g, b = [random.choice(cvals) for i in range(3)] return pygame.Color(r, g, b, alpha) # //////////////////////// if __name__ == '__main__': grid = Grid((50, 50), (14,14)) screen = pygame.display.set_mode((grid.w*grid.cw, grid.h*grid.ch)) bg = pygame.Surface(screen.get_size()) clock = pygame.time.Clock() running = True bg.fill((0,0,0)) bg.set_alpha(10) 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 #screen.blit(bg, (0,0)) grid.update() #updaterects = [cell.rect for cell in grid.array if cell.state] #pygame.display.update(updaterects) pygame.display.flip()