Fix: Map swipe optimize should use local map view to generate blacklist

- Opt: Take less screenshots during swipe, reuse local view object as possible
- Refactor: handle_boss_appear_refocus()
- Fix: Update swipe box area in map, avoid clicking auto search
This commit is contained in:
LmeSzinc 2021-11-22 18:02:40 +08:00
parent 153c9fb491
commit 7a0c566a9e
14 changed files with 112 additions and 74 deletions

View File

@ -86,9 +86,5 @@ class Campaign(CampaignBase):
return self.fleet_2.clear_boss()
def handle_boss_appear_refocus(self):
for data in self.map.spawn_data:
if data.get('battle') == self.battle_count and data.get('boss', 0):
self.map_swipe((-3, -2))
return super().handle_boss_appear_refocus()
def handle_boss_appear_refocus(self, preset=(-3, -2)):
return super().handle_boss_appear_refocus(preset)

View File

@ -45,8 +45,5 @@ class Campaign(CampaignBase):
def battle_1(self):
return self.clear_boss()
def handle_boss_appear_refocus(self):
for data in self.map.spawn_data:
if data.get('battle') == self.battle_count and data.get('boss', 0):
self.map_swipe((-3, 0))
return super().handle_boss_appear_refocus()
def handle_boss_appear_refocus(self, preset=(-3, 0)):
return super().handle_boss_appear_refocus(preset)

View File

@ -68,8 +68,5 @@ class Campaign(CampaignBase):
return self.fleet_boss.clear_boss()
def handle_boss_appear_refocus(self):
for data in self.map.spawn_data:
if data.get('battle') == self.battle_count and data.get('boss', 0):
self.map_swipe((0, -2))
return super().handle_boss_appear_refocus()
def handle_boss_appear_refocus(self, preset=(0, -2)):
return super().handle_boss_appear_refocus(preset)

View File

@ -68,8 +68,5 @@ class Campaign(CampaignBase):
return self.fleet_2.brute_clear_boss()
def handle_boss_appear_refocus(self):
for data in self.map.spawn_data:
if data.get('battle') == self.battle_count and data.get('boss', 0):
self.map_swipe((-3, -2))
return super().handle_boss_appear_refocus()
def handle_boss_appear_refocus(self, preset=(-3, -2)):
return super().handle_boss_appear_refocus(preset)

View File

@ -49,8 +49,5 @@ class Config:
class Campaign(CampaignBase):
MAP = MAP
def handle_boss_appear_refocus(self):
if self.battle_count == 4:
self.map_swipe((-3, -2))
return super().handle_boss_appear_refocus()
def handle_boss_appear_refocus(self, preset=(-3, -2)):
return super().handle_boss_appear_refocus(preset)

View File

