-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathglobal_stuff.py
232 lines (171 loc) · 7.42 KB
/
global_stuff.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
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
import tkinter as tk
import threading
import math
import argparse
from stats_collector import *
###################### Helper Functions ######################
def clamp(value, min_val, max_val):
return max(min(value, max_val), min_val)
def rgb_to_hex(rgb):
r, g, b = rgb
return f'#{int(r):02x}{int(g):02x}{int(b):02x}'
def normalize_vector(x, y):
"""
Normalizes a 2D vector.
Args:
- x (float): The x-component of the vector.
- y (float): The y-component of the vector.
Returns:
- tuple: A tuple containing the normalized x-component,
normalized y-component, and the magnitude of the original vector.
"""
magnitude = math.sqrt(x**2 + y**2)
if magnitude == 0:
return (0, 0, 0) # To avoid division by zero
else:
normalized_x = x / magnitude
normalized_y = y / magnitude
return (normalized_x, normalized_y, magnitude)
def check_bounds(col, row):
"""
Checks if a given column and row are within the bounds of the canvas.
Args:
- col (int): Column value.
- row (int): Row value.
Returns:
- bool: True if the column and row are within the bounds, False otherwise.
"""
# We had a problem where things could spawn at x = 0 but not move there
# so plants and rabbits would be attracted to the top and left sides of
# screen and changing the minimum spawn location to x = 1 not 0 fixed the
# issue
if col < 1 or col > canvas_width:
return False
elif row < stat_bottom or row > canvas_height:
return False
else:
return True
def capped_int(value, cap):
"""
Converts a value to an integer and checks if it is within a specified
limit.
Args:
- value: The value to convert and check.
- cap: The upper limit.
Returns:
- int: The value as an integer if it is within the limit.
Raises:
- argparse.ArgumentTypeError: If the value is not a positive integer
or exceeds the limit.
"""
ivalue = int(value)
if ivalue <= 0:
raise argparse.ArgumentTypeError("%s is an invalid int value" % value)
elif ivalue > cap:
raise argparse.ArgumentTypeError(
'''%s exceeds the limit of %s''' % (value, cap))
return ivalue
###################### Argument Parsing ######################
parser = argparse.ArgumentParser(description=
"Parse simulation start configurations.")
parser.add_argument('--plants', metavar='PLANTS', type=lambda x:
capped_int(x, 400), default=200,
help="""Number of plants at the start of the simulation;
Max number of plants to start with is 400""")
parser.add_argument('--rabbits', metavar='RABBITS', type=lambda x:
capped_int(x, 300), default=100,
help="""Number of rabbits at the start of the simulation;
Max number of rabbits to start with is 300""")
parser.add_argument('--foxes', metavar='FOXES', type=lambda x:
capped_int(x, 300), default=0,
help="""Number of foxes at the start of the simulation;
Max number of foxes to start with is 300""")
parser.add_argument('--height', metavar='HEIGHT', type=lambda x:
capped_int(x, 1000), default=500,
help='Height of the canvas; Max height is 1000')
parser.add_argument('--width', metavar='WIDTH', type=lambda x:
capped_int(x, 1500), default=500,
help='Width of the canvas; Max width is 1500')
args = parser.parse_args()
n_plants = args.plants
n_rabbits = args.rabbits
n_foxes = args.foxes
###################### Simulation Parameters ######################
health = 200 # starting health of rabbits and foxes
# Plant info
foodValue = 1 # number of times food can be eated before destruction
plantRate = 0.13 # likelyhood that any plant will reproduce each time step
maxPlants = 500 # max number of plants
minPlantDistance = 30 # minimum distance plants must be from each other
maxPlantDistance = 6000 # maximum distance plants can be from their parent
# rabbit info
rabbitMutationRate = 0.2
rabbitMetabolism = 60 # amount of health that rabbits get back per food
rabbitStomachSize = 300 # max amount of health a rabbit can have
rabbitSpeed = 1.2 # rabbit starting speed
rabbitRate = 0.004 # likelyhood that any healthy rabbit will reproduce
rabbitReproductionCutoff = 100 # rabbits can only reproduce if they have
# at least this much health
fearFactor = 1 # how afraid of foxes rabbits are
hungerFactor = 1 # how much they desire food
avoidOthersFactor = 0.1 # how much they avoid other rabbits
rabbitRadius = 100 # how far away they care about other rabbits
generation = 1 # tracks the number of generations
rabbitColor = (50, 50, 200)
rabbitHealth = 100 # starting health of rabbits
maxRabbits = 150 # max number of rabbits
minRabbitDistance = 30 # minimum distance rabbits must be from each other
maxRabbitDistance = 50 # maximum distance rabbits can be from their parent
# create a genome for the starting population
rabbitStartingGenes = [rabbitMutationRate, rabbitMetabolism,
rabbitStomachSize, rabbitSpeed, rabbitRate,
rabbitReproductionCutoff, fearFactor, hungerFactor,
avoidOthersFactor, rabbitColor, rabbitHealth,
generation]
# fox info
foxMetabolism = 50 # amount of health that fox get back per food
foxStomachSize = 350 # max amount of health a fox can have
foxSpeed = 2 # fox starting speed
foxRate = 0.001 # likelyhood that any healthy fox will reproduce each time step
foxReproductionCutoff = 100 # foxes only reproduce if they have at least this
# much health
avoidOthers = 0.3 # how strongly foxes avoid other foxes
maxFoxes = 50 # max number of foxes
minFoxDistance = 30 # minimum distance foxes must be from each other
maxFoxDistance = 50 # maximum distance foxes can be from their parent
###################### Stat Block Information ######################
canvas_height = args.height
canvas_width = args.width
stat_height = int(canvas_height * .1)
stat_bottom = int(stat_height + 10) # y-coord of bottom count boxes
fox_color = "#ff8585"
rabbit_color = "#7c9feb"
plant_color = "#91c795"
###################### Tkinter Canvas Info ######################
window = tk.Tk()
window.title("Foxes, Rabbits, & Plants Simulation")
canvas = tk.Canvas(window, width=canvas_width,
height=canvas_height,
bg="white")
canvas.pack()
canvas_lock = threading.Lock()
###################### Global Shared Information ######################
# these lists are super important. Creatures have acess to these lists and use
# them to locate other creatures among a number of other useful things like
# representing how many threads are running (for the barrier)
rabbits = []
plants = []
foxes = []
# protect the above lists
rabbit_lock = threading.Lock()
plant_lock = threading.Lock()
fox_lock = threading.Lock()
# used in the barrier
semList = []
semListLock = threading.Lock()
# signal the end of the simulation
sim_done = False
sim_done_event = threading.Event()
# global stats collector to report stats to
stats_collector = StatsCollector(n_plants, n_plants, n_foxes,
rabbitSpeed, fearFactor, hungerFactor)