0
0
mirror of https://github.com/ok-oldking/ok-wuthering-waves.git synced 2025-04-24 08:25:16 +00:00

优化寻路刷大地图

This commit is contained in:
firedcto@gmail.com 2025-04-09 21:33:13 +08:00
parent 418a18b7da
commit b6bc9cde5d
53 changed files with 559 additions and 1074 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -501,8 +501,14 @@ msgstr "战斗后自动拾取声骸"
msgid "Farm Map with Star Path"
msgstr "标记寻路刷大地图"
msgid "Farm world map with a marked path of stars, start in the map screen"
msgstr "刷用星星标记的路径, 传送到起点后, 在大地图界面开始"
msgid "Farm world map with a marked path of stars (diamond as the starting point), start in the map screen"
msgstr "刷用星星标记的路径, 钻石作为起点, 在大地图界面开始, 工具使用钩锁."
msgid "Stars"
msgstr "星星标记"
msgid "Need be in the map screen and have a diamond as the starting point!"
msgstr "需要在大地图界面并且标记一个钻石为起点!"
msgid "Need be in the map screen and have a path of at least 3 stars!"
msgstr "需要在大地图界面并且至少有3个星星标记为路径!"

View File

@ -56,7 +56,7 @@ numpy==2.2.4
# shapely
rapidocr==2.0.6
# via -r .\requirements.in
ok-script==0.0.524
ok-script==0.0.525
# via -r .\requirements.in
omegaconf==2.3.0
# via ok-rapidocr-dml

View File

@ -28,7 +28,6 @@ class CombatCheck(BaseWWTask):
self.last_in_realm_not_combat = 0
self._last_liberation = 0
self.target_enemy_time_out = 3
self.check_pick_echo = False
@property
def in_liberation(self):
@ -40,6 +39,9 @@ class CombatCheck(BaseWWTask):
if value:
self._last_liberation = time.time()
def on_combat_check(self):
return True
def reset_to_false(self, recheck=False, reason=""):
if self.should_check_monthly_card() and self.handle_monthly_card():
return True
@ -111,8 +113,9 @@ class CombatCheck(BaseWWTask):
now = time.time()
if now - self.last_combat_check > self.combat_check_interval:
self.last_combat_check = now
if self.check_pick_echo:
self.incr_drop(self.pick_f())
if not self.on_combat_check():
self.log_info('on_combat_check failed')
return False
if self.has_target():
self.last_in_realm_not_combat = 0
return True

View File

