-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhelper.py
232 lines (194 loc) · 8.08 KB
/
helper.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
from random import randint
def lighten_hex_color(hex_color, lighten_factor=0.1) -> str:
"""
Lightens a given hex color.
Args:
hex_color (str): The hex color string to lighten, e.g., '#RRGGBB'.
lighten_factor (float): The factor by which to lighten the color, where 0 is no change
and 1 is white. Default is 0.1 (10% lighter).
Returns:
str: The lightened hex color string.
"""
if hex_color.startswith('#'):
hex_color = hex_color[1:]
r = int(hex_color[:2], 16)
g = int(hex_color[2:4], 16)
b = int(hex_color[4:], 16)
r = int(r + (255 - r) * lighten_factor)
g = int(g + (255 - g) * lighten_factor)
b = int(b + (255 - b) * lighten_factor)
r = min(255, max(0, r))
g = min(255, max(0, g))
b = min(255, max(0, b))
lightened_hex_color = f'#{r:02X}{g:02X}{b:02X}'
return lightened_hex_color
def darken_hex_color(hex_color, darken_factor=0.1) -> str:
"""
Darkens a given hex color.
Args:
hex_color (str): The hex color string to darken, e.g., '#RRGGBB'.
darken_factor (float): The factor by which to darken the color, where 0 is no change
and 1 is black. Default is 0.1 (10% darker).
Returns:
str: The darkened hex color string.
"""
if hex_color.startswith('#'):
hex_color = hex_color[1:]
r = int(hex_color[:2], 16)
g = int(hex_color[2:4], 16)
b = int(hex_color[4:], 16)
r = int(r * (1 - darken_factor))
g = int(g * (1 - darken_factor))
b = int(b * (1 - darken_factor))
r = min(255, max(0, r))
g = min(255, max(0, g))
b = min(255, max(0, b))
darkened_hex_color = f'#{r:02X}{g:02X}{b:02X}'
return darkened_hex_color
def random_coordinates(grid_width:int, grid_height:int, box_size:int) -> tuple[int,int]:
"""
Generate random coordinates within the given grid dimensions, adjusted by the box size.
Args:
grid_width (int): The width of the grid in terms of number of boxes.
grid_height (int): The height of the grid in terms of number of boxes.
box_size (int): The size of each box in the grid.
Returns:
tuple[int, int]: A tuple containing the random (x, y) coordinates.
"""
# The approach divides the screen into a grid of cells, where each cell represents a possible position for the food.
# The grid is defined by the box_size, which determines the size of each cell.
# To select a random cell, we choose a random integer index along the x-axis (vertical lines) and y-axis (horizontal lines).
# We then multiply these indices by the box_size to obtain the exact coordinates within the canvas where the food can be placed.
x = randint(0, grid_width)* box_size
y = randint(0, grid_height)* box_size
return (x , y)
def generate_non_overlapping_coordinates(
coordinates : list|tuple,
grid_width : int,
grid_height : int,
box_size : int
) -> tuple[int,int]|None:
"""
Generate new coordinates within a grid that do not overlap with existing coordinates.
Args:
list1 (list of tuples): List of current coordinates.
width_box (int): Width of the grid in terms of boxes.
height_box (int): Height of the grid in terms of boxes.
box_size (int): Size of each box.
Returns:
tuple: New x, y coordinates in terms of pixels if available, otherwise None.
Time Complexity: 𝑂(𝑛 + width_box + height_box)
Space Complexity: 𝑂(𝑛)
"""
def coordinates_to_dict(coordinates, box_size) -> dict[int:set]:
"""
Convert a list of coordinates into a dictionary for quick lookup.
"""
dict1 = {}
for x , y in coordinates:
x //= box_size
y //= box_size
if x in dict1:
dict1[x].add(y)
else:
dict1[x] = {y}
return dict1
#genrating random cordss in box_size
x = randint(0 , grid_width)
y = randint(0 , grid_height)
dict1 = coordinates_to_dict(coordinates, box_size)
#there is no infinite loop possible
# If the current x is in the dictionary and all possible y values are taken (column is full),
# move to the next x value. Wrap around to 0 if the end of the grid is reached.
# If we've cycled back to the original x value, it means no available x-coordinate was found.
# the same thing going on with 2nd while loop
original_x = x
while (x in dict1) and (len(dict1[x]) == grid_width + 1):
x = (x + 1) if x < grid_width else 0
if original_x == x:
return None
# there is no infinite loop possible
original_y = y
while (x in dict1) and (y in dict1[x]):
y = (y + 1) if y < grid_height else 0
if original_y == y:
return None
return x * box_size , y * box_size
def validate_coordinates(cords ,box_size:int) -> tuple[int:int]:
"""
Snap coordinates to the nearest lower multiple of box size.
Parameters:
cords (tuple): A tuple (x, y) representing the coordinates.
box_size (int): The size of the box grid.
Returns:
tuple: Adjusted coordinates (x, y) snapped to the nearest lower multiple of box_size.
"""
x , y = cords
x -= x % box_size
y -= y % box_size
return (x , y)
def check_cords_in_range(list_cords:list[tuple], coordinates:tuple[int]) -> bool:
"""
Check if the given coordinates fall within any of the ranges specified in the list of coordinates.
Parameters:
- list_cords (list[tuple, tuple]): A list of tuples representing coordinate ranges. Each tuple contains
four integers (x1, y1, x2, y2), defining a rectangular area.
- coordinates (tuple[int, int]): A tuple representing the coordinates to be checked.
Returns:
- bool: True if the coordinates fall within any of the specified ranges, False otherwise.
"""
x , y = coordinates
for group in list_cords:
x1 , y1 , x2 , y2 = group
if x1 < x < x2 and y1 < y < y2:
return True
return False
def round_up_coords(height:int, width:int, box_size:int, coordinates:tuple) -> tuple[int,int]:
coordinates[0] = min((height // box_size),max(0,coordinates[0]))*box_size
coordinates[1] = min((width // box_size),max(0,coordinates[1]))*box_size
return coordinates
def deep_copy(original:dict|list|tuple|set):
# Create an empty dictionary to hold the copy
copied_dict = {}
# Iterate through each key-value pair in the original dictionary
for key, value in original.items():
# If the value is a dictionary, recursively copy it
if isinstance(value, dict):
copied_dict[key] = deep_copy(value)
# If the value is a list, make a copy of the list and check for nested dictionaries
elif isinstance(value, list):
copied_list = []
for item in value:
if isinstance(item, dict):
copied_list.append(deep_copy(item))
else:
copied_list.append(item)
copied_dict[key] = copied_list
# If the value is a set, make a copy of the set and check for nested dictionaries
elif isinstance(value, set):
copied_set = set()
for item in value:
if isinstance(item, dict):
copied_set.add(frozenset(deep_copy(item).items()))
else:
copied_set.add(item)
copied_dict[key] = copied_set
# For all other data types, simply copy the value
else:
copied_dict[key] = value
return copied_dict
def get_nested_value(d, keys:dict):
"""
Retrieves a value from a nested dictionary using a list of keys.
Parameters:
d (dict): The dictionary to search.
keys (list): A list of keys specifying the path to the value.
Returns:
any: The value at the specified path, or an empty dictionary if any key is missing.
"""
for key in keys:
try:
d = d.get(key, None)
except KeyError:
return None
return d