Add: Logic fleet_2_rescue, Logic for chapter 3

- Fix camera outside map caused by info bar
- Fix mis-detection of is_caught_by_siren
- Fix grid attribute is_caught_by_siren will be kept to next attack
- Fix find_current_fleet when ammo icon of another fleet is covered by the green arrow of current fleet
- Fix fleet_boss_index
- Fix can not predict when boss appear on fleet's face
This commit is contained in:
LmeSzinc 2020-06-05 03:51:54 +08:00
parent 6548677c80
commit 81f9b61ea5
12 changed files with 123 additions and 45 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

@ -14,9 +14,9 @@ MAP.map_data = '''
''' '''
MAP.weight_data = ''' MAP.weight_data = '''
30 30 30 20 10 10 10 30 30 30 20 10 10 10
30 30 30 20 10 10 10 30 30 30 20 10 09 10
40 40 40 20 10 10 10
40 40 40 20 10 10 10 40 40 40 20 10 10 10
40 40 40 20 20 10 10
''' '''
MAP.spawn_data = [ MAP.spawn_data = [
{'battle': 0, 'enemy': 2, 'mystery': 1}, {'battle': 0, 'enemy': 2, 'mystery': 1},
@ -36,6 +36,9 @@ class Config:
FLEET_BOSS = 1 FLEET_BOSS = 1
MAP_MYSTERY_HAS_CARRIER = True MAP_MYSTERY_HAS_CARRIER = True
INTERNAL_LINES_HOUGHLINES_THRESHOLD = 40
EDGE_LINES_HOUGHLINES_THRESHOLD = 40
INTERNAL_LINES_FIND_PEAKS_PARAMETERS = { INTERNAL_LINES_FIND_PEAKS_PARAMETERS = {
'height': (120, 255 - 40), 'height': (120, 255 - 40),
'width': (1.5, 10), 'width': (1.5, 10),
@ -54,6 +57,11 @@ class Campaign(CampaignBase):
MAP = MAP MAP = MAP
def battle_0(self): def battle_0(self):
self.fleet_2_push_forward()
if self.fleet_2_rescue(G2):
return True
self.clear_all_mystery() self.clear_all_mystery()
return self.battle_default() return self.battle_default()
@ -64,4 +72,4 @@ class Campaign(CampaignBase):
if not self.check_accessibility(G2, fleet='boss'): if not self.check_accessibility(G2, fleet='boss'):
return self.fleet_boss.battle_default() return self.fleet_boss.battle_default()
return self.clear_boss() return self.fleet_boss.clear_boss()

View File

@ -15,10 +15,10 @@ MAP.map_data = '''
SP ME -- -- ME MM -- ++ SP ME -- -- ME MM -- ++
''' '''
MAP.weight_data = ''' MAP.weight_data = '''
50 50 50 30 30 20 10 10 50 50 50 30 30 20 10 09
50 50 40 40 30 20 10 10 50 50 40 40 30 20 10 10
50 50 50 40 40 20 20 20 50 50 50 40 40 50 20 20
50 50 50 50 35 30 30 30 50 50 50 50 35 50 50 50
''' '''
MAP.spawn_data = [ MAP.spawn_data = [
{'battle': 0, 'enemy': 2, 'mystery': 1}, {'battle': 0, 'enemy': 2, 'mystery': 1},
@ -38,11 +38,17 @@ class Campaign(CampaignBase):
MAP = MAP MAP = MAP
def battle_0(self): def battle_0(self):
self.fleet_2_push_forward()
if self.fleet_2_rescue(H1):
return True
self.clear_all_mystery() self.clear_all_mystery()
return self.battle_default() return self.battle_default()
def battle_3(self): def battle_3(self):
# print(H1.__dict__)
self.clear_all_mystery() self.clear_all_mystery()
if not self.check_accessibility(H1, fleet='boss'): if not self.check_accessibility(H1, fleet='boss'):

View File

@ -18,8 +18,8 @@ MAP.weight_data = '''
50 50 30 30 50 50 50 50 30 30 50 50
50 50 30 30 50 50 50 50 30 30 50 50
50 50 20 30 50 50 50 50 20 30 50 50
10 10 10 20 50 50 09 10 11 20 50 50
10 10 10 50 50 50 10 10 11 50 50 50
''' '''
MAP.spawn_data = [ MAP.spawn_data = [
{'battle': 0, 'enemy': 2, 'mystery': 1}, {'battle': 0, 'enemy': 2, 'mystery': 1},
@ -40,6 +40,11 @@ class Campaign(CampaignBase):
MAP = MAP MAP = MAP
def battle_0(self): def battle_0(self):
self.fleet_2_push_forward()
if self.fleet_2_rescue(A4):
return True
self.clear_all_mystery() self.clear_all_mystery()
return self.battle_default() return self.battle_default()

View File

@ -18,8 +18,8 @@ MAP.map_data = '''
MAP.weight_data = ''' MAP.weight_data = '''
40 40 40 40 40 40 40 40 40 40 40 40 40 40 40 40
40 40 40 30 30 30 30 30 40 40 40 30 30 30 30 30
40 40 30 30 20 10 10 10 40 40 30 30 20 10 10 09
40 40 30 20 20 10 10 10 40 40 30 20 20 10 10 09
''' '''
MAP.spawn_data = [ MAP.spawn_data = [
{'battle': 0, 'enemy': 2}, {'battle': 0, 'enemy': 2},
@ -38,15 +38,16 @@ A4, B4, C4, D4, E4, F4, G4, H4, \
class Config(Config31): class Config(Config31):
MAP_MYSTERY_HAS_CARRIER = False MAP_MYSTERY_HAS_CARRIER = False
# Map 3-4 is relatively small for the density of enemies.
INTERNAL_LINES_HOUGHLINES_THRESHOLD = 40
EDGE_LINES_HOUGHLINES_THRESHOLD = 40
class Campaign(CampaignBase): class Campaign(CampaignBase):
MAP = MAP MAP = MAP
def battle_0(self): def battle_0(self):
self.fleet_2_push_forward()
if self.fleet_2_rescue(H3):
return True
return self.battle_default() return self.battle_default()
def battle_3(self): def battle_3(self):

View File

@ -111,7 +111,15 @@ class Camera(InfoHandler):
self.grids.update(image=self.device.image) self.grids.update(image=self.device.image)
return True return True
self.grids = Grids(self.device.image, config=self.config) try:
self.grids = Grids(self.device.image, config=self.config)
except PerspectiveError as e:
if self.info_bar_count():
logger.info('Perspective error cause by info bar. Waiting.')
self.handle_info_bar()
return self.update(camera=camera)
else:
raise e
# Catch perspective error # Catch perspective error
known_exception = self.info_bar_count() known_exception = self.info_bar_count()

View File

@ -1,5 +1,6 @@
import itertools import itertools
from module.base.timer import Timer from module.base.timer import Timer
from module.exception import MapWalkError from module.exception import MapWalkError
from module.handler.ambush import AmbushHandler from module.handler.ambush import AmbushHandler
@ -58,7 +59,7 @@ class Fleet(Camera, MapOperation, AmbushHandler):
@property @property
def fleet_boss_index(self): def fleet_boss_index(self):
if self.config.FLEET_BOSS == 2 or self.config.FLEET_2: if self.config.FLEET_BOSS == 2 or self.config.FLEET_2:
return 1 return 2
else: else:
return 1 return 1
@ -265,7 +266,12 @@ class Fleet(Camera, MapOperation, AmbushHandler):
for loca in [self.fleet_1_location, self.fleet_2_location]: for loca in [self.fleet_1_location, self.fleet_2_location]:
if len(loca) and loca in self.map: if len(loca) and loca in self.map:
self.map[loca].wipe_out() grid = self.map[loca]
if grid.may_boss and grid.is_caught_by_siren:
# Only boss appears on fleet's face
pass
else:
self.map[loca].wipe_out()
def find_all_fleets(self): def find_all_fleets(self):
logger.hr('Find all fleets') logger.hr('Find all fleets')
@ -306,7 +312,12 @@ class Fleet(Camera, MapOperation, AmbushHandler):
self.fleet_1 = another.location self.fleet_1 = another.location
self.fleet_2 = fleets[0].location self.fleet_2 = fleets[0].location
else: else:
self.find_all_fleets() cover = self.map.grid_covered(fleets[0], location=[(0, -1)])
if fleets[0].is_current_fleet and len(cover) and cover[0].is_spawn_point:
self.fleet_1 = fleets[0].location
self.fleet_2 = cover[0].location
else:
self.find_all_fleets()
elif count == 2: elif count == 2:
current = self.map.select(is_current_fleet=True) current = self.map.select(is_current_fleet=True)
if current.count == 1: if current.count == 1:

View File

@ -139,11 +139,17 @@ class GridInfo:
ignore_may (bool): Ignore map_data, force update. ignore_may (bool): Ignore map_data, force update.
ignore_cleared (bool): Ignore is_cleared property. ignore_cleared (bool): Ignore is_cleared property.
""" """
if info.is_caught_by_siren:
self.is_caught_by_siren = True
for item in ['boss', 'siren']: for item in ['boss', 'siren']:
if info.enemy_scale or self.enemy_scale: if info.enemy_scale or self.enemy_scale:
break break
if info.__getattribute__('is_' + item): if info.__getattribute__('is_' + item):
flag = not info.is_fleet and not self.is_fleet if item == 'boss':
flag = not info.is_fleet
else:
flag = not info.is_fleet and not self.is_fleet
if not ignore_may: if not ignore_may:
flag &= self.__getattribute__('may_' + item) flag &= self.__getattribute__('may_' + item)
if not ignore_cleared: if not ignore_cleared:
@ -186,8 +192,6 @@ class GridInfo:
self.is_fleet = info.is_fleet self.is_fleet = info.is_fleet
if info.is_current_fleet: if info.is_current_fleet:
self.is_current_fleet = True self.is_current_fleet = True
if info.is_caught_by_siren:
self.is_caught_by_siren = True
return False return False
def wipe_out(self): def wipe_out(self):
@ -201,6 +205,7 @@ class GridInfo:
self.is_boss = False self.is_boss = False
self.is_ammo = False self.is_ammo = False
self.is_siren = False self.is_siren = False
self.is_caught_by_siren = False
def reset(self): def reset(self):
""" """

View File

@ -267,4 +267,3 @@ class GridPredictor:
return name return name
return None return None

View File

@ -237,7 +237,8 @@ class Map(Fleet):
bool: bool:
""" """
grids = self.map.select(is_boss=True, is_accessible=True) grids = self.map.select(is_boss=True, is_accessible=True)
logger.info('Is boss: %s' % self.map.select(is_boss=True)) grids = grids.add(self.map.select(may_boss=True, is_caught_by_siren=True))
logger.info('Is boss: %s' % grids)
if not grids.count: if not grids.count:
grids = grids.add(self.map.select(may_boss=True, is_enemy=True, is_accessible=True)) grids = grids.add(self.map.select(may_boss=True, is_enemy=True, is_accessible=True))
logger.warning('Boss not detected, using may_boss grids.') logger.warning('Boss not detected, using may_boss grids.')
@ -277,6 +278,7 @@ class Map(Fleet):
def brute_clear_boss(self): def brute_clear_boss(self):
""" """
Method to clear boss, using brute-force to find roadblocks. Method to clear boss, using brute-force to find roadblocks.
Note: This method will use 2 fleets.
""" """
boss = self.map.select(is_boss=True) boss = self.map.select(is_boss=True)
if boss: if boss:
@ -296,7 +298,7 @@ class Map(Fleet):
elif self.map.select(may_boss=True, is_caught_by_siren=True): elif self.map.select(may_boss=True, is_caught_by_siren=True):
logger.info('BOSS appear on fleet grid') logger.info('BOSS appear on fleet grid')
self.fleet_2.switch_to() self.fleet_2.switch_to()
self.clear_chosen_enemy(self.map.select(may_boss=True, is_caught_by_siren=True)[0]) return self.clear_chosen_enemy(self.map.select(may_boss=True, is_caught_by_siren=True)[0])
else: else:
logger.warning('BOSS not detected, trying all boss spawn point.') logger.warning('BOSS not detected, trying all boss spawn point.')
return self.clear_potential_boss() return self.clear_potential_boss()
@ -442,3 +444,26 @@ class Map(Fleet):
self.fleet_2.goto(grids[0]) self.fleet_2.goto(grids[0])
self.fleet_1.switch_to() self.fleet_1.switch_to()
return True return True
def fleet_2_rescue(self, grid):
"""Use mob fleet to rescue boss fleet.
Args:
grid (GridInfo): Destination. Usually to be boss spawn grid.
Returns:
bool: If clear an enemy.
"""
if not self.config.FLEET_2:
return False
grids = self.brute_find_roadblocks(grid, fleet=2)
if not grids:
return False
logger.info('Fleet_2 rescue')
grids = self.select_grids(grids)
if not grids:
return False
self.clear_chosen_enemy(grids[0])
return True

View File

@ -392,6 +392,22 @@ class CampaignMap:
return path return path
def grid_covered(self, grid, location=None):
"""
Args:
grid (GridInfo)
location (list[tuple[int]]): Relative coordinate of the covered grid.
Returns:
list[GridInfo]:
"""
if location is None:
covered = [tuple(np.array(grid.location) + upper) for upper in grid.covered_grid()]
else:
covered = [tuple(np.array(grid.location) + upper) for upper in location]
covered = [self[upper] for upper in covered if upper in self]
return covered
def missing_get(self, battle_count, mystery_count=0, siren_count=0, carrier_count=0): def missing_get(self, battle_count, mystery_count=0, siren_count=0, carrier_count=0):
try: try:
missing = self.spawn_data[battle_count].copy() missing = self.spawn_data[battle_count].copy()
@ -408,15 +424,12 @@ class CampaignMap:
missing[attr] -= 1 missing[attr] -= 1
for grid in self: for grid in self:
for upper in grid.covered_grid(): for upper in self.grid_covered(grid):
upper = tuple(np.array(grid.location) + upper) for attr in ['enemy', 'mystery', 'siren', 'boss']:
if upper in self: if upper.__getattribute__('may_' + attr) and not upper.__getattribute__('is_' + attr):
upper = self[upper] may[attr] += 1
for attr in ['enemy', 'mystery', 'siren', 'boss']: if upper.may_carrier:
if upper.__getattribute__('may_' + attr) and not upper.__getattribute__('is_' + attr): may['carrier'] += 1
may[attr] += 1
if upper.may_carrier:
may['carrier'] += 1
logger.attr('enemy_missing', logger.attr('enemy_missing',
', '.join([f'{k[:2].upper()}:{str(v).rjust(2)}' for k, v in missing.items() if k != 'battle'])) ', '.join([f'{k[:2].upper()}:{str(v).rjust(2)}' for k, v in missing.items() if k != 'battle']))
@ -444,18 +457,15 @@ class CampaignMap:
# predict # predict
for grid in self: for grid in self:
for upper in grid.covered_grid(): for upper in self.grid_covered(grid):
upper = tuple(np.array(grid.location) + upper) for attr in ['enemy', 'mystery', 'siren', 'boss']:
if upper in self: if upper.__getattribute__('may_' + attr) and missing[attr] > 0 and missing[attr] == may[attr]:
upper = self[upper] logger.info('Predict %s to be %s' % (location2node(upper.location), attr))
for attr in ['enemy', 'mystery', 'siren', 'boss']: upper.__setattr__('is_' + attr, True)
if upper.__getattribute__('may_' + attr) and missing[attr] > 0 and missing[attr] == may[attr]: if carrier_count:
logger.info('Predict %s to be %s' % (location2node(upper.location), attr)) if upper.may_carrier and missing['carrier'] > 0 and missing['carrier'] == may['carrier']:
upper.__setattr__('is_' + attr, True) logger.info('Predict %s to be enemy' % location2node(upper.location))
if carrier_count: upper.__setattr__('is_enemy', True)
if upper.may_carrier and missing['carrier'] > 0 and missing['carrier'] == may['carrier']:
logger.info('Predict %s to be enemy' % location2node(upper.location))
upper.__setattr__('is_enemy', True)
def select(self, **kwargs): def select(self, **kwargs):
""" """