@ -139,12 +139,15 @@ class BaseWWTask(BaseTask):
return None
return f
def walk_to_box(self, find_function, time_out=30, end_condition=None, y_offset=0.05):
def walk_to_box(self, find_function, time_out=30, end_condition=None, y_offset=0.05, v_move_fix_time=0):
if not find_function:
self.log_info('find_function not found, break')
return False
last_direction = None
v_fix_count = 0
original_y_offset = y_offset
start = time.time()
last_v_move = start
ended = False
while time.time() - start < time_out:
self.next_frame()
@ -158,17 +161,27 @@ class BaseWWTask(BaseTask):
treasure_icon = treasure_icon[0]
else:
treasure_icon = None
if not treasure_icon:
next_direction = None
if treasure_icon is None:
if not end_condition:
self.log_info('find_function not found, break')
break
break
if 0 < v_move_fix_time < time.time() - last_v_move:
if v_fix_count > 3:
v_fix_count += 1
y_offset = original_y_offset + 0.05 * v_fix_count
else:
self.next_frame()
continue
x, y = treasure_icon.center()
v_fix_count += 1
y_offset = original_y_offset - 0.05 * (v_fix_count - 4)
if next_direction is None:
x, y = treasure_icon.center()
y = max(0, y - self.height_of_screen(y_offset))
next_direction = self.get_direction(x, y, self.width, self.height)
if next_direction == 'w' or next_direction == 's':
last_v_move = time.time()
y = max(0, y - self.height_of_screen(y_offset))
next_direction = self.get_direction(x, y, self.width, self.height)
if next_direction != last_direction:
if last_direction:
self.send_key_up(last_direction)
@ -184,6 +197,18 @@ class BaseWWTask(BaseTask):
else:
return ended
def opposite_direction(self, direction):
if direction == 'w':
return 's'
elif direction == 's':
return 'w'
elif direction == 'a':
return 'd'
elif direction == 'd':
return 'a'
else:
return 'w'
def get_direction(self, location_x, location_y, screen_width, screen_height):
"""
Determines the location (w, a, s, d) based on diagonals
@ -413,7 +438,11 @@ class BaseWWTask(BaseTask):
"""
# Load the ONNX model
boxes = og.my_app.yolo_detect(self.frame, threshold=threshold, label=12)
ret = sorted(boxes, key=lambda detection: detection.x, reverse=True)
for box in ret:
box.y += box.height - 1
box.height = 1
return ret
def yolo_find_all(self, threshold=0.3):
@ -464,7 +493,7 @@ class BaseWWTask(BaseTask):
self.log_debug(f'max_echo_count {max_echo_count}')
if echos:
self.log_info(f'yolo found echo {echos}')
return self.walk_to_box(self.find_echo, time_out=15, end_condition=self.pick_echo, y_offset=0.2), max_echo_count > 1
return self.walk_to_box(self.find_echo, time_out=15, end_condition=self.pick_echo, v_move_fix_time=5), max_echo_count > 1
if use_color:
color_percent = self.calculate_color_percentage(echo_color, front_box)
self.log_debug(f'pick_echo color_percent:{color_percent}')
@ -660,33 +689,22 @@ class BaseWWTask(BaseTask):
raise Exception("can't find gray_book_boss, make sure f2 is the hotkey for book")
return gray_book_boss
def click_traval_button(self, use_custom=False):
if feature := self.find_one(['fast_travel_custom', 'remove_custom', 'gray_teleport'], threshold=0.6):
if feature.name == 'gray_teleport':
if use_custom:
# if not self.wait_click_feature('custom_teleport_hcenter_vcenter', raise_if_not_found=False, time_out=3):
self.click_relative(0.5, 0.5, after_sleep=1)
# if self.wait_click_feature('gray_custom_way_point', raise_if_not_found=False, time_out=4):
# self.sleep(1)
self.click_relative(0.68, 0.6, after_sleep=1)
self.click_relative(0.74, 0.92, after_sleep=1)
return True
else:
self.click_relative(0.74, 0.92, after_sleep=1)
def click_traval_button(self):
if feature := self.find_first_match_in_box('bottom_right', ['fast_travel_custom', 'gray_teleport', 'remove_custom'], threshold=0.8):
self.click(feature, after_sleep=1)
if feature.name == 'fast_travel_custom':
if self.wait_click_feature(['confirm_btn_hcenter_vcenter', 'confirm_btn_highlight_hcenter_vcenter'],
relative_x=-1, raise_if_not_found=True,
threshold=0.6,
time_out=4):
relative_x=-1, raise_if_not_found=False,
threshold=0.6,
time_out=2):
self.wait_click_feature(['confirm_btn_hcenter_vcenter', 'confirm_btn_highlight_hcenter_vcenter'],
relative_x=-1, raise_if_not_found=False,
threshold=0.6,
time_out=1)
return True
elif btn := self.find_one('gray_teleport', threshold=0.7):
return self.click_box(btn, relative_x=1)
relative_x=-1, raise_if_not_found=False,
threshold=0.6,
time_out=1)
return True
def wait_click_travel(self, use_custom=False):
self.wait_until(lambda: self.click_traval_button(use_custom=use_custom), raise_if_not_found=True, time_out=10,
def wait_click_travel(self):
self.wait_until(self.click_traval_button, raise_if_not_found=True, time_out=10,
settle_time=1)
def wait_book(self, feature="gray_book_all_monsters"):

View File

@ -18,38 +18,43 @@ class BigMap(WWOneTimeTask, BaseCombatTask):
super().__init__(*args, **kwargs)
self.big_map_frame = None
self.stars = None
self.bounding_box = None
self.sorted = False
self.my_box = None
self.diamond = None
def reset(self):
self.big_map_frame = None
self.stars = None
self.bounding_box = None
self.sorted = False
self.my_box = None
self.diamond = None
def load_stars(self):
def load_stars(self, wait_world=True):
self.reset()
self.click_relative(0.94, 556 / 1080, after_sleep=1)
self.big_map_frame = self.frame
self.diamond = self.find_one('big_map_diamond', threshold=0.7, frame=self.big_map_frame, box=Box(0,0,self.big_map_frame.shape[1],self.big_map_frame.shape[0]))
if not self.diamond:
raise Exception('Need be in the map screen and have a diamond as the starting point!')
self.stars = self.find_feature('big_map_star', threshold=0.7, frame=self.big_map_frame, box=Box(0,0,self.big_map_frame.shape[1],self.big_map_frame.shape[0]))
all_star_len = len(self.stars)
self.stars = group_boxes_by_center_distance(self.stars, self.height_of_screen(0.2))
self.stars = sort_stars(self.stars, self.diamond, self.height_of_screen(0.2))
self.stars.insert(0, self.diamond)
mini_map_box = self.get_box_by_name('box_minimap')
self.my_box = self.diamond.scale(mini_map_box.width/self.diamond.width * 2)
# if self.debug:
# init_my_box = self.my_box.crop_frame(self.frame)
# self.screenshot('init_my_box', frame=init_my_box)
if len(self.stars) <= 2:
raise Exception('Need be in the map screen and have a path of at least 3 stars!')
self.log_info(f'Loaded {len(self.stars)} from {all_star_len} Stars', notify=True)
self.bounding_box = get_bounding_box(self.stars)
mini_map_box = self.get_box_by_name('box_minimap')
self.bounding_box.width += mini_map_box.width * 2
self.bounding_box.height += mini_map_box.height * 2
self.bounding_box.x -= mini_map_box.width
self.bounding_box.y -= mini_map_box.height
self.log_info(f'Loaded {len(self.stars)} from {all_star_len + 1} Stars', notify=True)
# self.click(self.diamond, after_sleep=1)
# self.wait_click_travel()
self.send_key('esc')
self.info_set('Stars', len(self.stars))
self.send_key('esc', after_sleep=1)
if wait_world:
self.wait_in_team_and_world()
def get_angle_between(self, my_angle, angle):
if my_angle > angle:
@ -63,9 +68,9 @@ class BigMap(WWOneTimeTask, BaseCombatTask):
return to_turn
def get_my_angle(self):
return self.rotate_arrow_and_find('box_arrow')[0]
return self.rotate_arrow_and_find()[0]
def rotate_arrow_and_find(self, box):
def rotate_arrow_and_find(self):
arrow_template = self.get_feature_by_name('arrow')
original_mat = arrow_template.mat
max_conf = 0
@ -75,7 +80,7 @@ class BigMap(WWOneTimeTask, BaseCombatTask):
(h, w) = arrow_template.mat.shape[:2]
# self.log_debug(f'turn_east h:{h} w:{w}')
center = (w // 2, h // 2)
target_box = self.get_box_by_name(box) if isinstance(box, str) else box
target_box = self.get_box_by_name('arrow')
# if self.debug:
# self.screenshot('arrow_original', original_ mat)
for angle in range(0, 360):
@ -112,36 +117,11 @@ class BigMap(WWOneTimeTask, BaseCombatTask):
min_star = star
return min_star
def sort_stars(self, my_box):
if self.sorted:
return
remaining_boxes = self.stars[:] # Make a copy
sorted_boxes = []
# Start with the first box in the original list
current_box = self.find_closest(my_box)
remaining_boxes.remove(current_box)
sorted_boxes.append(current_box)
while remaining_boxes:
min_dist = float('inf')
best_idx = -1
# Find the box in remaining_boxes closest to the current_box
for i, box in enumerate(remaining_boxes):
dist = current_box.center_distance(box)
if dist < min_dist:
min_dist = dist
best_idx = i
# Add the closest box to the sorted list and remove from remaining
next_box = remaining_boxes.pop(best_idx)
sorted_boxes.append(next_box)
current_box = next_box # Update the reference point
self.stars = sorted_boxes
self.sorted = True
def find_direction_angle(self, screenshot=False):
if len(self.stars) == 0:
return None, 0, 0
my_box = self.find_my_location(screenshot=screenshot)
self.sort_stars(my_box)
sort_stars(self.stars, my_box,0)
min_star = self.stars[0]
min_distance = my_box.center_distance(min_star)
self.draw_boxes('star', min_star, color='green')
@ -160,37 +140,26 @@ class BigMap(WWOneTimeTask, BaseCombatTask):
def find_my_location(self, screenshot=False):
frame = self.big_map_frame
mat = self.get_box_by_name('box_minimap').crop_frame(self.frame)
mat = keep_circle(mat)
# in_big_map = self.find_one(frame=frame, template=mat, threshold=0.01, match_method=cv2.TM_SQDIFF_NORMED, box=self.bounding_box, mask_function=create_circle_mask_with_hole, screenshot=screenshot, canny_lower=50, canny_higher=150)
in_big_map = self.find_one(frame=frame, template=mat, threshold=0.01,
box=self.my_box.scale(1.3) if self.my_box is not None else self.bounding_box, mask_function=create_circle_mask_with_hole,
# mask = create_circle_mask_with_hole(mat)
# mat = cv2.bitwise_and(mat, mat, mask=mask)
in_big_map = self.find_one(frame=frame, template=mat, threshold=0.2,
box=self.my_box, mask_function=create_circle_mask_with_hole,
screenshot=screenshot)
# in_big_maps = self.find_feature(frame=frame, template=mat, threshold=0.01, box=self.bounding_box)
if not in_big_map:
raise RuntimeError('can not find my cords on big map!')
self.log_debug(f'found big map: {in_big_map}')
self.log_debug(f'found in_big_map: {in_big_map}')
if self.debug and in_big_map:
self.draw_boxes('stars', self.stars)
self.draw_boxes('search_map', self.bounding_box)
self.draw_boxes('my_box', self.my_box, color='green')
self.draw_boxes('in_big_map', in_big_map, color='yellow')
self.draw_boxes('me', in_big_map.scale(0.1), color='blue')
# self.screenshot('box_minimap', frame=frame, show_box=True)
self.my_box = in_big_map
# self.screenshot('template_minimap', frame=mat)
self.my_box = in_big_map.scale(1.25)
return in_big_map
def keep_circle(img):
height, width = img.shape[:2]
# Create a black mask with the same dimensions
mask = np.zeros((height, width), dtype=np.uint8)
# Define circle parameters (center and radius)
center_x, center_y = width // 2, height // 2
radius = min(center_x, center_y) # Fit circle within image bounds
# Draw a filled white circle on the mask
cv2.circle(mask, (center_x, center_y), radius, (255), thickness=-1)
# Apply the mask to the original image using bitwise AND
result = cv2.bitwise_and(img, img, mask=mask)
return result
def create_circle_mask_with_hole(image):
"""
Creates a binary circular mask with a rectangular hole in the center.
@ -226,17 +195,16 @@ class FarmMapTask(BigMap):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.icon = FluentIcon.GLOBE
self.description = "Farm world map with a marked path of stars, start in the map screen"
self.description = "Farm world map with a marked path of stars (diamond as the starting point), start in the map screen"
self.name = "Farm Map with Star Path"
self.max_star_distance = 1000
self.stuck_keys = [['space', 0.2], ['a',2], ['d',2]]
self.stuck_keys = [['space', 0.02], ['a',2], ['d',2], ['t', 0.02]]
self.stuck_index = 0
self.last_distance = 0
self.check_pick_echo = True
@property
def star_move_distance_threshold(self):
return self.height_of_screen(0.025)
return self.height_of_screen(0.03)
def run(self):
self.stuck_index = 0
@ -244,6 +212,11 @@ class FarmMapTask(BigMap):
self.load_stars()
self.go_to_star()
def on_combat_check(self):
self.incr_drop(self.pick_f())
self.find_my_location()
return True
def go_to_star(self):
current_direction = None
self.center_camera()
@ -253,17 +226,22 @@ class FarmMapTask(BigMap):
self.sleep(0.01)
self.middle_click(interval=1, after_sleep=0.2)
if self.in_combat():
self.sleep(2)
if current_direction is not None:
self.mouse_up(key='right')
self.send_key_up(current_direction)
current_direction = None
start = time.time()
self.combat_once()
while True:
dropped, has_more = self.yolo_find_echo(use_color=False, walk=False)
self.incr_drop(dropped)
self.sleep(0.5)
if not dropped or not has_more:
break
duration = time.time() - start
if duration > 8:
self.my_box = self.my_box.scale(1.1)
while True:
dropped, has_more = self.yolo_find_echo(use_color=False, walk=False)
self.incr_drop(dropped)
self.sleep(0.5)
if not dropped or not has_more:
break
star, distance, angle = self.find_direction_angle()
# self.draw_boxes('next_star', star, color='green')
if not star:
@ -284,17 +262,17 @@ class FarmMapTask(BigMap):
else:
continue
elif distance == self.last_distance:
logger.info(f'might be stuck, try {[self.stuck_index % 3]}')
self.send_key(self.stuck_keys[self.stuck_index % 3][0], down_time=self.stuck_keys[self.stuck_index % 3][1], after_sleep=0.5)
logger.info(f'might be stuck, try {[self.stuck_index % 4]}')
self.send_key(self.stuck_keys[self.stuck_index % 4][0], down_time=self.stuck_keys[self.stuck_index % 4][1], after_sleep=0.5)
self.stuck_index += 1
continue
self.last_distance = distance
if current_direction == 'w':
if 15 <= angle <= 75:
if 10 <= angle <= 80:
minor_adjust = 'd'
elif -75 <= angle <= -15:
elif -80 <= angle <= -10:
minor_adjust = 'a'
else:
minor_adjust = None
@ -305,7 +283,7 @@ class FarmMapTask(BigMap):
self.sleep(0.1)
self.middle_click(down_time=0.1)
self.send_key_up(minor_adjust)
self.sleep(0.2)
self.sleep(0.01)
continue
if current_adjust:
self.send_key_up(current_adjust)
@ -320,9 +298,8 @@ class FarmMapTask(BigMap):
new_direction = 's'
if current_direction != new_direction:
self.log_info(f'changed direction {angle} {current_direction} -> {new_direction}')
if self.debug:
self.screenshot(f'{current_direction}_{new_direction}_{angle}')
if current_direction:
self.mouse_up(key='right')
self.send_key_up(current_direction)
self.sleep(0.2)
self.turn_direction(new_direction)
@ -359,38 +336,36 @@ star_color = {
'b': (190, 220) # Blue range
}
def group_boxes_by_center_distance(boxes: List[Box], distance_threshold: float) -> List[Box]:
def sort_stars(points, start_point, max_distance = 0):
"""
Groups boxes where any box is close (center_distance < threshold)
to any other box in the group (connected components).
Returns the largest group.
BUILDS A PATH using Nearest Neighbor heuristic starting from 'start_point'.
Filters steps where distance < 'min_distance'. Prepends start_point.
NOTE: This is a HEURISTIC, likely NOT the absolute shortest total path.
"""
if not boxes:
unvisited = points[:] # Copy the list of points to visit
if not unvisited: # Handle empty input list
return []
n = len(boxes)
visited = [False] * n
all_groups = []
# Find connected components using DFS
for i in range(n):
if not visited[i]:
current_group = []
stack = [i]
visited[i] = True
while stack:
current_idx = stack.pop()
current_group.append(boxes[current_idx])
for j in range(n):
if not visited[j]:
# Use center_distance as requested
dist = boxes[current_idx].center_distance(boxes[j])
if dist < distance_threshold:
visited[j] = True
stack.append(j)
all_groups.append(current_group)
# Return the largest group found
if not all_groups:
return [] # Should not happen if boxes is not empty, but safe check
return max(all_groups, key=len)
path_result = [] # Initialize empty list for the results (excluding start)
current_point = start_point # Start the calculation from start_point
while unvisited:
# Find points reachable according to min_distance
# If min_distance is 0, distance(..) >= 0 is always true for distinct points.
reachable_points = [p for p in unvisited if max_distance == 0 or current_point.center_distance(p) <= max_distance]
if not reachable_points:
# Stop if no remaining points meet the criteria (or if unvisited is empty)
# print(f"Stopping: No remaining points meet criteria from {current_point}.") # Optional debug
break
# Find the closest point among the reachable ones
next_point = min(reachable_points, key=lambda p: current_point.center_distance(p))
path_result.append(next_point) # Add the chosen point to the result list
unvisited.remove(next_point) # Mark as visited
current_point = next_point # Update the current point for the next iteration
return path_result
def mask_star(image):
# return image

View File

@ -13,20 +13,20 @@ class TestTacet(TaskTestCase):
def test_find_treasure_icon(self):
self.set_image('tests/images/angle_130.png')
angle, box = self.task.get_angle()
angle, box = self.task.get_my_angle()
self.logger.info(f'test_find_treasure_icon {angle, box}')
self.assertTrue(100 <= angle <= 200)
def test_find_path(self):
self.set_image('tests/images/path.png')
self.task.load_stars()
self.task.load_stars(wait_world=False)
self.set_image('tests/images/mini_map.png')
self.task.my_box = self.task.box_of_screen(0.45, 0.17, 0.62, 0.54)
# self.task.my_box = self.task.box_of_screen(0.45, 0.17, 0.62, 0.54)
star, distance, angle = self.task.find_direction_angle(screenshot=True)
time.sleep(5)
self.logger.info(f'test_find_path {star, distance, angle}')
self.assertTrue(1 <= distance <= 20)
self.assertTrue(1 <= distance <= 50)
if __name__ == '__main__':

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 MiB

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 MiB

After

Width:  |  Height:  |  Size: 1.7 MiB