@ -86,19 +86,32 @@ def random_rectangle_vector_opted(
half_vector = np.round(vector / 2).astype(np.int)
box = np.array(box) + np.append(np.abs(half_vector) + padding, -np.abs(half_vector) - padding)
box = area_offset(box, half_vector)
segment = int(np.linalg.norm(vector) // 70) + 1
def in_blacklist(end):
if not blacklist_area:
return False
for x in range(segment + 1):
point = - vector * x / segment + end
for area in blacklist_area:
if point_in_area(point, area, threshold=0):
return True
return False
if whitelist_area:
for area in whitelist_area:
area = area_limit(area, box)
if sum(area_size(area)) > 0:
end_point = random_rectangle_point(area)
return tuple(end_point - vector), tuple(end_point)
for _ in range(10):
if in_blacklist(end_point):
continue
return tuple(end_point - vector), tuple(end_point)
for n in range(100):
for _ in range(100):
end_point = random_rectangle_point(box)
if blacklist_area:
if any([point_in_area(end_point, area, threshold=0) for area in blacklist_area]):
continue
if in_blacklist(end_point):
continue
return tuple(end_point - vector), tuple(end_point)
end_point = random_rectangle_point(box)

View File

@ -115,6 +115,8 @@ class ManualConfig:
MAP_WALK_OPTIMIZE = True
# Optimize swipe path, reducing swipes turn info clicks.
MAP_SWIPE_OPTIMIZE = True
# Swipe after boss appear. Could avoid map detection error when camera is on edge.
MAP_BOSS_APPEAR_REFOCUS_SWIPE = (0, 0)
"""
module.map_detection

View File

@ -112,7 +112,7 @@ class Control(MiniTouch):
)
self.device.long_click(x, y, duration=duration)
def swipe(self, vector, box=(123, 159, 1193, 628), random_range=(0, 0, 0, 0), padding=15, duration=(0.1, 0.2),
def swipe(self, vector, box=(123, 159, 1175, 628), random_range=(0, 0, 0, 0), padding=15, duration=(0.1, 0.2),
whitelist_area=None, blacklist_area=None, name='SWIPE'):
"""Method to swipe.

View File

@ -20,11 +20,10 @@ class Camera(MapOperation):
map: CampaignMap
camera = (0, 0)
grid_class = Grid
_correct_camera = False
_prev_view = None
_prev_swipe = None
def _map_swipe(self, vector, box=(123, 159, 1193, 628)):
def _map_swipe(self, vector, box=(123, 159, 1175, 628)):
"""
Args:
vector (tuple, np.ndarray): float
@ -53,7 +52,9 @@ class Camera(MapOperation):
self.device.sleep(0.3)
self.update()
else:
self.update(camera=False)
# Drop swipe
# self.update(camera=False)
pass
def map_swipe(self, vector):
"""
@ -109,7 +110,7 @@ class Camera(MapOperation):
self._view_init()
try:
self.view.load(self.device.image)
except (MapDetectionError, AttributeError) as e:
except MapDetectionError as e:
if self.info_bar_count():
logger.info('Perspective error cause by info bar. Waiting.')
self.handle_info_bar()
@ -151,9 +152,6 @@ class Camera(MapOperation):
self._prev_swipe = None
self.show_camera()
if not self._correct_camera:
self.show_camera()
return False
# Set camera position
if self.view.left_edge:
x = 0 + self.view.center_loca[0]
@ -173,14 +171,16 @@ class Camera(MapOperation):
self.camera = (x, y)
self.show_camera()
def predict(self, mode='normal'):
self.predict()
def predict(self):
self.view.predict()
self.map.update(grids=self.view, camera=self.camera, mode=mode)
self.view.show()
def show_camera(self):
logger.attr_align('Camera', location2node(self.camera))
def ensure_edge_insight(self, reverse=False, preset=None, swipe_limit=(3, 2)):
def ensure_edge_insight(self, reverse=False, preset=None, swipe_limit=(3, 2), skip_first_update=True):
"""
Swipe to bottom left until two edges insight.
Edges are used to locate camera.
@ -189,18 +189,19 @@ class Camera(MapOperation):
reverse (bool): Reverse swipes.
preset (tuple(int)): Set in map swipe manually.
swipe_limit (tuple): (x, y). Limit swipe in (-x, -y, x, y).
skip_first_update (bool): Usually to be True. Use False if you are calling ensure_edge_insight manually.
Returns:
list[tuple]: Swipe record.
"""
logger.info(f'Ensure edge in sight.')
record = []
self._correct_camera = True
x_swipe, y_swipe = np.multiply(swipe_limit, random_direction(self.config.MAP_ENSURE_EDGE_INSIGHT_CORNER))
while 1:
if len(record) == 0:
self.update()
if not skip_first_update:
self.update()
if preset is not None:
self.map_swipe(preset)
record.append(preset)
@ -217,8 +218,6 @@ class Camera(MapOperation):
if x == 0 and y == 0:
break
# self._correct_camera = False
if reverse:
logger.info('Reverse swipes.')
for vector in record[::-1]:
@ -279,10 +278,9 @@ class Camera(MapOperation):
queue = queue.sort_by_camera_distance(self.camera)
self.focus_to(queue[0])
self.focus_to_grid_center(0.25)
self.view.predict()
success = self.map.update(grids=self.view, camera=self.camera, mode=mode)
if not success:
self.ensure_edge_insight()
self.ensure_edge_insight(skip_first_update=False)
continue
queue = queue[1:]
@ -405,30 +403,36 @@ class Camera(MapOperation):
"""
map_vector = np.array(map_vector)
def filter_grids(globe_grids, pad=0):
def local_to_area(local_grid, pad=0):
result = []
for local in local_grid:
# Predict the position of grid after swipe.
# Swipe should ends there, to prevent treating swipe as click.
area = area_offset((0, 0, 1, 1), offset=-map_vector)
corner = local.grid2screen(area2corner(area))
area = trapezoid2area(corner, pad=pad)
result.append(area)
return result
def globe_to_local(globe_grids):
result = []
for globe in globe_grids:
location = tuple(np.array(globe.location) - self.camera + self.view.center_loca)
if location in self.view:
# Predict the position of grid after swipe.
# Swipe should ends there, to prevent treating swipe as click.
local = self.view[location]
area = area_offset((0, 0, 1, 1), offset=-map_vector)
corner = local.grid2screen(area2corner(area))
area = trapezoid2area(corner, pad=pad)
result.append(area)
result.append(local)
return result
whitelist = self.map.select(is_land=True) \
.add(self.map.select(is_current_fleet=True)) \
.sort_by_camera_distance(self.camera)
blacklist = self.map.select(is_sea=False) \
.delete(self.map.select(is_land=True)) \
.add(self.map.select(is_fleet=True, is_current_fleet=False)) \
.add(self.map.select(is_mystery=True)) \
.sort_by_camera_distance(self.camera)
blacklist = self.view.select(is_enemy=True) \
.add(self.view.select(is_siren=True)) \
.add(self.view.select(is_mystery=True)) \
.add(self.view.select(is_fleet=True, is_current_fleet=False))
whitelist = filter_grids(whitelist, pad=25)
blacklist = filter_grids(blacklist, pad=-5)
# self.view.show()
whitelist = local_to_area(globe_to_local(whitelist), pad=25)
blacklist = [grid.outer for grid in blacklist] + local_to_area(blacklist, pad=-5)
return whitelist, blacklist

View File

@ -1,7 +1,9 @@
import itertools
import numpy as np
from module.base.timer import Timer
from module.exception import MapWalkError, MapEnemyMoved
from module.exception import MapWalkError, MapEnemyMoved, MapDetectionError
from module.handler.ambush import AmbushHandler
from module.logger import logger
from module.map.camera import Camera
@ -298,7 +300,8 @@ class Fleet(Camera, AmbushHandler):
elif self.map[location].may_enemy:
self.map[location].is_cleared = True
self.handle_boss_appear_refocus()
if self.catch_boss_appear():
self.handle_boss_appear_refocus()
if self.config.MAP_FOCUS_ENEMY_AFTER_BATTLE:
self.camera = location
self.update()
@ -364,6 +367,7 @@ class Fleet(Camera, AmbushHandler):
break
if walk_timeout.reached():
logger.warning('Walk timeout. Retrying.')
self.predict()
self.ensure_edge_insight()
break
@ -382,8 +386,11 @@ class Fleet(Camera, AmbushHandler):
self.full_scan_carrier()
if result == 'combat':
self.round_battle()
self.predict()
self.round_next()
if self.round_is_new:
if result != 'combat':
self.predict()
self.full_scan_movable(enemy_cleared=result == 'combat')
self.find_path_initial()
raise MapEnemyMoved
@ -422,6 +429,7 @@ class Fleet(Camera, AmbushHandler):
self._goto(node, expected=expected if node == nodes[-1] else '')
except MapWalkError:
logger.warning('Map walk error.')
self.predict()
self.ensure_edge_insight()
nodes_ = self.map.find_path(node, step=1)
for node_ in nodes_:
@ -845,7 +853,7 @@ class Fleet(Camera, AmbushHandler):
logger.warning('Enemy roadblock try exhausted.')
def handle_boss_appear_refocus(self):
def catch_boss_appear(self):
"""
"""
@ -868,14 +876,33 @@ class Fleet(Camera, AmbushHandler):
# g.wipe_out()
# break
if appear:
camera = self.camera
return appear
def handle_boss_appear_refocus(self, preset=None):
"""
Refocus to previous camera position after boss appear.
Args:
preset (tuple): (x, y).
"""
camera = self.camera
if preset is None:
preset = self.config.MAP_BOSS_APPEAR_REFOCUS_SWIPE
if preset is not None and np.linalg.norm(preset) > 0:
try:
self.update()
except MapDetectionError:
logger.info(f'MapDetectionError occurs after boss appear, trying swipe preset {preset}')
# Swipe optimize here may not be accurate.
self.map_swipe(preset)
self.ensure_edge_insight()
logger.info('Refocus to previous camera position.')
self.focus_to(camera)
return True
else:
return False
self.update()
self.ensure_edge_insight()
logger.info('Refocus to previous camera position.')
self.focus_to(camera)
def fleet_checked_reset(self):
self.map_fleet_checked = False

View File

@ -294,7 +294,7 @@ class CampaignMap:
mode (str): Scan mode, such as 'normal', 'carrier', 'movable'
"""
offset = np.array(camera) - np.array(grids.center_loca)
grids.show()
# grids.show()
failed_count = 0
for grid in grids.grids.values():

View File

@ -112,6 +112,10 @@ class Perspective:
edge_v = edge_v.delete(inner_v, threshold=self.config.TRUST_EDGE_LINES_THRESHOLD)
self.horizontal = horizontal
self.vertical = vertical
if not self.horizontal:
raise MapDetectionError('No horizontal line detected')
if not self.vertical:
raise MapDetectionError('No vertical line detected')
# Calculate perspective
self.crossings = self.horizontal.cross(self.vertical)

View File

@ -17,6 +17,10 @@ class Assets:
def ui_mask(self):
return UI_MASK.image
@cached_property
def ui_mask_os(self):
return UI_MASK_OS.image
@cached_property
def ui_mask_stroke(self):
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
@ -33,7 +37,7 @@ class Assets:
def ui_mask_os_in_map(self):
area = np.append(np.subtract(0, DETECTING_AREA[:2]), self.ui_mask.shape[::-1])
# area = (-123, -55, 1157, 665)
return crop(UI_MASK_OS.image, area)
return crop(self.ui_mask_os, area)
@cached_property
def tile_center_image(self):

View File

@ -36,7 +36,7 @@ class OSFleet(OSCamera, Combat, Fleet, OSAsh):
Remove non-exist things like strategy, round.
"""
# self.handle_strategy(index=1 if not self.fleets_reversed() else 2)
# self.update()
self.update()
# if self.handle_fleet_reverse():
# self.handle_strategy(index=1)
self.hp_reset()