TEXT   5

GameBoard2.py

Guest on 6th June 2021 05:01:57 PM

  1. # GameBoard2.py
  2.  
  3. from LifeDisplay import Organism
  4. import graphics
  5.  
  6. class Board:
  7.     # A board comprises a two-dimensional array, plus a width (
  8.     #   x-dimension) and height(y-dimension).
  9.     #
  10.     # The origin of the array is AT THE CENTER OF THE BOARD. Two members,
  11.     #   xOffset and yOffset, denote the value to add to the x and y
  12.     #   coordinates of a cell to get the column and row number, respectively.
  13.     #
  14.     #   Note that these are update when rows or columns are added or
  15.     #   deleted.
  16.     #
  17.     # Each cell of the array may contain either a reference to an
  18.     #   organism (indicating that it is occupied) or a zero (indicating
  19.     #   that it is not occupied). Each organism knows its own position
  20.     #   in the coordinate system of the window, and it also knows how
  21.     #   to draw or clear itself in that window.
  22.    
  23.     def __init__(self, opt=None, win=None):
  24.         if opt is None:
  25.             # Create an empty board
  26.             self.__w, self.__h = 0, 0   # width and height
  27.             self.__yOffset, self.__xOffset = 0, 0
  28.             self.__array = []
  29.             self.__win = win
  30.             self.__gens = 0
  31.             return
  32.         elif type(opt) is list:
  33.             self.__win = win
  34.             self.initFromStrings(opt, win)
  35.             return
  36.         elif type(opt) is Board:
  37.             self.newGeneration(opt)
  38.         else:
  39.             print("Invalid or unimplemented initialization!")
  40.             return
  41.        
  42.  
  43.     def height(self):
  44.         return self.__h
  45.  
  46.     def width(self):
  47.         return self.__w
  48.  
  49.     def xOffset(self):
  50.         return self.__xOffset
  51.  
  52.     def yOffset(self):
  53.         return self.__yOffset
  54.  
  55.     def generations(self):
  56.         return self.__gens
  57.  
  58.     def empty(self):
  59.         return len(self.__array) == 0
  60.  
  61.     #   The follow method returns one row of the array (for display)
  62.     def row(self, yCoord):
  63.         rowNumber = yCoord - self.__yOffset
  64.         if rowNumber < 0 or rowNumber >= self.__h:
  65.             print("Error: illegal row number!")
  66.             return None
  67.         else:
  68.             return self.__array[rowNumber]
  69.  
  70.     def __eq__(self, other):
  71.         #   Returns true if two boards are identical
  72.         if self.__h != other.__h or self.__w != other.__w or \
  73.            self.__yOffset != other.__yOffset or \
  74.            self.__xOffset != other.__xOffset:
  75.             return False
  76.  
  77.         for i in range(self.__h):
  78.             for j in range(self.__w):
  79.                 if self.__array[i][j] != other.__array[i][j]:
  80.                    return False
  81.         return True
  82.  
  83.     #   The following function  initializes a Game of Life Board
  84.     #   from a list of strings, each string containing 'x' and
  85.     #   'o' characters
  86.  
  87.     #   The height of the board is the number of strings. The
  88.     #   width is the length of the longest string.
  89.  
  90.     def initFromStrings(self, listOfStrings, window = None):
  91.         rows = len(listOfStrings)
  92.         self.__h = rows
  93.         self.__gens = 1
  94.         self.__win = window
  95.  
  96.         #get maximum length of input strings
  97.         maxLen = 0
  98.         for r in range(rows):
  99.             if len(listOfStrings[r]) > maxLen:
  100.                 maxLen = len(listOfStrings[r])
  101.         self.__w = maxLen
  102.  
  103.         #   Set offsets to the middle of the original array
  104.         self.__xOffset, self.__yOffset = maxLen//2, rows//2
  105.  
  106.         # initialize array to __h rows of __w zeros and organisms
  107.         array = []
  108.         for j in range(rows):
  109.             array.append([0] * maxLen)  # a row of zeros
  110.             for i in range(len(listOfStrings[j])):
  111.                 if listOfStrings[j][i] == 'x':
  112.                     newOrganism = Organism(i - self.__xOffset, \
  113.                                            j - self.__yOffset)
  114.                     array[j][i] = newOrganism
  115.                     if self.__win is not None:
  116.                         newOrganism.draw(self.__win)
  117.  
  118.         self.__array = array
  119.         if self.__win is not None:
  120.             self.__win.update()
  121.        
  122.         return
  123.  
  124.     #   The following function returns both the contents of a cell and
  125.     #   the count of occupied neighbors of that cell. The X and Y
  126.     #   coordinates are provided in the window coordinate system (origin
  127.     #   typically at the center), so that the same X and Y values may be
  128.     #   used by both the caller and the callee (which may have different
  129.     #   size arrays). The function returns
  130.     #
  131.     #       cellContents, numberOfOccupiedNeighbors
  132.     #
  133.     #   If the cell does not exist (because X and Y are out of bounds),
  134.     #   cellContents is None. Otherwise it is either zero or a reference
  135.     #   to an Organism.
  136.  
  137.     def getNeighborhood(self, X, Y):
  138.         x, y = X + self.__xOffset, Y + self.__yOffset
  139.         neighbors = 0
  140.         cellContent = None
  141.         for row in [y-1, y, y+1]:
  142.             if (0 <= row < self.__h):
  143.                 for col in [x-1, x, x+1]:
  144.                     if (0 <= col < self.__w):
  145.                         if (y == row and x == col):
  146.                             cellContent = self.__array[row][col]
  147.                         elif type(self.__array[row][col]) is Organism:
  148.                                     neighbors += 1
  149.         return cellContent, neighbors
  150.        
  151.  
  152.  
  153.    
  154. ###   The following function prints out the count of neighbors of
  155. ###   each cell of the board. It is used to test the countNeighbors
  156. ###   method and also to help debug other methods
  157. ##
  158. ##    def printNeighbors(self):
  159. ##        print("The following are the number of occupied neighbors")
  160. ##        print("   of each cell of the board:-")
  161. ##        for v in range(0, self.__h):
  162. ##            print("Row", v, ":-", end=" ")
  163. ##            for u in range (0, self.__w):
  164. ##                cell, neighbors = self.
  165. ##                print(self.countNeighbors(u, v), end= " ")
  166. ##            print("")
  167. ##
  168. #   The following function prints one row of the array
  169.  
  170.     def printRow(self, y):
  171.         if y < 0 or y >= self.__h:
  172.             print("Error:", y, "is an invalid row!")
  173.            
  174.         else:
  175.             for x in range(self.__w):
  176.                 if type(self.__array[y][x]) is Organism:
  177.                     print(1, end=" ")
  178.                 else:
  179.                     print(0, end=" ")
  180.             print()
  181.         return
  182.  
  183. #   The following function prints all of the rows of the array
  184.     def printRows(self):
  185.         h = self.__h
  186.         for n in range(h):
  187.             self.printRow(n)
  188.        
  189.  
  190.  
  191. #   The following function is the principal function of the Game of Life
  192. #   It "plays" one generation by constructing a new board from a
  193. #   previous board. The new board is expanded in each direction to
  194. #   accommodate new pieces off the edge. Later, it is shrunken to
  195. #   account for empty rows or columns at the edges
  196.  
  197.     def newGeneration(self, prev):
  198.         oldWidth, oldHeight = prev.__w, prev.__h
  199.         newWidth, newHeight = oldWidth + 2, oldHeight + 2
  200.         self.__w, self.__h = newWidth, newHeight
  201.         self.__win = prev.__win
  202.         self.__gens = prev.__gens + 1
  203.  
  204.         #   Adjust offsets to reflect the addition of ONE row and
  205.         #   ONE column to the top and left of the array, respectively
  206.         xNewOffset, yNewOffset = prev.__xOffset + 1, prev.__yOffset + 1
  207.         self.__xOffset, self.__yOffset = xNewOffset, yNewOffset
  208.         array = []
  209.  
  210.         #   First, populate the new array with zeros
  211.         for y in range(newHeight):
  212.             array.append([0] * newWidth)    #   array is local (for now)
  213.  
  214. ##        #Debug
  215. ##        print("self.__w. .__h are (a)", self.__w, self.__h)
  216.  
  217.         for y in range(newHeight):
  218.             coordY = y - yNewOffset     #   convert to window coordinates
  219.             for x in range(newWidth):
  220.                 coordX = x - xNewOffset #   convert to window coordinates
  221.                 cell, neighbors = prev.getNeighborhood(coordX, coordY)
  222.  
  223.                 if type(cell) is Organism:
  224.                     if neighbors < 2 or neighbors > 3:
  225.                         #   Organism dies to loneliness or overcrowding
  226.                         array[y][x] = 0
  227.                         cell.undraw()
  228.                     else:
  229.                         array[y][x] = cell   #   Organism survives
  230.  
  231.                 elif neighbors == 3:
  232.                     #   Birth of new organism
  233.                     newOrg = Organism(coordX, coordY)
  234.                     if self.__win is not None:
  235.                         array[y][x] = newOrg
  236.                         newOrg.draw(self.__win)
  237. ##        #Debug
  238. ##        print("self.__w. .__h are (c)", self.__w, self.__h)
  239.  
  240.         self.__array = array
  241.         self.trimEdges()    # trim edges that are all zeros
  242.  
  243. ##        #Debug
  244. ##        print("self.__w. .__h are (c)", self.__w, self.__h)
  245.  
  246.         return
  247.  
  248.  
  249. #   The following function trims the edges of a board when organisms
  250. #   near those edges have died off
  251.            
  252.     def trimEdges(self):
  253.         height = self.__h
  254.         width = self. __w
  255.            
  256.         while height > 0 and self.rowCount(0) == 0:
  257.             self.__array.pop(0)     # remove top row
  258.             height          -= 1    #
  259.             self.__h        = height    
  260.             self.__yOffset  -= 1    # adjust offset to reflect deleted row
  261.  
  262.         while height > 0 and self.rowCount(-1) == 0:
  263.             self.__array.pop()  # remove bottom row
  264.             height -= 1         # adjust height
  265.             self.__h = height
  266.             #   Note: do not adjust offset for bottom row!
  267.  
  268.         while width > 0 and self.columnCount(0) == 0:
  269.             for row in range(height):
  270.                 self.__array[row].pop(0)    #remove left element
  271.             width -= 1              # adjust width
  272.             self.__w = width
  273.             self.__xOffset  -= 1    #   adjust offset for deleted column
  274.  
  275.         while width > 0 and self.columnCount(-1) == 0:
  276.             for row in range(height):
  277.                 self.__array[row].pop()     #remove right element
  278.             width -= 1
  279.             self.__w = width
  280.             #   Do NOT adjust offset for deleted right column!
  281.  
  282.         return
  283.  
  284. #   The following functions count the number of organisms in the row or
  285. #   column (respectively).
  286.  
  287.     def rowCount(self, row):
  288.         count = 0
  289.         for c in range(self.__w):       #   Loop thru rows
  290.             if type(self.__array[row][c]) is Organism:
  291.                 count += 1
  292.         return count
  293.  
  294.     def columnCount(self, col):
  295.         count = 0
  296.         for r in range(self.__h):       #   Loop thru rows
  297.             if type(self.__array[r][col]) is Organism:
  298.                 count += 1
  299.         return count

Raw Paste


Login or Register to edit or fork this paste. It's free.