associação pythonbrasil[11] django zope/plone planet Início Logado como (Entrar)

Diferenças para "GameOfLifeConway"

Diferenças entre as versões de 5 e 6
Revisão 5e 2004-07-07 16:15:34
Tamanho: 6896
Comentário:
Revisão 6e 2004-08-16 17:57:22
Tamanho: 7108
Comentário:
Deleções são marcadas assim. Adições são marcadas assim.
Linha 21: Linha 21:
        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.
        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.
Linha 32: Linha 35:
            #if not rule is passed, use the default one             #if not rule is passed,
            #
use the default one
Linha 41: Linha 45:
        Returns a number between 0 and 8, counting how many
       
'living' neighbours (=1)
        a cell specified by x,y has.
        Returns a number between 0 and 8, counting
       
how many 'living' neighbours (=1) a cell
        specified by x,y has.
Linha 47: Linha 51:
        #count the living neighbours (=1) on the row above         #count the living neighbours (=1) on the
       #row above
Linha 55: Linha 60:
        #count the living neighbours on the left and right         #count the living neighbours on the left
       #and right
Linha 61: Linha 67:
        #count the living neighbours on the row below         #count the living neighbours on the row
       #below
Linha 70: Linha 77:
    def resizeGrid (self, world, rows, cols, centralizeData=True):
        """
        resizeGrid (world, rows, cols, centralizeData=True)
    def resizeGrid (self, world, rows, cols,
                    
centralizeData=True):
        """
        resizeGrid (world, rows, cols,
                             
centralizeData=True)
Linha 75: Linha 84:
        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
        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
Linha 90: Linha 100:
        this method is used for example to "zoom in" and "zoom
       
out" the matrix on graphical clients.
        this method is used for example to "zoom in"
       
and "zoom out" the matrix on graphical
       
clients.
Linha 97: Linha 108:
        #if it's centered, calculates the row/col offset to be used         #if it's centered, calculates the row/col
       #offset to be used
Linha 108: Linha 120:
                if (row+row_offset) < len(new_world) and \
                   (col+col_offset) < len(new_world[0]):
                    new_world[row+row_offset, col+col_offset] = \
                if (row+row_offset) < len(new_world) \
                 and (col+col_offset) < len(new_world[0]):
                    new_world[row+row_offset, \
                              
col+col_offset] = \
Linha 119: Linha 132:
        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.
        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.
Linha 137: Linha 150:
                result [row, col] = self.applyRules(row, col)                 result [row, col] = \
                    
self.applyRules(row, col)
Linha 149: Linha 163:
        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:]]
        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:]]
