title: Conway's Game of Life using Sparse Matrix (Python)
body: <p>I am writing the game of life in python using a Sparse Matrix. My program takes coordinates from user input and sets the cells at the chosen coordinates to be alive. I have it to where it will print the first generation, but I can't seem to figure out why it wont print any subsequent generations. Any help would be appreciated.</p>
  
  <pre><code>class SparseLifeGrid:
  
  generations = list()
  
  def __init__(self):
      """
      "pass" just allows this to run w/o crashing.
      Replace it with your own code in each method.
      """
      self._mat = list()
      self.col = []
      self.row = []
  
  def minRange(self):
      """
      Return the minimum row &amp; column as a tuple.
      """
      for i in range(len(self.row)):
  
          if self.row[i] &lt; self.minRow:
              self.minRow = self.row[i]
  
          if self.col[i] &lt; self.minCol:
              self.minCol = self.col[i]
  
      min_Range = [self.minRow,self.minCol]
  
      return min_Range
  
  def maxRange(self):
      """
      Returns the maximum row &amp; column as a tuple.
      """
      for i in range(len(self.row)):
  
          if self.row[i] &gt; self.maxRow:
              self.maxRow = self.row[i]
  
          if self.col[i] &gt; self.maxCol:
              self.maxCol = self.col[i]
  
      max_Range = [self.maxRow,self.maxCol]
  
      return max_Range
  
  def configure(self,coordList):
      """
      Set up the initial board position.
      "coordlist" is a list of coordinates to make alive.
      """
     # for i in coordList:
     #     self.setCell(i[0],i[1])
  
      self._mat = list()
      self.coordList = coordList
  
      for i in range(len(self.coordList)):
          spot = self.coordList[i]
          self.row += [spot[0]]
          self.col += [spot[1]]
          self._mat += [[self.row[i],self.col[i]]]
  
      self.maxRow = self.minRow = self.row[0]
      self.maxCol = self.minCol = self.col[0]
  
  
  def clearCell(self,row, col):
      """
      Set the cell to "dead" (False)
      """
      self[row,col] = 0
  
  def setCell(self,row, col):
      """
      Set the cell to "live" (True") and if necessary, expand the
      minimum or maximum range.
      """
      self[row,col] = 1
  
  
  def isLiveCell(self,row,col):
      n = len(self.coordList)
  
      for i in range(n):
  
          if (self._mat[i] == [row,col]):
              return True
  
      return False
  
  
  def numLiveNeighbors(self, row,col):
      """
      Returns the number of live neighbors a cell has.
      """
      neighbors = 0
  
      if self.isLiveCell(row+1,col): #checks below the current cell
          neighbors += 1
  
      if self.isLiveCell(row-1,col): #checks above the current cell
          neighbors += 1
  
      if self.isLiveCell(row,col+1): #checks to the right of the current cell
          neighbors += 1
  
      if self.isLiveCell(row,col-1): #checks to the left of the current cell
          neighbors += 1
  
      if self.isLiveCell(row+1,col+1): #checks downwards diagonally to the right of the current cell
          neighbors += 1
  
      if self.isLiveCell(row+1,col-1): #checks downwards diagonally to the left of the current cell
          neighbors += 1
  
      if self.isLiveCell(row-1,col+1): #checks upwards diagonally to the right of the current cell
          neighbors += 1
  
      if self.isLiveCell(row-1,col-1): #checks upawards diagonally to the left of the current cell
          neighbors += 1
  
      return neighbors
  
  
  def __getitem__(self,ndxTuple):
      row = ndxTuple[0]
      col = ndxTuple[1]
  
      if(self.isLiveCell(row,col)==1):
          return 1
  
      else:
          return 0
  
  def __setitem__(self,ndxTuple, life):
      """
      The possible values are only true or false:
      True says alive, False for dead.
      Also, check to see if this cell is outside of the maximum row and/or
      column. If it is, modify the maximum row and/or maximum column.
      """
      ndx = self._findPosition(ndxTuple[0],ndxTuple[1])
  
      if ndx != None:
  
          if life != True:
              self._mat[ndx].value = life
  
          else:
              self._mat.pop[ndx]
  
      else:
  
          if life != True:
              element = _GoLMatrixElement(ndxTuple[0],ndxTuple[1],life)
              self._mat.append(element)
  
  def _findPosition(self,row,col):
      ''' Does a search through the matrix when given the row&amp;col and
          returns the index of the element if found
      '''
      n = len(self._mat)
  
      for i in range(n):
  
          if (row == self._mat[i]) and (col == self._mat[i]):
              return i
  
      return None
  
  def __str__(self):
      """
      Print a column before and after the live cells
      """
      s=""
      maxRange=self.maxRange()
      minRange=self.minRange()
  
      for i in range(minRange[0]-1,maxRange[0]+2):
          for j in range(minRange[1]-1,maxRange[1]+2):
              s+=" "+str(self[i,j])
          s+="\n"
  
      return s
  
  def getCopy(self):
      """
      Return a copy of the current board object, including the max and min
      values, etc.
      """
      return SparseLifeGrid()
  
  def evolve(self):
      """
      Save the current state to the "generations" list.
      Based on the current generation, return the next generation state.
      """
      self.generations.append(self._mat)
  
      for row in range(len(self.row)):
          for col in range(len(self.col)):
  
              if ((self[row,col] == True) and (self.numLiveNeighbors(row,col) == 2)):
                  self.setCell(row,col)
  
              if ((self[row,col] == True) and (self.numLiveNeighbors(row,col) == 3)):
                  self.setCell(row,col)
  
              if ((self[row,col] == True) and (self.numLiveNeighbors(row,col) &lt; 2)):
                  self.clearCell(row,col)
  
              if ((self[row,col] == True) and (self.numLiveNeighbors(row,col) &gt; 3)):
                  self.clearCell(row,col)
  
              if ((self[row,col] == False) and (self.numLiveNeighbors(row,col) == 3)):
                  self.setCell(row,col)
  
      self.generations.append(self._mat)
      return self._mat
  
  def hasOccurred(self):
      """
      Check whether  this current state has already occured.
      If not, return False.  If true, return which generation number (1-10).
      """
      for i in range(len(self.generations)):
  
          if len(self.generations) &gt; 0:
              print("This is generation",len(self.generations))
              return self.generations[i]
  
          else:
              print("No Generations")
              return False
  
  def __eq__(self,other):
      """
      This is good method if we want to compare two sparse matrices.
      You can just use "sparseMatrixA == sparseMatrixB" once this method
      is working.
      """
      pass
  
  class _GoLMatrixElement:
      """
      Storage class for one cell
      """
      def __init__(self,row,col):
          self.row = row
          self.col = col
          self.next = None  #
          # Since this node exists, this cell is now alive!
          # To kill it, we just delete this node from the lists.
  </code></pre>
  
     
  
  <pre><code>from SparseLifeGrid import SparseLifeGrid
  import sys
  
  def readPoints(lifeGrid):
      """
      Reads the locations of life and set to the SparseMatrix
      """
      print("1. Enter positions of life with row,col format (e.g., 2,3).")
      print("2. Enter empty line to stop.")
  
      life=input()
      coordList=[]
      while life:
          points=life.split(",")
          try:
              coord=[int(points[0]),int(points[1])]
              coordList.append(coord)
          except ValueError:
              print("Ignored input:" + life+ ", row, col not valid numbers")
          except:
              print("Unexpected error:", sys.exc_info()[0])
          print("added, keep entering or enter empty line to stop.")
          life=input()
      print("Thanks, finished entering live cells")
      lifeGrid.configure(coordList)
  
  def main():
      """
      Runs for ten generations if a stable (repeating) state is not found.
      """
      lifeGrid= SparseLifeGrid()
      readPoints(lifeGrid)
      patterns=0
      i=0 
      while i &lt;10 :
          """
          Evolve to the next generation
          """
          lifeGrid.evolve()
          print(lifeGrid)
          """
          Check whether this generation is a repetition of any of the
          previous states.
          If yes return the previous matching generation (1-10).
          """
          patterns=lifeGrid.hasOccurred()
          if patterns != -1:
              break
          i+=1
  
      if i==10:
          print("No pattern found")
      else:
  
          print("Pattern found at: " + str(i)+ " of type: " + str(patterns))
  
  main()
  </code></pre>