PYTHON   4

# GameBoard3.py

Guest on 6th June 2021 05:03:11 PM

1. # GameBoard3.py
2.
3. from Organism import Organism
4.
5. #   The following is a constant list used for driving
6. #   an interator around a particular element (in clockwise
7. #   order starting from the upper left. Each member of the
8. #   list is the relative offset from the particular element.
9. _neighbors = [(-1, -1), (-1, 0), (-1, 1), (0, 1), (1, 1),
10.              (1, 0), (1, -1), (0, -1)]
11.
12. ##class Neighborhood:
13. ##    #   This is for iterating thru the nearest neighbors
14. ##    #   of an organism on a Board (defined below)
15. ##
16. ##    def __init__(self, row, col):
17. ##        self._n = 0
18. ##        self._row = row
19. ##        self._col = col
20. ##        return
21. ##
22. ##    def __iter__(self):
23. ##        return self
24. ##
25. ##    def __next__(self):
26. ##        #   The following are for debugging
27. ##        n = self._n
28. ##        row = self._row
29. ##        col = self._col
30. ##
31. ##        if self._n >= len(_neighbors):
32. ##            raise StopIteration     # end of neighborhood
33. ##        (nRow, nCol) = neighbors[self._n]
34. ##        self._n += 1
35. ##        return (self._row + nRow, self._col + nCol)
36.
37.
38.
39. class Board:
40.     """ A board comprises a sparse two-dimendional array of
41.    organisms. Initially, it is centered (approximately) at
42.    row zero and column zero, but it can grow and/or shift
43.
44.    The sparse 2D array is represented by a dictionary of
45.    dictionaries in Python. The main dictionary contains the
46.    rows, each indexed by its row number.
47.
48.    Each row is, however, a separate dictionary, with the
49.    elements indexed by column number.
50.
51.    The elements in a row dictionary are the organisms in the
52.    Game of Life. In the current implementation, they simply
53.    have the value 1.
54.
55.    """
56.
57.     def __init__(self, initSource):
58.         self._Rows = {}
59.         self._minRow, self._maxRow = 0, 0
60.         self._minCol, self._maxCol = 0, 0
61.
62.         if type(initSource) == type(['oxx', 'xx', 'ox']):
63.             self._initFromFile(initSource)
64.         elif type(initSource) == type(self):
65.             self._initFromBoard(initSource)
66.         else:
67.             raise TypeError
68.         return
69.
70.     def _addOrganism(self, row, col, org=None):
71.         #   This function adds an organism to the row and column of the board
72.         #   If the org argument is not supplied, a new organism is created.
73.         #   Otherwise, the organism passed as the org argument is linked to
74.         #   the row and column.
75.         #   If there is an organism already at the row and column, nothing
76.         #   is done.
77.         if row not in self._Rows:
78.             self._Rows[row] = {}    #add a new row
79.         if col not in self._Rows[row]:
80.             if org is None:
81.                 org = Organism(row, col)
82.             self._Rows[row][col] = org
83.
84.         #   Update maximum and minimum row and column
85.         if row < self._minRow:
86.             self._minRow = row
87.         if row > self._maxRow:
88.             self._maxRow = row
89.         if col < self._minCol:
90.             self._minCol = col
91.         if col > self._maxCol:
92.             self._maxCol = col
93.         return
94.
95.     def _initFromFile(self, listOfStrings):
96.         #   Set up local variables because IDLE debugger
97.         #   does not show instance variables of a object
98.         maxLen = 0
99.         #get maximum length of input strings
100.         numberOfRows = len(listOfStrings)
101.         for r in range(numberOfRows):
102.             if len(listOfStrings[r]) > maxLen:
103.                 maxLen = len(listOfStrings[r])
104.
105.         xOffset, yOffset = maxLen//2, numberOfRows//2
106.
107.         for i in range(numberOfRows):
108.             row = i - yOffset
109.             for j in range(len(listOfStrings[i])):
110.                 if listOfStrings[i][j] == 'x':
111.                     col = j - xOffset
112.                     self._addOrganism(row, col)
113.         return
114.
115.     def _initFromBoard(self, prevBoard):
116.         self._minRow = prevBoard._maxRow    #   initialize minRow, maxRow,
117.         self._maxRow = prevBoard._minRow    #   minCol, and maxCol to absurd
118.         self._minCol = prevBoard._maxCol    #   values so that they will be
119.         self._maxCol = prevBoard._minCol    #   properly set by _addOrganism
120.
121.         for organism in prevBoard.enumerateOrganisms():
122.             row, column = organism.getCoords()
123.             neighbors = prevBoard.countNeighbors(row, column)
124.             if neighbors == 2 or neighbors == 3:
125.                 #   move existing organism to new board
126.                 self._addOrganism(row, column, organism)
127.
128.             #   Next, look at the surround spaces of prevBoard to see if any
129.             #   of THEM need have exactly three neighbors. If so, add a
130.             #   new organism to this new board. (Note that no new organism can
131.             #   be created that is more than one space away from an existing
132.             #   organism on the previous Board.
133.
134.             for (adjRow, adjCol) in prevBoard.enumerateNeighbors(row, column):
135.                 if prevBoard.countNeighbors(adjRow, adjCol) == 3:
136.                     self._addOrganism(adjRow, adjCol)
137.         return
138.
139.     def enumerateOrganisms(self):
140.         for row in self._Rows:
141.             for column in self._Rows[row]:
142.                 yield self._Rows[row][column]
143.         return
144.
145.     def enumerateNeighbors(self, row, col):
146.         for (nr, nc) in _neighbors:      # neighbors is a global (defined above)
147.                                         # that enumerates the relative
148.                                         # positions of the eight
149.                                         # immediately adjacent cells
150.             nRow, nCol = nr + row, nc + col
151.             yield nRow, nCol
152.         return
153.
154. ##    def __iter__(self):
155. ##        return self
156. ##
157. ##    def __next__(self):
158. ##        return self.enumerateOrganisms()
159.
160.     def organismPresent(self, row, col):
161.         #   This returns true if an organism is at (row, col)
162.         #   of the board and zero if not
163.         if row in self._Rows:
164.             if col in self._Rows[row]:
165.                 return True
166.         return False
167.
168.     def countNeighbors(self, row, col):
169.         count = 0
170.         for (nr, nc) in self.enumerateNeighbors(row, col):
171.             if self.organismPresent(nr, nc):
172.                 count += 1
173.         return count
174.
175.     def minRow(self):
176.         return self._minRow
177.
178.     def maxRow(self):
179.         return self._maxRow
180.
181.     def minCol(self):
182.         return self._minCol
183.
184.     def maxCol(self):
185.         return self._maxCol
186.
187.     def printBoard(self):
188.         for x in range (self._minRow, self._maxRow+1):
189.             for y in range(self._minCol, self._maxCol+1):
190.                 if  self.organismPresent(x, y):
191.                     print("x", sep='', end='')
192.                 else:
193.                     print("o", sep='', end='')
194.             print("")   #   Terminate the printed line
195.         print("MinRow =", self._minRow, ", MaxRow =", self._maxRow,
196.               ", MinCol =", self._minCol, ", MaxCol =", self._maxCol)
197.         print("")       #   Print a blank line at the end
198.         return