Linha 180: Linha 197:
    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"
   print "glider to do :)"                
    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 :)"""

Game of Life, de Conway

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

   1 from numarray import *
   2 
   3 class LifeGame:
   4     def __init__(self, rule=None):
   5         """
   6         Rule is a string with the format ss/dd where
   7         ss are digits in 1..8 representing how many
   8         neighbours a cell must have to stay alive,
   9         and dd are digits in 1..8 representing how
  10         many neighbours a dead cell must have to
  11         become alive.
  12         
  13         For example, the default conway rule (which
  14         is used if no string is passed as parameter)
  15         is "23/3", which means a cell stay alive if
  16         it has 2 or 3 neighbours, and becomes alive
  17         if it has 3 neighbours.
  18         """
  19         if not rule:
  20             #if not rule is passed,
  21             # use the default one
  22             self.rule = "23/3"
  23         else:
  24             self.rule = rule
  25 
  26     def countNeighbours (self, row, col):
  27         """
  28         countNeighbours (row, col)
  29         
  30         Returns a number between 0 and 8, counting
  31         how many 'living' neighbours (=1) a cell
  32         specified by x,y has.
  33         """
  34         total = 0
  35 
  36         #count the living neighbours (=1) on the
  37         #row above
  38         if row > 0:
  39             total += self.world[row-1, col]
  40             if col > 0:
  41                 total += self.world[row-1, col-1]
  42             if col < self.num_cols - 1:
  43                 total += self.world[row-1, col+1]
  44 
  45         #count the living neighbours on the left
  46         #and right
  47         if col > 0:
  48             total += self.world[row, col-1]
  49         if col < self.num_cols - 1:
  50             total += self.world[row, col+1]
  51 
  52         #count the living neighbours on the row
  53         #below
  54         if row < self.num_rows - 1:
  55             total += self.world[row+1, col]
  56             if col > 0:
  57                 total += self.world[row+1, col-1]
  58             if col < self.num_cols - 1:
  59                 total += self.world[row+1, col+1]
  60         return total
  61 
  62     def resizeGrid (self, world, rows, cols,
  63                      centralizeData=True):
  64         """
  65         resizeGrid (world, rows, cols,
  66                               centralizeData=True)        
  67         
  68         Resize the matrix passed on 'world'.
  69         If the new values of 'rows' and 'cols' are
  70         smaller than the current matrix, the matrix
  71         is trimmed down starting from the last rows
  72         and columns.
  73         
  74         If centralizeData=True, any eventual data
  75         present in the matrix will be placed
  76         centralized in the new matrix, for example
  77         [[1,1],
  78          [1,1]]
  79         when resized to 4 rows and cols would become
  80         [[0,0,0,0],
  81          [0,1,1,0],
  82          [0,1,1,0],
  83          [0,0,0,0]]
  84         
  85         this method is used for example to "zoom in"
  86         and "zoom out" the matrix on graphical
  87         clients.
  88         """
  89         num_rows = len(world)
  90         num_cols = len(world[0])
  91         new_world = zeros([rows, cols])
  92 
  93         #if it's centered, calculates the row/col
  94         #offset to be used
  95         row_offset = 0
  96         col_offset = 0
  97         if centralizeData and rows > num_rows:
  98             row_offset = (rows/2) - (num_rows/2)
  99         if centralizeData and cols > num_cols:
 100             col_offset = (cols/2) - (num_cols/2)
 101 
 102         #copy the data
 103         for row in range(num_rows):
 104             for col in range(num_cols):
 105                 if (row+row_offset) < len(new_world) \
 106                  and (col+col_offset) < len(new_world[0]):
 107                     new_world[row+row_offset, \
 108                               col+col_offset] = \
 109                                world[row, col]
 110         return new_world
 111     
 112     def playLife (self, world, debug=False):
 113         """
 114         playLife (world, debug=False)
 115         
 116         This is the main method for the class.
 117         It will return a matrix which is the
 118         result of the game rules  (defined by rule
 119         attribute) applied on the 'world' matrix.
 120         
 121         If debug=True, the resulting matrix is
 122         also printed on the console.
 123         """
 124         self.world = world
 125         self.num_rows = len(world)
 126         self.num_cols = len(world[0])
 127 
 128         if debug:
 129             print "Original grid:"
 130             print world
 131 
 132         result = zeros([self.num_rows, self.num_cols])
 133         for row in range(self.num_rows):
 134             for col in range(self.num_cols):
 135                 result [row, col] = \
 136                     self.applyRules(row, col)
 137 
 138         if debug:
 139             print "Result grid:"
 140             print result
 141         return result
 142 
 143 
 144     def applyRules (self, row, col):
 145         """
 146         applyRules (row, col)
 147         
 148         Apply the rule defined on self.rule for
 149         the cell(row,col) in the matrix self.world.
 150         This method is usually not called directly,
 151         but called through playLife.
 152         """
 153         survival_rule = [int(c) for c in \
 154                   self.rule[:self.rule.find("/")]]
 155         birth_rule = [int(c) for c in \
 156                   self.rule[self.rule.find("/")+1:]]
 157         cell = 0
 158         sum_neighb = self.countNeighbours(row,col)
 159         if self.world[row,col] == 1:
 160             if sum_neighb in survival_rule:
 161                 cell = 1
 162         else:
 163             if sum_neighb in birth_rule:
 164                 cell = 1
 165         return cell
 166 
 167 if __name__ == '__main__':
 168     #initialize grids
 169     testworld  = array([[1, 0, 1, 0, 0, 0, 0, 0],
 170                         [0, 1, 1, 0, 0, 0, 0, 0],
 171                         [0, 1, 0, 0, 0, 0, 0, 0],
 172                         [0, 0, 0, 0, 0, 0, 0, 0],
 173                         [0, 0, 0, 0, 0, 0, 0, 0]])
 174 
 175     #play Life!
 176     lg = LifeGame()
 177     for i in range(1,5):
 178         print "-" * 20
 179         print "Iteration", i
 180         testworld = lg.playLife(testworld, True)
 181     print "-" * 20
 182     print """This test matrix had a glider on the
 183 top corner, that moved print "down and right after
 184 4 iterations, as you'd expect a glider to do :)"""

Volta para CookBook.


RodrigoVieira