-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcells.py
215 lines (167 loc) · 6.66 KB
/
cells.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
"""
Base classes for OPAL
"""
from typing import Dict, List
class Cell(object):
""" Represents a land cell in the simulation."""
def __init__(self, x: int, y: int, cost: float, slope: float,
fertility: float, composition: Dict[str, float]) -> None:
""" Creates a new cell with given parameters.
Parameters:
x (int): x co-ordinate of cell
y (int): y co-ordinate of the cell
cost (float): cost of the cell
slope (float): slope of the cell (0 - 1)
fertility (float): fertility of the cell (0 - 1)
composition (Dict[str, float]): community composition of the cell
Raises:
ValueError if !(0 <= slope <= 1) || !(0 <= fertility <= 1)
"""
self.x = x
self.y = y
self.cost = cost
if not (0 <= slope <= 1) or not (0 <= fertility <= 1):
raise ValueError
self.slope = slope
self.fertility = fertility
self.composition = composition
self.opportunity_cost = 1 - max(slope, 1 - fertility)
def get_x(self) -> int:
""" Get the cell's x-coordinate
Returns:
(int): This cell's x-coordinate
"""
return self.x
def get_y(self) -> int:
""" Get the cell's y-coordinate
Returns:
(int): This cell's y-coordinate
"""
return self.y
def get_cost(self) -> float:
""" Gets the cost of the cell
Returns:
(float): This cell's cost
"""
return self.cost
def get_slope(self) -> float:
""" Gets the slope of the cell
Returns:
(int): This cell's slope
"""
return self.slope
def get_fertility(self) -> float:
""" Gets the fertility of the cell
Returns:
(int): This cell's fertility
"""
return self.fertility
def get_opportunity_cost(self) -> float:
""" Gets the opportunity cost of the cell, this value is from 0 - 1 where
1 represents a high opportunity cost and 0 represents no opportunity cost
Returns:
(float) this cell's opportunity cost
"""
return self.opportunity_cost
def get_composition(self) -> Dict[str, float]:
""" Gets a shallow copy of the cell's community composition dictionary
Returns:
(Dict[str, int]): This cell's community composition dictionary
"""
return self.composition.copy()
def get_species_population(self, species: str) -> float:
""" Get the current population of a particular species in the cell
Parameters:
species (str): the species to get the population of
Returns:
(float): The current population of the species parameter in this cell
Raises:
KeyError: if specified species not in dictionary
"""
return self.get_species[species]
class CellCollection(object):
""" Represents a group of cells in the simulation. """
def __init__(self, cells: List[Cell] = []) -> None:
""" Create a new CellCollection with an optional list of starting cells.
Parameters:
cells (List[Cell]) (optional): starting cells
"""
self.max_id = 0
#Dictionary of cells and their ids
self.cells = {}
for cell in cells:
self.add_cell(cell)
def get_cells(self) -> List[Cell]:
""" Get a list of the cells within the collection
Returns:
(List[Cell]): List of cells within this collection"""
return list(self.cells.keys()).copy()
def add_cell(self, cell : Cell) -> None:
""" Adds a cell to the map
Parameters:
cell (Cell): cell to be added
Raises:
ValueError: if cell at the same (x, y) coordinates already in collection
"""
for other_cell in self.get_cells():
if (cell.get_x() == other_cell.get_x() and
cell.get_y() == other_cell.get_y()):
raise ValueError
else:
self.cells[cell] = self.max_id
self.max_id += 1
def get_adjacents(self, cell: Cell) -> List[Cell]:
"""Get the cells within the collection adjacent to a given cell.
Parameters:
cell (Cell): cell to find adjacents of
Returns:
(List[Cell]): list of cells within this collection adjacent to given cell.
"""
adjacents = []
for other_cell in self.get_cells():
if ((other_cell.get_x() == cell.get_x() and
abs(other_cell.get_y() - cell.get_y()) == 1) or
(other_cell.get_y() == cell.get_y() and
abs(other_cell.get_x() - cell.get_x()) == 1)):
adjacents.append(other_cell)
return adjacents
def is_in(self, cell : Cell) -> bool:
""" Checks if a cell is in the collection
Parameters:
cell (Cell): cell to be checked whether in collection
Returns:
(bool): true if cell in collection false otherwise
"""
return self.cells.get(cell, -1) != -1
def get_permutations(collection: CellCollection,
ambient_collection: CellCollection) -> List[CellCollection]:
"""
Gets all small permutations of a given collection, given an ambient
collection. A permutation is defined as a collection where one element is
removed OR one element is added OR one element is replaced.
Parameters:
collection (CellCollection): collection to permutate
ambient_collection (CellCollection): ambient collection to add new elements
from
Returns:
List[CellCollection]: list of permutations
"""
removals = []
for cell in collection.get_cells():
removed = collection.get_cells()
removed.remove(cell)
removals.append(CellCollection(removed))
substitutions = []
for removal in removals:
for cell in ambient_collection.get_cells():
if not removal.is_in(cell):
substituted = removal.get_cells().copy()
substituted.append(cell)
substitutions.append(CellCollection(substituted))
additions = []
for cell in ambient_collection.get_cells():
if not collection.is_in(cell):
added = collection.get_cells()
added.append(cell)
additions.append(CellCollection(added))
return removals + substitutions + additions