Essa classe foi criada para executar o [[http://www.math.com/students/wonders/life/life.html|Game of Life]] em uma matriz de 0s e 1s, onde 1 representa uma célula "viva". Já existe código para o Game of Life em Python (bem, em qualquer linguagem que você pensar, pois é um problema matemático clássico) mas eu estou querendo desenvolver por conta própria e ver quão longe eu chego, principalmente em termos de desempenho e funcionalidade. Estou usando essa classe para implementar uma [[http://www20.brinkster.com/rodviking/game.gif|versão gráfica]] do Life usando PyQt e Numarray. Caso tenha interesse nesse código também, contate-me através do link no fim da página :) Por enquanto o código não está otimizado pois meu enfoque é primeiro ter meu programa funcionando pra depois melhorar o desempenho (que está razoável), mas estou aberto a sugestões, em especial nos métodos "applyRules" e "countNeighbours" que é onde estão os "gargalos". Em breve essa classe também irá suportar o carregamento de arquivos de "pattern" (extensão .lif), que inclui regras dinâmicas. == Código == {{{ #!python from numarray import * class LifeGame: def __init__(self, rule=None): """ Rule is a string with the format ss/dd where ss are digits in 1..8 representing how many neighbours a cell must have to stay alive, and dd are digits in 1..8 representing how many neighbours a dead cell must have to become alive. For example, the default conway rule (which is used if no string is passed as parameter) is "23/3", which means a cell stay alive if it has 2 or 3 neighbours, and becomes alive if it has 3 neighbours. """ if not rule: #if not rule is passed, # use the default one self.rule = "23/3" else: self.rule = rule def countNeighbours (self, row, col): """ countNeighbours (row, col) Returns a number between 0 and 8, counting how many 'living' neighbours (=1) a cell specified by x,y has. """ total = 0 #count the living neighbours (=1) on the #row above if row > 0: total += self.world[row-1, col] if col > 0: total += self.world[row-1, col-1] if col < self.num_cols - 1: total += self.world[row-1, col+1] #count the living neighbours on the left #and right if col > 0: total += self.world[row, col-1] if col < self.num_cols - 1: total += self.world[row, col+1] #count the living neighbours on the row #below if row < self.num_rows - 1: total += self.world[row+1, col] if col > 0: total += self.world[row+1, col-1] if col < self.num_cols - 1: total += self.world[row+1, col+1] return total def resizeGrid (self, world, rows, cols, centralizeData=True): """ resizeGrid (world, rows, cols, centralizeData=True) Resize the matrix passed on 'world'. If the new values of 'rows' and 'cols' are smaller than the current matrix, the matrix is trimmed down starting from the last rows and columns. If centralizeData=True, any eventual data present in the matrix will be placed centralized in the new matrix, for example [[1,1], [1,1]] when resized to 4 rows and cols would become [[0,0,0,0], [0,1,1,0], [0,1,1,0], [0,0,0,0]] this method is used for example to "zoom in" and "zoom out" the matrix on graphical clients. """ num_rows = len(world) num_cols = len(world[0]) new_world = zeros([rows, cols]) #if it's centered, calculates the row/col #offset to be used row_offset = 0 col_offset = 0 if centralizeData and rows > num_rows: row_offset = (rows/2) - (num_rows/2) if centralizeData and cols > num_cols: col_offset = (cols/2) - (num_cols/2) #copy the data for row in range(num_rows): for col in range(num_cols): if (row+row_offset) < len(new_world) \ and (col+col_offset) < len(new_world[0]): new_world[row+row_offset, \ col+col_offset] = \ world[row, col] return new_world def playLife (self, world, debug=False): """ playLife (world, debug=False) This is the main method for the class. It will return a matrix which is the result of the game rules (defined by rule attribute) applied on the 'world' matrix. If debug=True, the resulting matrix is also printed on the console. """ self.world = world self.num_rows = len(world) self.num_cols = len(world[0]) if debug: print "Original grid:" print world result = zeros([self.num_rows, self.num_cols]) for row in range(self.num_rows): for col in range(self.num_cols): result [row, col] = \ self.applyRules(row, col) if debug: print "Result grid:" print result return result def applyRules (self, row, col): """ applyRules (row, col) Apply the rule defined on self.rule for the cell(row,col) in the matrix self.world. This method is usually not called directly, but called through playLife. """ survival_rule = [int(c) for c in \ self.rule[:self.rule.find("/")]] birth_rule = [int(c) for c in \ self.rule[self.rule.find("/")+1:]] cell = 0 sum_neighb = self.countNeighbours(row,col) if self.world[row,col] == 1: if sum_neighb in survival_rule: cell = 1 else: if sum_neighb in birth_rule: cell = 1 return cell if __name__ == '__main__': #initialize grids testworld = array([[1, 0, 1, 0, 0, 0, 0, 0], [0, 1, 1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]]) #play Life! lg = LifeGame() for i in range(1,5): print "-" * 20 print "Iteration", i testworld = lg.playLife(testworld, True) print "-" * 20 print """This test matrix had a glider on the top corner, that moved print "down and right after 4 iterations, as you'd expect a glider to do :)""" }}} Volta para CookBook. ---- RodrigoVieira