forked from tanjeffreyz/auto-maple
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutils.py
More file actions
238 lines (189 loc) · 6.59 KB
/
utils.py
File metadata and controls
238 lines (189 loc) · 6.59 KB
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
233
234
235
236
237
238
"""A collection of functions and classes used across multiple modules."""
import config
import math
import cv2
import numpy as np
from random import random
def run_if_enabled(function):
"""
Decorator for functions that should only run if the bot is enabled.
:param function: The function to decorate.
:return: The decorated function.
"""
def helper(*args, **kwargs):
if config.enabled:
return function(*args, **kwargs)
return helper
def reset_settings():
"""
Resets all settings to their default values.
:return: None
"""
config.move_tolerance = 0.1
config.adjust_tolerance = 0.01
config.record_layout = False
config.buff_cooldown = 250
def distance(a, b):
"""
Applies the distance formula to two points.
:param a: The first point.
:param b: The second point.
:return: The distance between the two points.
"""
return math.sqrt((a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2)
def separate_args(arguments):
"""
Separates a given array ARGUMENTS into an array of normal arguments and a
dictionary of keyword arguments.
:param arguments: The array of arguments to separate.
:return: An array of normal arguments and a dictionary of keyword arguments.
"""
arguments = [s.strip() for s in arguments]
args = []
kwargs = {}
for a in arguments:
index = a.find('=')
if index > -1:
key = a[:index].strip()
value = a[index+1:].strip()
kwargs[key] = value
else:
args.append(a)
return args, kwargs
def single_match(frame, template):
"""
Finds the best match within FRAME.
:param frame: The image in which to search for TEMPLATE.
:param template: The template to match with.
:return: The top-left and bottom-right positions of the best match.
"""
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
result = cv2.matchTemplate(gray, template, cv2.TM_CCOEFF)
_, _, _, top_left = cv2.minMaxLoc(result)
w, h = template.shape[::-1]
bottom_right = (top_left[0] + w, top_left[1] + h)
return top_left, bottom_right
def multi_match(frame, template, threshold=0.95):
"""
Finds all matches in FRAME that are similar to TEMPLATE by at least THRESHOLD.
:param frame: The image in which to search.
:param template: The template to match with.
:param threshold: The minimum percentage of TEMPLATE that each result must match.
:return: An array of matches that exceed THRESHOLD.
"""
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
result = cv2.matchTemplate(gray, template, cv2.TM_CCOEFF_NORMED)
locations = np.where(result >= threshold)
locations = list(zip(*locations[::-1]))
results = []
for p in locations:
x = int(round(p[0] + template.shape[1] / 2))
y = int(round(p[1] + template.shape[0] / 2))
results.append((x, y))
return results
def convert_to_relative(point, frame):
"""
Converts POINT into relative coordinates in the range [0, 1] based on FRAME.
Normalizes the units of the vertical axis to equal those of the horizontal
axis by using config.mm_ratio.
:param point: The point in absolute coordinates.
:param frame: The image to use as a reference.
:return: The given point in relative coordinates.
"""
x = point[0] / frame.shape[1]
y = point[1] / config.mm_ratio / frame.shape[0]
return x, y
def convert_to_absolute(point, frame):
"""
Converts POINT into absolute coordinates (in pixels) based on FRAME.
Normalizes the units of the vertical axis to equal those of the horizontal
axis by using config.mm_ratio.
:param point: The point in relative coordinates.
:param frame: The image to use as a reference.
:return: The given point in absolute coordinates.
"""
x = int(round(point[0] * frame.shape[1]))
y = int(round(point[1] * config.mm_ratio * frame.shape[0]))
return x, y
def print_separator():
"""
Prints a 3 blank lines for visual clarity.
:return: None
"""
print('\n\n')
def closest_point(points, target):
"""
Returns the point in POINTS that is closest to TARGET.
:param points: A list of points to check.
:param target: The point to check against.
:return: The point closest to TARGET, otherwise None if POINTS is empty.
"""
if points:
points.sort(key=lambda p: distance(p, target))
return points[0]
def bernoulli(p):
"""
Returns the value of a Bernoulli random variable with probability P.
:param p: The random variable's probability of being True.
:return: True or False.
"""
return random() < p
#################################
# Validator Functions #
#################################
def validate_type(string, other):
"""
Checks whether STRING can be converted into type OTHER.
:param string: The string to check.
:param other: The type to check against.
:return: True if STRING can be of type OTHER, False otherwise.
"""
try:
other(string)
return True
except ValueError:
return False
def validate_arrows(key):
"""
Checks whether string KEY is an arrow key.
:param key: The key to check.
:return: KEY in lowercase if it is a valid arrow key.
"""
if isinstance(key, str):
key = key.lower()
if key in ['up', 'down', 'left', 'right']:
return key
raise ValueError
def validate_horizontal_arrows(key):
"""
Checks whether string KEY is either a left or right arrow key.
:param key: The key to check.
:return: KEY in lowercase if it is a valid horizontal arrow key.
"""
if isinstance(key, str):
key = key.lower()
if key in ['left', 'right']:
return key
raise ValueError
def validate_nonzero_int(value):
"""
Checks whether VALUE can be a valid nonzero integer.
:param value: The string to check.
:return: STRING as an integer.
"""
if int(value) >= 1:
return int(value)
raise ValueError
def validate_boolean(boolean):
"""
Checks whether string BOOLEAN is a valid bool.
:param boolean: The string to check.
:return: BOOLEAN as a bool if it is valid, otherwise None.
"""
if isinstance(boolean, str):
boolean = boolean.lower()
if boolean == 'true':
return True
elif boolean == 'false':
return False
raise ValueError