1
0
mirror of https://gitee.com/sui-feng-cb/AzurLaneAutoScript1 synced 2026-03-28 19:44:04 +08:00

Merge pull request #7 from guoh064/exercise_period_ocr

Exercise period ocr
This commit is contained in:
guoh064
2023-04-09 14:09:53 +08:00
committed by GitHub
10 changed files with 126 additions and 146 deletions

View File

@@ -1466,8 +1466,7 @@
"Exercise": { "Exercise": {
"OpponentChooseMode": "max_exp", "OpponentChooseMode": "max_exp",
"OpponentTrial": 1, "OpponentTrial": 1,
"ExercisePreserve": 5, "ExerciseStrategy": "sun18",
"AdmiralTrialTime": "sun18",
"LowHpThreshold": 0.4, "LowHpThreshold": 0.4,
"LowHpConfirmWait": 0.1, "LowHpConfirmWait": 0.1,
"OpponentRefreshValue": 0, "OpponentRefreshValue": 0,

View File

@@ -7546,18 +7546,11 @@
"type": "input", "type": "input",
"value": 1 "value": 1
}, },
"ExercisePreserve": { "ExerciseStrategy": {
"type": "select",
"value": 5,
"option": [
0,
5
]
},
"AdmiralTrialTime": {
"type": "select", "type": "select",
"value": "sun18", "value": "sun18",
"option": [ "option": [
"aggressive",
"sun18", "sun18",
"sun12", "sun12",
"sun0", "sun0",

View File

@@ -573,12 +573,9 @@ Exercise:
value: max_exp value: max_exp
option: [ max_exp, easiest, leftmost, easiest_else_exp ] option: [ max_exp, easiest, leftmost, easiest_else_exp ]
OpponentTrial: 1 OpponentTrial: 1
ExercisePreserve: ExerciseStrategy:
value: 5
option: [ 0, 5 ]
AdmiralTrialTime:
value: sun18 value: sun18
option: [ sun18, sun12, sun0, sat18, sat12, sat0, fri18 ] option: [ aggressive, sun18, sun12, sun0, sat18, sat12, sat0, fri18 ]
LowHpThreshold: 0.4 LowHpThreshold: 0.4
LowHpConfirmWait: 0.1 LowHpConfirmWait: 0.1
OpponentRefreshValue: 0 OpponentRefreshValue: 0

View File

@@ -340,8 +340,7 @@ class GeneratedConfig:
# Group `Exercise` # Group `Exercise`
Exercise_OpponentChooseMode = 'max_exp' # max_exp, easiest, leftmost, easiest_else_exp Exercise_OpponentChooseMode = 'max_exp' # max_exp, easiest, leftmost, easiest_else_exp
Exercise_OpponentTrial = 1 Exercise_OpponentTrial = 1
Exercise_ExercisePreserve = 5 # 0, 5 Exercise_ExerciseStrategy = 'sun18' # aggressive, sun18, sun12, sun0, sat18, sat12, sat0, fri18
Exercise_AdmiralTrialTime = 'sun18' # sun18, sun12, sun0, sat18, sat12, sat0, fri18
Exercise_LowHpThreshold = 0.4 Exercise_LowHpThreshold = 0.4
Exercise_LowHpConfirmWait = 0.1 Exercise_LowHpConfirmWait = 0.1
Exercise_OpponentRefreshValue = 0 Exercise_OpponentRefreshValue = 0

View File

@@ -2035,22 +2035,17 @@
"name": "Each Opponent Try X Time(s)", "name": "Each Opponent Try X Time(s)",
"help": "1 ~ Positive Infinity" "help": "1 ~ Positive Infinity"
}, },
"ExercisePreserve": { "ExerciseStrategy": {
"name": "Keep X Number Remain(s)", "name": "Exercise Strategy (Keep X number remains)",
"help": "0 means run until 0/10\n5 means run until 5/10 normally and use all remains on Sunday evening", "help": "If keeping 5 number remains, will try admiral at set time and clear number remains at last recover",
"0": "0", "aggressive": "0",
"5": "5" "sun18": "5 until Sunday 18pm",
}, "sun12": "5 until Sunday 12pm",
"AdmiralTrialTime": { "sun0": "5 until Sunday 12am",
"name": "Try using all preserved remains for admiral at X", "sat18": "5 until Saturday 18pm",
"help": "Only applies if keeping 5 remains, will use all remains at X to go for admiral", "sat12": "5 until Saturday 12pm",
"sun18": "Sunday 18pm", "sat0": "5 until Saturday 12am",
"sun12": "Sunday 12pm", "fri18": "5 until Friday 18pm"
"sun0": "Sunday 12am",
"sat18": "Saturday 18pm",
"sat12": "Saturday 12pm",
"sat0": "Saturday 12am",
"fri18": "Friday 18pm"
}, },
"LowHpThreshold": { "LowHpThreshold": {
"name": "Low HP Threshold", "name": "Low HP Threshold",

View File

@@ -2035,15 +2035,10 @@
"name": "Exercise.OpponentTrial.name", "name": "Exercise.OpponentTrial.name",
"help": "Exercise.OpponentTrial.help" "help": "Exercise.OpponentTrial.help"
}, },
"ExercisePreserve": { "ExerciseStrategy": {
"name": "Exercise.ExercisePreserve.name", "name": "Exercise.ExerciseStrategy.name",
"help": "Exercise.ExercisePreserve.help", "help": "Exercise.ExerciseStrategy.help",
"0": "0", "aggressive": "aggressive",
"5": "5"
},
"AdmiralTrialTime": {
"name": "Exercise.AdmiralTrialTime.name",
"help": "Exercise.AdmiralTrialTime.help",
"sun18": "sun18", "sun18": "sun18",
"sun12": "sun12", "sun12": "sun12",
"sun0": "sun0", "sun0": "sun0",

View File

@@ -2035,22 +2035,17 @@
"name": "每个对手尝试 X 次", "name": "每个对手尝试 X 次",
"help": "" "help": ""
}, },
"ExercisePreserve": { "ExerciseStrategy": {
"name": "保留 X 次演习次数", "name": "演习策略",
"help": "保留 5 次时会在周日晚上强制清空剩余次数", "help": "保留 5 次,则会在设定时间尝试冲击元帅,并在周日 18 点刷新后清空所有次数",
"0": "0", "aggressive": "保留 0 次",
"5": "5" "sun18": "保留 5 次直到星期日 18 点",
}, "sun12": "保留 5 次直到星期日 12 点",
"AdmiralTrialTime": { "sun0": "保留 5 次直到星期日 0 点",
"name": "在 X 时冲击元帅", "sat18": "保留 5 次直到星期六 18 点",
"help": "仅当保留 5 次演习次数时生效。只在设定时间点通过用光所有次数来尝试达到元帅", "sat12": "保留 5 次直到星期六 12 点",
"sun18": "星期天18点", "sat0": "保留 5 次直到星期六 0 点",
"sun12": "星期天12点", "fri18": "保留 5 次直到星期五 18 点"
"sun0": "星期天0点",
"sat18": "星期六18点",
"sat12": "星期六12点",
"sat0": "星期六0点",
"fri18": "星期五18点"
}, },
"LowHpThreshold": { "LowHpThreshold": {
"name": "血量低于 X 后撤退", "name": "血量低于 X 后撤退",

View File

@@ -2035,22 +2035,17 @@
"name": "每個對手嘗試 X 次", "name": "每個對手嘗試 X 次",
"help": "" "help": ""
}, },
"ExercisePreserve": { "ExerciseStrategy": {
"name": "保留 X 次演習次數", "name": "演習策略",
"help": "保留 5 次時會在周日晚上强制清空剩餘次數", "help": "保留 5 次則會在設定時間嘗試衝擊元帥並在周日18點刷新后清空所有次數",
"0": "0", "aggressive": "保留 0 次",
"5": "5" "sun18": "保留 5 次直到星期日 18 點",
}, "sun12": "保留 5 次直到星期日 12 點",
"AdmiralTrialTime": { "sun0": "保留 5 次直到星期日 0 點",
"name": "在 X 時衝擊元帥,", "sat18": "保留 5 次直到星期六 18 點",
"help": "僅當保留 5 次演習次數時生效,只在設定時間時嘗試通過清空所有次數來達到元帥", "sat12": "保留 5 次直到星期六 12 點",
"sun18": "周日18點", "sat0": "保留 5 次直到星期六 0 點",
"sun12": "周日12點", "fri18": "保留 5 次直到星期五 18 點"
"sun0": "周日0點",
"sat18": "周六18點",
"sat12": "周六12點",
"sat0": "sat0",
"fri18": "fri18"
}, },
"LowHpThreshold": { "LowHpThreshold": {
"name": "血量低於 X 後撤退", "name": "血量低於 X 後撤退",

View File

@@ -3,13 +3,66 @@ from module.config.utils import get_server_last_update
from module.exercise.assets import * from module.exercise.assets import *
from module.exercise.combat import ExerciseCombat from module.exercise.combat import ExerciseCombat
from module.logger import logger from module.logger import logger
from module.ocr.ocr import DatedDuration, Digit from module.ocr.ocr import Digit, Ocr, OcrYuv
from module.ui.ui import page_exercise from module.ui.ui import page_exercise
class DatedDuration(Ocr):
def __init__(self, buttons, lang='cnocr', letter=(255, 255, 255), threshold=128, alphabet='0123456789:IDS天日d',
name=None):
super().__init__(buttons, lang=lang, letter=letter, threshold=threshold, alphabet=alphabet, name=name)
def after_process(self, result):
result = super().after_process(result)
result = result.replace('I', '1').replace('D', '0').replace('S', '5')
return result
def ocr(self, image, direct_ocr=False):
"""
Do OCR on a dated duration, such as `10d 01:30:30` or `7日01:30:30`.
Args:
image:
direct_ocr:
Returns:
list, datetime.timedelta: timedelta object, or a list of it.
"""
result_list = super().ocr(image, direct_ocr=direct_ocr)
if not isinstance(result_list, list):
result_list = [result_list]
result_list = [self.parse_time(result) for result in result_list]
if len(self.buttons) == 1:
result_list = result_list[0]
return result_list
@staticmethod
def parse_time(string):
"""
Args:
string (str): `10d 01:30:30` or `7日01:30:30`
Returns:
datetime.timedelta:
"""
import re
result = re.search(r'(\d{1,2})\D?(\d{1,2}):?(\d{2}):?(\d{2})', string)
if result:
result = [int(s) for s in result.groups()]
return timedelta(days=result[0], hours=result[1], minutes=result[2], seconds=result[3])
else:
logger.warning(f'Invalid dated duration: {string}')
return timedelta(days=0, hours=0, minutes=0, seconds=0)
class DatedDurationYuv(DatedDuration, OcrYuv):
pass
OCR_EXERCISE_REMAIN = Digit(OCR_EXERCISE_REMAIN, letter=(173, 247, 74), threshold=128) OCR_EXERCISE_REMAIN = Digit(OCR_EXERCISE_REMAIN, letter=(173, 247, 74), threshold=128)
OCR_PERIOD_REMAIN = DatedDuration(OCR_PERIOD_REMAIN, letter=(255, 255, 255), threshold=128) OCR_PERIOD_REMAIN = DatedDuration(OCR_PERIOD_REMAIN, letter=(255, 255, 255), threshold=128)
ADMIRAL_TRIAL_HOUR_INTERVAL = { ADMIRAL_TRIAL_HOUR_INTERVAL = {
# "aggressive": [336, 0]
"sun18": [6, 0], "sun18": [6, 0],
"sun12": [12, 6], "sun12": [12, 6],
"sun0": [24, 12], "sun0": [24, 12],
@@ -19,9 +72,12 @@ ADMIRAL_TRIAL_HOUR_INTERVAL = {
"fri18": [56, 48] "fri18": [56, 48]
} }
class Exercise(ExerciseCombat): class Exercise(ExerciseCombat):
opponent_change_count = 0 opponent_change_count = 0
remain = 0 remain = 0
preserve = 0
def _new_opponent(self): def _new_opponent(self):
logger.info('New opponent') logger.info('New opponent')
@@ -118,7 +174,7 @@ class Exercise(ExerciseCombat):
def server_support_ocr_reset_remain(self) -> bool: def server_support_ocr_reset_remain(self) -> bool:
return self.config.SERVER in ['jp'] return self.config.SERVER in ['cn', 'en', 'jp']
def _get_exercise_reset_remain(self): def _get_exercise_reset_remain(self):
@@ -129,11 +185,27 @@ class Exercise(ExerciseCombat):
result = OCR_PERIOD_REMAIN.ocr(self.device.image) result = OCR_PERIOD_REMAIN.ocr(self.device.image)
return result return result
def _get_exercise_strategy(self):
"""
Returns:
int: ExercisePreserve, X times to remain
list, int: Admiral trial time period
"""
if self.config.Exercise_ExerciseStrategy == "aggressive":
preserve = 0
admiral_interval = None
else:
preserve = 5
admiral_interval = ADMIRAL_TRIAL_HOUR_INTERVAL[self.config.Exercise_ExerciseStrategy]
return preserve, admiral_interval
def run(self): def run(self):
self.ui_ensure(page_exercise) self.ui_ensure(page_exercise)
self.opponent_change_count = self._get_opponent_change_count() self.opponent_change_count = self._get_opponent_change_count()
logger.attr("Change_opponent_count", self.opponent_change_count) logger.attr("Change_opponent_count", self.opponent_change_count)
self.preserve, admiral_interval = self._get_exercise_strategy()
if not self.server_support_ocr_reset_remain(): if not self.server_support_ocr_reset_remain():
logger.info(f'Server {self.config.SERVER} does not yet support OCR exercise reset remain time') logger.info(f'Server {self.config.SERVER} does not yet support OCR exercise reset remain time')
@@ -142,26 +214,19 @@ class Exercise(ExerciseCombat):
else: else:
remain_time = OCR_PERIOD_REMAIN.ocr(self.device.image) remain_time = OCR_PERIOD_REMAIN.ocr(self.device.image)
needs_restore = False if admiral_interval is not None and remain_time:
if self.config.Exercise_ExercisePreserve == 5 and remain_time: admiral_start, admiral_end = admiral_interval
admiral_start, admiral_end = ADMIRAL_TRIAL_HOUR_INTERVAL[self.config.Exercise_AdmiralTrialTime]
if admiral_start > int(remain_time.total_seconds() // 3600) >= admiral_end: #set time for getting admiral if admiral_start > int(remain_time.total_seconds() // 3600) >= admiral_end: #set time for getting admiral
needs_restore = True logger.info('Reach set time for admiral trial, using all attempts.')
logger.hr(f'Reach set time for admiral trial, using all attempts.') self.preserve = 0
backup = self.config.temporary(
Exercise_ExercisePreserve=0
)
elif int(remain_time.total_seconds() // 3600) < 6: #if not set to "sun18", still depleting at sunday 18pm. elif int(remain_time.total_seconds() // 3600) < 6: #if not set to "sun18", still depleting at sunday 18pm.
needs_restore = True logger.info('Exercise period remain less than 6 hours, using all attempts.')
logger.hr(f'Exercise period remain less than 6 hours, using all attempts.') self.preserve = 0
backup = self.config.temporary(
Exercise_ExercisePreserve=0
)
while 1: while 1:
self.remain = OCR_EXERCISE_REMAIN.ocr(self.device.image) self.remain = OCR_EXERCISE_REMAIN.ocr(self.device.image)
if self.remain <= self.config.Exercise_ExercisePreserve: if self.remain <= self.preserve:
break break
logger.hr(f'Exercise remain {self.remain}', level=1) logger.hr(f'Exercise remain {self.remain}', level=1)
@@ -172,17 +237,14 @@ class Exercise(ExerciseCombat):
if not success: if not success:
logger.info('New opponent exhausted') logger.info('New opponent exhausted')
break break
# Restore user settings if necessary after final exercise.
if needs_restore:
backup.recover()
# self.equipment_take_off_when_finished() # self.equipment_take_off_when_finished()
# Scheduler # Scheduler
with self.config.multi_set(): with self.config.multi_set():
self.config.set_record(Exercise_OpponentRefreshValue=self.opponent_change_count) self.config.set_record(Exercise_OpponentRefreshValue=self.opponent_change_count)
if self.remain <= self.config.Exercise_ExercisePreserve or self.opponent_change_count >= 5: if self.remain <= self.preserve or self.opponent_change_count >= 5:
self.config.task_delay(server_update=True) self.config.task_delay(server_update=True)
else: else:
self.config.task_delay(success=False) self.config.task_delay(success=False)

View File

@@ -251,53 +251,3 @@ class Duration(Ocr):
class DurationYuv(Duration, OcrYuv): class DurationYuv(Duration, OcrYuv):
pass pass
class DatedDuration(Ocr):
def __init__(self, buttons, lang='cnocr', letter=(255, 255, 255), threshold=128, alphabet='0123456789:IDS天日d',
name=None):
super().__init__(buttons, lang=lang, letter=letter, threshold=threshold, alphabet=alphabet, name=name)
def after_process(self, result):
result = super().after_process(result)
result = result.replace('I', '1').replace('D', '0').replace('S', '5')
return result
def ocr(self, image, direct_ocr=False):
"""
Do OCR on a dated duration, such as `10d 01:30:30` or `7日01:30:30`.
Args:
image:
direct_ocr:
Returns:
list, datetime.timedelta: timedelta object, or a list of it.
"""
result_list = super().ocr(image, direct_ocr=direct_ocr)
if not isinstance(result_list, list):
result_list = [result_list]
result_list = [self.parse_time(result) for result in result_list]
if len(self.buttons) == 1:
result_list = result_list[0]
return result_list
@staticmethod
def parse_time(string):
"""
Args:
string (str): `10d 01:30:30` or `7日01:30:30`
Returns:
datetime.timedelta:
"""
result = re.search(r'(\d{1,2})\D?(\d{1,2}):?(\d{2}):?(\d{2})', string)
if result:
result = [int(s) for s in result.groups()]
return timedelta(days=result[0], hours=result[1], minutes=result[2], seconds=result[3])
else:
logger.warning(f'Invalid dated duration: {string}')
return timedelta(days=0, hours=0, minutes=0, seconds=0)
class DatedDurationYuv(DatedDuration, OcrYuv):
pass