diff --git a/arknights_mower/models/recruit.pkl b/arknights_mower/models/recruit.pkl new file mode 100644 index 000000000..628830563 Binary files /dev/null and b/arknights_mower/models/recruit.pkl differ diff --git a/arknights_mower/models/recruit_result.pkl b/arknights_mower/models/recruit_result.pkl new file mode 100644 index 000000000..98aeea042 Binary files /dev/null and b/arknights_mower/models/recruit_result.pkl differ diff --git a/arknights_mower/resources/recruit.png b/arknights_mower/resources/recruit.png deleted file mode 100644 index 308fffeea..000000000 Binary files a/arknights_mower/resources/recruit.png and /dev/null differ diff --git a/arknights_mower/resources/agent_token.png b/arknights_mower/resources/recruit/agent_token.png similarity index 100% rename from arknights_mower/resources/agent_token.png rename to arknights_mower/resources/recruit/agent_token.png diff --git a/arknights_mower/resources/recruit/agent_token_first.png b/arknights_mower/resources/recruit/agent_token_first.png new file mode 100644 index 000000000..13b298259 Binary files /dev/null and b/arknights_mower/resources/recruit/agent_token_first.png differ diff --git a/arknights_mower/resources/available_level.png b/arknights_mower/resources/recruit/available_level.png similarity index 100% rename from arknights_mower/resources/available_level.png rename to arknights_mower/resources/recruit/available_level.png diff --git a/arknights_mower/resources/recruit/begin_recruit.png b/arknights_mower/resources/recruit/begin_recruit.png new file mode 100644 index 000000000..0954a7382 Binary files /dev/null and b/arknights_mower/resources/recruit/begin_recruit.png differ diff --git a/arknights_mower/resources/career_needs.png b/arknights_mower/resources/recruit/career_needs.png similarity index 100% rename from arknights_mower/resources/career_needs.png rename to arknights_mower/resources/recruit/career_needs.png diff --git a/arknights_mower/resources/job_requirements.png b/arknights_mower/resources/recruit/job_requirements.png similarity index 100% rename from arknights_mower/resources/job_requirements.png rename to arknights_mower/resources/recruit/job_requirements.png diff --git a/arknights_mower/resources/recruit/lmb.png b/arknights_mower/resources/recruit/lmb.png new file mode 100644 index 000000000..63dbc5dda Binary files /dev/null and b/arknights_mower/resources/recruit/lmb.png differ diff --git a/arknights_mower/resources/recruit/recruit_done.png b/arknights_mower/resources/recruit/recruit_done.png new file mode 100644 index 000000000..181d1fbe1 Binary files /dev/null and b/arknights_mower/resources/recruit/recruit_done.png differ diff --git a/arknights_mower/resources/recruit/recruit_lock.png b/arknights_mower/resources/recruit/recruit_lock.png new file mode 100644 index 000000000..c43bb58e9 Binary files /dev/null and b/arknights_mower/resources/recruit/recruit_lock.png differ diff --git a/arknights_mower/resources/recruit/refresh.png b/arknights_mower/resources/recruit/refresh.png new file mode 100644 index 000000000..8d3fb3e99 Binary files /dev/null and b/arknights_mower/resources/recruit/refresh.png differ diff --git a/arknights_mower/resources/recruit/refresh_comfirm.png b/arknights_mower/resources/recruit/refresh_comfirm.png new file mode 100644 index 000000000..5f6e05fc3 Binary files /dev/null and b/arknights_mower/resources/recruit/refresh_comfirm.png differ diff --git a/arknights_mower/resources/recruit/riic_res/CASTER.png b/arknights_mower/resources/recruit/riic_res/CASTER.png new file mode 100644 index 000000000..fee4f5a4b Binary files /dev/null and b/arknights_mower/resources/recruit/riic_res/CASTER.png differ diff --git a/arknights_mower/resources/recruit/riic_res/MEDIC.png b/arknights_mower/resources/recruit/riic_res/MEDIC.png new file mode 100644 index 000000000..19c4c47df Binary files /dev/null and b/arknights_mower/resources/recruit/riic_res/MEDIC.png differ diff --git a/arknights_mower/resources/recruit/riic_res/PIONEER.png b/arknights_mower/resources/recruit/riic_res/PIONEER.png new file mode 100644 index 000000000..77defdf22 Binary files /dev/null and b/arknights_mower/resources/recruit/riic_res/PIONEER.png differ diff --git a/arknights_mower/resources/recruit/riic_res/SNIPER.png b/arknights_mower/resources/recruit/riic_res/SNIPER.png new file mode 100644 index 000000000..4ced1d41a Binary files /dev/null and b/arknights_mower/resources/recruit/riic_res/SNIPER.png differ diff --git a/arknights_mower/resources/recruit/riic_res/SPECIAL.png b/arknights_mower/resources/recruit/riic_res/SPECIAL.png new file mode 100644 index 000000000..f0592b04e Binary files /dev/null and b/arknights_mower/resources/recruit/riic_res/SPECIAL.png differ diff --git a/arknights_mower/resources/recruit/riic_res/SUPPORT.png b/arknights_mower/resources/recruit/riic_res/SUPPORT.png new file mode 100644 index 000000000..8aa9ee364 Binary files /dev/null and b/arknights_mower/resources/recruit/riic_res/SUPPORT.png differ diff --git a/arknights_mower/resources/recruit/riic_res/TANK.png b/arknights_mower/resources/recruit/riic_res/TANK.png new file mode 100644 index 000000000..d4873691f Binary files /dev/null and b/arknights_mower/resources/recruit/riic_res/TANK.png differ diff --git a/arknights_mower/resources/recruit/riic_res/WARRIOR.png b/arknights_mower/resources/recruit/riic_res/WARRIOR.png new file mode 100644 index 000000000..35ccda1b9 Binary files /dev/null and b/arknights_mower/resources/recruit/riic_res/WARRIOR.png differ diff --git a/arknights_mower/resources/recruit/start_recruit.png b/arknights_mower/resources/recruit/start_recruit.png new file mode 100644 index 000000000..d1baa1d74 Binary files /dev/null and b/arknights_mower/resources/recruit/start_recruit.png differ diff --git a/arknights_mower/resources/recruit/stone.png b/arknights_mower/resources/recruit/stone.png new file mode 100644 index 000000000..e04e20dcc Binary files /dev/null and b/arknights_mower/resources/recruit/stone.png differ diff --git a/arknights_mower/resources/recruit/ticket.png b/arknights_mower/resources/recruit/ticket.png new file mode 100644 index 000000000..eb49acaff Binary files /dev/null and b/arknights_mower/resources/recruit/ticket.png differ diff --git a/arknights_mower/resources/recruit/time.png b/arknights_mower/resources/recruit/time.png new file mode 100644 index 000000000..1fb776ef8 Binary files /dev/null and b/arknights_mower/resources/recruit/time.png differ diff --git a/arknights_mower/resources/recruit_2.png b/arknights_mower/resources/recruit_2.png deleted file mode 100644 index 1922cde05..000000000 Binary files a/arknights_mower/resources/recruit_2.png and /dev/null differ diff --git a/arknights_mower/resources/recruit_4.png b/arknights_mower/resources/recruit_4.png deleted file mode 100644 index 3a9294ec2..000000000 Binary files a/arknights_mower/resources/recruit_4.png and /dev/null differ diff --git a/arknights_mower/resources/recruit_4_chose.png b/arknights_mower/resources/recruit_4_chose.png deleted file mode 100644 index 37bde9cc6..000000000 Binary files a/arknights_mower/resources/recruit_4_chose.png and /dev/null differ diff --git a/arknights_mower/resources/recruit_budget.png b/arknights_mower/resources/recruit_budget.png deleted file mode 100644 index f60365113..000000000 Binary files a/arknights_mower/resources/recruit_budget.png and /dev/null differ diff --git a/arknights_mower/resources/recruit_continue.png b/arknights_mower/resources/recruit_continue.png deleted file mode 100644 index 5405c7bfb..000000000 Binary files a/arknights_mower/resources/recruit_continue.png and /dev/null differ diff --git a/arknights_mower/resources/recruit_finish.png b/arknights_mower/resources/recruit_finish.png deleted file mode 100644 index e4f6b197f..000000000 Binary files a/arknights_mower/resources/recruit_finish.png and /dev/null differ diff --git a/arknights_mower/resources/recruit_no.png b/arknights_mower/resources/recruit_no.png deleted file mode 100644 index 1fb277bdd..000000000 Binary files a/arknights_mower/resources/recruit_no.png and /dev/null differ diff --git a/arknights_mower/resources/recruit_no_lmb.png b/arknights_mower/resources/recruit_no_lmb.png deleted file mode 100644 index 84215496c..000000000 Binary files a/arknights_mower/resources/recruit_no_lmb.png and /dev/null differ diff --git a/arknights_mower/resources/recruit_no_refresh.png b/arknights_mower/resources/recruit_no_refresh.png deleted file mode 100644 index 9a270eb11..000000000 Binary files a/arknights_mower/resources/recruit_no_refresh.png and /dev/null differ diff --git a/arknights_mower/resources/recruit_no_ticket.png b/arknights_mower/resources/recruit_no_ticket.png deleted file mode 100644 index a4fedf97a..000000000 Binary files a/arknights_mower/resources/recruit_no_ticket.png and /dev/null differ diff --git a/arknights_mower/resources/recruit_refresh.png b/arknights_mower/resources/recruit_refresh.png deleted file mode 100644 index 9fb5e47a0..000000000 Binary files a/arknights_mower/resources/recruit_refresh.png and /dev/null differ diff --git a/arknights_mower/resources/recruit_special.png b/arknights_mower/resources/recruit_special.png deleted file mode 100644 index 28938bf7f..000000000 Binary files a/arknights_mower/resources/recruit_special.png and /dev/null differ diff --git a/arknights_mower/resources/recruit_tags.png b/arknights_mower/resources/recruit_tags.png deleted file mode 100644 index 8b2b71342..000000000 Binary files a/arknights_mower/resources/recruit_tags.png and /dev/null differ diff --git a/arknights_mower/resources/recruit_ticket.png b/arknights_mower/resources/recruit_ticket.png deleted file mode 100644 index 413df8971..000000000 Binary files a/arknights_mower/resources/recruit_ticket.png and /dev/null differ diff --git a/arknights_mower/resources/recruit_yesorno.png b/arknights_mower/resources/recruit_yesorno.png deleted file mode 100644 index 31321b24f..000000000 Binary files a/arknights_mower/resources/recruit_yesorno.png and /dev/null differ diff --git a/arknights_mower/solvers/base_schedule.py b/arknights_mower/solvers/base_schedule.py index 72d6b5d39..2edfc9cf2 100644 --- a/arknights_mower/solvers/base_schedule.py +++ b/arknights_mower/solvers/base_schedule.py @@ -3322,6 +3322,7 @@ def recruit_plan_solver(self): hours=config.conf.recruit_gap ): RecruitSolver(self.device, self.recog).run() + self.last_execution["recruit"] = datetime.now() logger.info(f"下一次公开招募执行时间在{config.conf.recruit_gap}小时之后") diff --git a/arknights_mower/solvers/recruit.py b/arknights_mower/solvers/recruit.py index a04288bc3..f466ee6e7 100644 --- a/arknights_mower/solvers/recruit.py +++ b/arknights_mower/solvers/recruit.py @@ -1,93 +1,83 @@ -import os +import lzma +import pickle +import traceback from itertools import combinations import cv2 -import numpy as np -from PIL import Image, ImageDraw, ImageFont from arknights_mower import __rootdir__ from arknights_mower.data import ( agent_with_tags, recruit_agent, - recruit_tag, - result_template_list, ) -from arknights_mower.utils import config, rapidocr, segment +from arknights_mower.utils import config from arknights_mower.utils.device.device import Device -from arknights_mower.utils.digit_reader import DigitReader from arknights_mower.utils.email import recruit_rarity, recruit_template, send_message from arknights_mower.utils.graph import SceneGraphSolver -from arknights_mower.utils.image import cropimg, loadres +from arknights_mower.utils.image import cropimg, thres2 from arknights_mower.utils.log import logger from arknights_mower.utils.recognize import Recognizer, Scene +from arknights_mower.utils.vector import va + +conf = config.conf + + +with lzma.open(f"{__rootdir__}/models/riic_base_digits.pkl", "rb") as f: + number = pickle.load(f) +with lzma.open(f"{__rootdir__}/models/recruit_result.pkl", "rb") as f: + recruit_res_template = pickle.load(f) +with lzma.open(f"{__rootdir__}/models/recruit.pkl", "rb") as f: + tag_template = pickle.load(f) +job_list = [ + "recruit/riic_res/CASTER", + "recruit/riic_res/MEDIC", + "recruit/riic_res/PIONEER", + "recruit/riic_res/SPECIAL", + "recruit/riic_res/SNIPER", + "recruit/riic_res/SUPPORT", + "recruit/riic_res/TANK", + "recruit/riic_res/WARRIOR", +] class RecruitSolver(SceneGraphSolver): def __init__(self, device: Device = None, recog: Recognizer = None) -> None: super().__init__(device, recog) + self.find_scope = { + "recruit/begin_recruit": [(340, 200), (590, 300)], + "recruit/job_requirements": [(100, 20), (300, 100)], + "recruit/recruit_done": [(300, 250), (600, 340)], + "recruit/recruit_lock": [(400, 120), (540, 220)], + } - self.result_agent = {} + # 四个招募栏位的位置 固定1920*1080所以直接写死了 + up = 270 + down = 1060 + left = 25 + right = 1890 + + self.segments = { + 1: [(left, up), (950, 650)], + 2: [(970, up), (right, 650)], + 3: [(left, 690), (950, 650)], + 4: [(970, 690), (right, down)], + } self.agent_choose = {} - - self.recruit_pos = -1 - - self.recruiting = 0 - self.has_ticket = True # 默认含有招募票 - self.can_refresh = True # 默认可以刷新 - self.permit_count = None - self.can_refresh = None - self.enough_lmb = True - self.digitReader = DigitReader() + self.recruit_index = 1 + # 默认要支援机械 + self.recruit_order_index = 2 self.recruit_order = [6, 5, 1, 4, 3, 2] - self.recruit_index = 2 - - def run(self): - self.recruiting = 0 - self.has_ticket = True # 默认含有招募票 - self.permit_count = None - - # 调整公招参数 - self.add_recruit_param() - - logger.info("Start: 公招") - # 清空 - self.result_agent.clear() self.result_agent = {} - self.agent_choose = {} - self.tag_template = {} - self.font = ImageFont.truetype( - "{}/fonts/SourceHanSansCN-Medium.otf".format(__rootdir__), 30 - ) - for tag in recruit_tag: - im = Image.new(mode="RGBA", color=(49, 49, 49), size=(215, 70)) - # im=Image.open("D:\\Git_Repositories\\Pycharm_Project\\Mower\\screenshot_tags\\{}.png".format(tag)) - W, H = im.size - draw = ImageDraw.Draw(im) - _, _, w, h = draw.textbbox((0, 0), tag, font=self.font) - # text_color=(255,255,255) - # if tag =="高级资深干员" or tag =="资深干员": - # text_color=(255,235,4) - - draw.text(((W - w) / 2, (H - h) / 2 - 5), tag, font=self.font) - - self.tag_template[tag] = cv2.cvtColor( - np.array(im.crop(im.getbbox())), cv2.COLOR_RGB2BGR - ) - try: - if len(self.tag_template) < len(recruit_tag): - raise "tag生成失败{}".format(self.tag_template) - super().run() - except Exception as e: - logger.error(e) - - logger.debug(self.agent_choose) - logger.debug(self.result_agent) + self.ticket_number = None - if self.result_agent: - logger.info(f"上次公招结果汇总{self.result_agent}") + def run(self): + self.add_recruit_param() + super().run() + logger.info(self.result_agent) if self.agent_choose: + logger.info("开包汇总如下") for pos in self.agent_choose: agent = [] for item in self.agent_choose[pos]["result"]: @@ -98,106 +88,90 @@ def run(self): + "]:{}".format(",".join(agent)) ) if self.agent_choose or self.result_agent: - if config.conf.recruit_email_enable: + logger.info("招募汇总如下") + if conf.recruit_email_enable: send_message( recruit_template.render( recruit_results=self.agent_choose, recruit_get_agent=self.result_agent, - permit_count=self.permit_count, + permit_count=conf.recruitment_permit, title_text="公招汇总", ), "公招汇总通知", ) - return self.agent_choose, self.result_agent - def add_recruit_param(self): - if not config.conf.recruit_robot: - self.recruit_order = [6, 5, 4, 3, 2, 1] - self.recruit_index = 1 - def transition(self) -> bool: if (scene := self.scene()) == Scene.RECRUIT_MAIN: - segments = segment.recruit(self.recog.img) - - if self.can_refresh is None: - refresh_img = self.recog.img[100:150, 1390:1440] - - refresh_gray = cv2.cvtColor(refresh_img, cv2.COLOR_BGR2GRAY) - refresh_binary = cv2.threshold( - refresh_gray, 220, 255, cv2.THRESH_BINARY - )[1] - refresh_res = rapidocr.engine( - refresh_binary, use_det=False, use_cls=False, use_rec=True - )[0][0][0] - if refresh_res == "0" or refresh_res == "o" or refresh_res == "O": - refresh_res = 0 - self.can_refresh = False - else: - self.can_refresh = True - - logger.info(f"刷新次数:{refresh_res}") - - try: - # 招募前读取数量 - template_ticket = loadres("recruit_ticket") - img = self.recog.img - res = cv2.matchTemplate(img, template_ticket, cv2.TM_CCOEFF_NORMED) - min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) - h, w = template_ticket.shape[:-1] - p0 = max_loc - p1 = (p0[0] + w, p0[1] + h) - - template_stone = loadres("stone") - res = cv2.matchTemplate(img, template_stone, cv2.TM_CCOEFF_NORMED) - min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) - p2 = max_loc - - res = self.digitReader.get_recruit_ticket( - img[p2[1] : p1[1], p1[0] : p2[0]] - ) - if str(res).isdigit(): - self.permit_count = int(res) - logger.info(f"招募券数量:{res}") - except Exception: - # 设置为1 先保证后续流程能正常进行 - self.permit_count = 1 - logger.error("招募券数量读取失败") - - if self.can_refresh is False and self.permit_count <= 0: - logger.info("无招募券和刷新次数,结束公招") + if self.recruit_index > 4: + logger.info("结束公招") return True + job_requirements_scope = [ + va( + self.segments[self.recruit_index][0], + self.find_scope["recruit/job_requirements"][0], + ), + va( + self.segments[self.recruit_index][0], + self.find_scope["recruit/job_requirements"][1], + ), + ] + begin_recruit_scope = [ + va( + self.segments[self.recruit_index][0], + self.find_scope["recruit/begin_recruit"][0], + ), + va( + self.segments[self.recruit_index][0], + self.find_scope["recruit/begin_recruit"][1], + ), + ] + recruit_done_scope = [ + va( + self.segments[self.recruit_index][0], + self.find_scope["recruit/recruit_done"][0], + ), + va( + self.segments[self.recruit_index][0], + self.find_scope["recruit/recruit_done"][1], + ), + ] + recruit_lock_scope = [ + va( + self.segments[self.recruit_index][0], + self.find_scope["recruit/recruit_lock"][0], + ), + va( + self.segments[self.recruit_index][0], + self.find_scope["recruit/recruit_lock"][1], + ), + ] - if self.permit_count <= 0: - self.has_ticket = False - - tapped = False - for idx, seg in enumerate(segments): - # 在主界面重置为-1 - self.recruit_pos = -1 - if self.recruiting & (1 << idx) != 0: - continue - if self.tap_element("recruit_finish", scope=seg, detected=True): - # 完成公招点击聘用候选人 - self.recruit_pos = idx - tapped = True - break - if not (self.has_ticket or self.enough_lmb) and not self.can_refresh: - continue - # 存在职业需求,说明正在进行招募 - required = self.find("job_requirements", scope=seg) - if required is None: - # 不在进行招募的位置 (1、空位 2、人力办公室等级不够没升的位置) - # 下一次循环进入对应位置,先存入值 - self.recruit_pos = idx - self.tap(seg) - tapped = True - self.recruiting |= 1 << idx - break - if not tapped: + if self.find("recruit/job_requirements", scope=job_requirements_scope): + self.recruit_index = self.recruit_index + 1 + logger.debug(f"{self.recruit_index}正在招募") + return + elif pos := self.find("recruit/recruit_lock", scope=recruit_lock_scope): + logger.debug(f"{self.recruit_index}锁定") return True + elif pos := self.find("recruit/recruit_done", scope=recruit_done_scope): + logger.debug(f"{self.recruit_index}结束招募 开包") + self.tap(pos) + return + elif pos := self.find("recruit/begin_recruit", scope=begin_recruit_scope): + self.ticket_number = self.get_ticket_number() + if self.ticket_number == 0: + self.recruit_index = self.recruit_index + 1 + logger.debug(f"{self.recruit_index} 张招募券") + return + self.tap(pos) + return + elif scene == Scene.RECRUIT_TAGS: + self.ticket_number = self.get_ticket_number() return self.recruit_tags() + elif scene == Scene.REFRESH_TAGS: + self.tap_element("recruit/refresh_comfirm") elif scene == Scene.RECRUIT_AGENT: return self.recruit_result() elif scene == Scene.SKIP: @@ -207,133 +181,118 @@ def transition(self) -> bool: else: self.scene_graph_navigation(Scene.RECRUIT_MAIN) - def recruit_tags(self): - """识别公招标签的逻辑""" - if self.find("recruit_no_ticket") is not None: - self.has_ticket = False - if self.find("recruit_no_refresh") is not None: - self.can_refresh = False - if self.find("recruit_no_lmb") is not None: - self.enough_lmb = False - - needs = self.find("career_needs") - avail_level = self.find("available_level") - budget = self.find("recruit_budget") - up = needs[0][1] - 80 - down = needs[1][1] + 60 - left = needs[1][0] + 50 - right = avail_level[0][0] - - while True: - # ocr the recruitment tags and rectify - img = self.recog.img[up:down, left:right] - tags_img = self.split_tags(img) - tags = {} - h, w, _ = img.shape - for index, value in enumerate(tags_img): - res = self.get_recruit_tag(value) - tag_pos = ( - int(left + (index % 3) * int(w / 3) + 30), - int(up + int(index / 3) * int(h / 2) + 30), - ) - tags[res["tag"]] = tag_pos - - logger.info("tag识别结果{} {}".format(res, tag_pos)) + def recruit_result(self): + try: + # 存在读完一次没退完再读一次 + if str(self.recruit_index) in self.result_agent.keys(): + self.tap((950, 150)) + return + + job_pt = None + for i in job_list: + if job_pt := self.find(i): + break - if len(tags) != 5: - raise "标签识别失败 tag={}".format(tags) + img = cropimg(self.recog.gray, ((job_pt[1][0], 730), (1800, 860))) + img = cv2.threshold(img, 220, 255, cv2.THRESH_BINARY)[1] - logger.info(f"第{self.recruit_pos + 1}个位置上的公招标签:{tags}") + score = {} + for id in recruit_res_template: + res = recruit_res_template[id] + result = cv2.matchTemplate(img, res, cv2.TM_CCORR_NORMED, res) + _, max_val, _, _ = cv2.minMaxLoc(result) + score[id] = max_val + self.result_agent[self.recruit_index] = recruit_agent[ + max(score, key=score.get) + ]["name"] - # 计算招募标签组合结果 - recruit_cal_result = self.recruit_cal(list(tags.keys())) - logger.debug("筛选结果:{}".format(recruit_cal_result)) - recruit_result_level = -1 + except Exception as e: + logger.error(f"公招开包异常:{e}") + logger.debug(traceback.format_exc()) + finally: + self.tap((500, 500)) - for index in self.recruit_order: - if recruit_cal_result[index]: - recruit_result_level = index - break - if recruit_result_level == -1: - logger.error("筛选结果为 {}".format(recruit_cal_result)) - raise "筛选tag失败" - logger.info("recruit_result_level={}".format(recruit_result_level)) - - conf = config.conf - - if self.recruit_order.index(recruit_result_level) <= self.recruit_index: - if conf.recruit_email_enable: - logger.info("稀有tag,发送邮件") - send_message( - recruit_rarity.render( - recruit_results=recruit_cal_result[recruit_result_level], - title_text="稀有tag通知", - ), - "出稀有标签辣", - ) - - if recruit_result_level == 6: - logger.debug("六星tag") - self.back() - return - if recruit_result_level == 1 and conf.recruit_robot: - logger.debug("支援机械 发送邮件") - self.back() - return + def recruit_tags(self): + tags = self.get_recruit_tag() + logger.debug("tag识别结果{}".format(tags)) + + tem_res = self.recruit_cal(sorted(tags)) + recruit_cal_result = None + recruit_result_level = -1 + + for index in self.recruit_order: + if tem_res[index]: + recruit_result_level = index + break + if recruit_result_level == -1: + logger.error("筛选结果为 {}".format(tem_res)) + raise ValueError("筛选tag失败") + elif recruit_result_level != 3 and self.all_same_res( + tem_res, recruit_result_level + ): + recruit_cal_result = [tem_res[recruit_result_level][-1]] + else: + recruit_cal_result = tem_res[recruit_result_level] + logger.debug(recruit_cal_result) + if recruit_result_level == 3: + if pos := self.find("recruit/refresh"): + self.tap(pos) + return + + if self.recruit_order.index(recruit_result_level) <= self.recruit_order_index: + if conf.recruit_email_enable: + send_message( + recruit_rarity.render( + recruit_results=recruit_cal_result[recruit_result_level], + title_text="稀有tag通知", + ), + "出稀有标签辣", + ) + logger.info("稀有tag,发送邮件") + if recruit_result_level == 6 or recruit_result_level == 1: + logger.debug(f"{recruit_result_level}星稀有tag ,不选") + self.recruit_index = self.recruit_index + 1 + self.back() + return + elif recruit_result_level == 5: if conf.recruit_auto_5 == 2: - if conf.recruit_auto_only5: - if len(recruit_cal_result[recruit_result_level]) > 1: - logger.debug("手动选择且单五星词条自动,但词条不止一种") - self.back() - return - else: - logger.debug("手动选择且单五星词条不自动") + if conf.recruit_auto_only5 and len(recruit_cal_result) > 1: + logger.debug( + f"{recruit_result_level}星稀有tag,但不止一个或纯手动选择" + ) + self.recruit_index = self.recruit_index + 1 self.back() return - if recruit_result_level == 3: - # refresh - recruit_refresh_pos = (1455, 610) - if self.get_color(recruit_refresh_pos)[2] > 200: - self.tap(recruit_refresh_pos) - self.tap_element("double_confirm/main", x_rate=1, interval=3) - logger.info("刷新标签") - continue - break - - if not self.enough_lmb: - logger.info("龙门币不足 结束公招") - self.back() - return - # 如果没有招募券则只刷新标签不选人 - if not self.has_ticket: - logger.info("无招募券") + if self.ticket_number == 0: + self.recruit_index = self.recruit_index + 1 self.back() return - # best为空说明这次大概率三星 - # 券数量少于预期值,仅招募四星或者停止招募,只刷新标签 - if self.permit_count <= conf.recruitment_permit and recruit_result_level == 3: - logger.info("不招三星") + if self.ticket_number < conf.recruitment_permit and recruit_result_level == 3: + self.recruit_index = self.recruit_index + 1 + logger.info("没券 返回") self.back() return choose = [] if recruit_result_level > 3: - choose = recruit_cal_result[recruit_result_level][0]["tag"] + choose = recruit_cal_result[0]["tag"] # tap selected tags logger.info(f"选择标签:{list(choose)} ") for x in choose: # 存在choose为空但是进行标签选择的情况 logger.debug(f"tap{x}:{tags[x]}") - self.device.tap(tags[x]) + self.tap(tags[x]) + # 9h为True 3h50min为False logger.debug("开始选择时长") + # 默认三星招募时长是9:00 recruit_time_choose = 540 - if recruit_result_level >= 3: - if recruit_result_level == 1: - recruit_time_choose = 230 + # 默认一星招募时长是3:50 + if recruit_result_level == 1: + recruit_time_choose = 230 if recruit_time_choose == 540: # 09:00 @@ -342,78 +301,54 @@ def recruit_tags(self): elif recruit_time_choose == 230: # 03:50 logger.debug("时间3h50min") - pos = self.find("one_hour") - [self.tap(pos, 0.2, 0.2, 0.1) for _ in range(2)] - [self.tap(pos, 0.5, 0.2, 0.1) for _ in range(5)] + [self.tap_element("one_hour", 0.2, 0.2, 0) for _ in range(2)] + [self.tap_element("one_hour", 0.5, 0.2, 0) for _ in range(5)] + # elif recruit_time_choose == 460: + # # 07:40 + # logger.debug("时间7h40min") + # [self.tap_element("one_hour", 0.2, 0.8, 0) for _ in range(2)] + # [self.tap_element("one_hour", 0.5, 0.8, 0) for _ in range(2)] # start recruit - self.tap((avail_level[1][0], budget[0][1]), interval=3) - - # 有券才能点下去 - if self.permit_count > 1: - self.permit_count -= 1 + self.tap_element("recruit/start_recruit") + self.ticket_number = self.ticket_number - 1 if recruit_result_level > 3: - self.agent_choose[str(self.recruit_pos + 1)] = { - "tags": choose, - "result": recruit_cal_result[recruit_result_level][0]["result"], + self.agent_choose[str(self.recruit_index)] = { + "tags": list(choose), + "result": list(recruit_cal_result[0]["result"]), } + tmp_res_list = [] + for i in list(recruit_cal_result[0]["result"]): + tmp_res_list.append(i["name"]) logger.info( "第{}个位置上的公招预测结果:{}".format( - self.recruit_pos + 1, - recruit_cal_result[recruit_result_level][0]["result"], + self.recruit_index, + tmp_res_list, ) ) else: - self.agent_choose[str(self.recruit_pos + 1)] = { - "tags": choose, + self.agent_choose[str(self.recruit_index)] = { + "tags": list(choose), "result": [{"id": "", "name": "随机三星干员", "star": 3}], } logger.info( - f'第{self.recruit_pos + 1}个位置上的公招预测结果:{"随机三星干员"}' + f'第{self.recruit_index}个位置上的公招预测结果:{"随机三星干员"}' ) + self.recruit_index = self.recruit_index + 1 + return - def recruit_result(self): - try: - agent = None - gray_img = cropimg(self.recog.gray, ((800, 600), (1500, 1000))) - - img_binary = cv2.threshold(gray_img, 220, 255, cv2.THRESH_BINARY)[1] - max = 0 - get_path = "" - - for template_name in result_template_list: - tem_path = f"{__rootdir__}/resources/agent_name/{template_name}.png" - template_ = cv2.imdecode( - np.fromfile(tem_path.__str__(), dtype=np.uint8), - cv2.IMREAD_GRAYSCALE, - ) - res = cv2.matchTemplate(img_binary, template_, cv2.TM_CCORR_NORMED) - min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) - if max < max_val: - get_path = tem_path - max = max_val - if max > 0.7: - break - - if max > 0.7: - agent_id = os.path.basename(get_path) - agent_id = agent_id.replace(".png", "") - agent = recruit_agent[agent_id]["name"] - - if agent is not None: - # 汇总开包结果 - self.result_agent[str(self.recruit_pos + 1)] = agent - except Exception as e: - logger.error(f"公招开包异常{e}") - send_message(f"公招开包异常{e}") - - self.tap((self.recog.w // 2, self.recog.h // 2)) + def all_same_res(self, recruit_cal_res, index): + tmp_list = recruit_cal_res[index] + last_res = tmp_list[-1] + for i in range(len(tmp_list) - 2, -1, -1): + if tmp_list[i]["result"] != last_res["result"]: + return False + return True def recruit_cal(self, tags: list[str]): logger.debug(f"选择标签{tags}") index_dict = {k: i for i, k in enumerate(self.recruit_order)} - combined_agent = {} if "新手" in tags: tags.remove("新手") @@ -496,24 +431,40 @@ def recruit_cal(self, tags: list[str]): ) for item in result: if result[item]: - logger.info("{}:{}".format(item, result[item])) + logger.debug("{}:{}".format(item, result[item])) return result - def get_recruit_tag(self, img): - max_v = -1 - tag_res = None - for key in self.tag_template: - res = cv2.matchTemplate( - img, - self.tag_template[key], - cv2.TM_CCORR_NORMED, - ) + def get_recruit_tag(self): + up = 520 + down = 740 + left = 530 + right = 1300 + + img = self.recog.img[up:down, left:right] + tags_img = self.split_tags(img) + tags = {} + h, w, _ = img.shape - min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) - if max_val > max_v: - tag_res = {"tag": key, "val": max_val} - max_v = max_val - return tag_res + for index, value in enumerate(tags_img): + max_v = -1 + tag_res = None + for key in tag_template: + res = cv2.matchTemplate( + value, + tag_template[key], + cv2.TM_CCORR_NORMED, + ) + + _, max_val, _, _ = cv2.minMaxLoc(res) + if max_val > max_v: + tag_res = {"tag": key, "val": max_val} + max_v = max_val + tag_pos = ( + int(left + (index % 3) * int(w / 3) + 30), + int(up + int(index / 3) * int(h / 2) + 30), + ) + tags[tag_res["tag"]] = tag_pos + return tags def split_tags(self, img): tag_img = [] @@ -529,3 +480,41 @@ def split_tags(self, img): img = ori_img[tag_h:h, 0:w] return tag_img + + def get_ticket_number(self, height: int | None = 0, thres: int | None = 180): + p1, p2 = self.find("recruit/ticket") + p3, _ = self.find("recruit/stone") + p1 = (p2[0], p1[1] + 10) + p3 = (p3[0] - 30, p2[1] - 5) + img = cropimg(self.recog.gray, (p1, p3)) + default_height = 29 + if height and height != default_height: + scale = default_height / height + img = cv2.resize(img, None, None, scale, scale) + img = thres2(img, thres) + contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) + rect = [cv2.boundingRect(c) for c in contours] + rect.sort(key=lambda c: c[0]) + value = 0 + for x, y, w, h in rect: + digit = cropimg(img, ((x, y), (x + w, y + h))) + digit = cv2.copyMakeBorder( + digit, 10, 10, 10, 10, cv2.BORDER_CONSTANT, None, (0,) + ) + if digit.size < 800: + continue + score = [] + for i in range(10): + im = number[i] + if digit.shape[0] < im.shape[0] or digit.shape[1] < im.shape[1]: + continue + result = cv2.matchTemplate(digit, im, cv2.TM_SQDIFF_NORMED) + min_val, _, _, _ = cv2.minMaxLoc(result) + score.append(min_val) + value = value * 10 + score.index(min(score)) + return value + + def add_recruit_param(self): + if not conf.recruit_robot: + self.recruit_order = [6, 5, 4, 3, 2, 1] + self.recruit_order_index = 1 diff --git a/arknights_mower/tests/recruit_tests.py b/arknights_mower/tests/recruit_tests.py index ede4a5daa..26c2d2881 100644 --- a/arknights_mower/tests/recruit_tests.py +++ b/arknights_mower/tests/recruit_tests.py @@ -1,530 +1,32 @@ -# -!- coding: utf-8 -!- - - import os -import pathlib -from itertools import combinations +import sys +from unittest.mock import patch -import cv2 -import numpy as np -from jinja2 import Environment, FileSystemLoader, select_autoescape - -from arknights_mower.__init__ import __rootdir__ -from arknights_mower.data import ( - agent_with_tags, - recruit_agent, - result_template_list, +sys.path.append( + os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) ) -from arknights_mower.utils import rapidocr, segment -from arknights_mower.utils.digit_reader import DigitReader -from arknights_mower.utils.image import cropimg, loadimg -from arknights_mower.utils.log import logger -from arknights_mower.utils.recognize import RecognizeError, Scene - -env = Environment( - loader=FileSystemLoader( - "D:\\Git_Repositories\\Pycharm_Project\\Mower\\arknights-mower\\arknights_mower\\templates\\email" - ), - autoescape=select_autoescape(), -) - -recruit_template = env.get_template("recruit_template.html") -recruit_rarity = env.get_template("recruit_rarity.html") - - -class RecruitSolver: - def __init__(self) -> None: - self.result_agent = {} - self.agent_choose = {} - self.recruit_config = {} - - self.recruit_pos = -1 - self.tag_template = {} - self.priority = None - self.recruiting = 0 - self.has_ticket = True # 默认含有招募票 - self.can_refresh = True # 默认可以刷新 - self.permit_count = None - self.can_refresh = None - self.enough_lmb = True - self.digitReader = DigitReader() - self.recruit_order = [6, 5, 1, 4, 3, 2] - self.recruit_index = 2 - - def run(self, priority: list[str] = None, recruit_config={}): - """ - :param priority: list[str], 优先考虑的公招干员,默认为高稀有度优先 - """ - self.priority = priority - self.recruiting = 0 - self.has_ticket = True # 默认含有招募票 - self.permit_count = None - - # 调整公招参数 - self.add_recruit_param(recruit_config) - - logger.info("Start: 公招") - # 清空 - self.result_agent.clear() - - self.result_agent = {} - self.agent_choose = {} - - # logger.info(f'目标干员:{priority if priority else "无,高稀有度优先"}')\ - try: - pass - except Exception as e: - logger.error(e) - - logger.debug(self.agent_choose) - logger.debug(self.result_agent) - - if self.result_agent: - logger.info(f"上次公招结果汇总{self.result_agent}") - - if self.agent_choose: - for pos in self.agent_choose: - agent = [] - for item in self.agent_choose[pos]["result"]: - agent.append(item["name"]) - logger.info( - "{}:[".format(pos) - + ",".join(self.agent_choose[pos]["tags"]) - + "]:{}".format(",".join(agent)) - ) - if self.agent_choose or self.result_agent: - if self.recruit_config["recruit_email_enable"]: - logger.info("发送公招结果邮件") - - return self.agent_choose, self.result_agent - - def add_recruit_param(self, recruit_config): - if not recruit_config: - raise Exception("招募设置为空") - - if recruit_config["recruitment_time"]: - recruitment_time = 460 - else: - recruitment_time = 540 - - self.recruit_config = { - "recruitment_time": {"3": recruitment_time, "4": 540, "5": 540, "6": 540}, - "recruit_robot": recruit_config["recruit_robot"], - "permit_target": recruit_config["permit_target"], - "recruit_auto_5": recruit_config["recruit_auto_5"], - "recruit_auto_only5": recruit_config["recruit_auto_only5"], - "recruit_email_enable": recruit_config["recruit_email_enable"], - } - - if not self.recruit_config["recruit_robot"]: - self.recruit_order = [6, 5, 4, 3, 2, 1] - self.recruit_index = 1 - - def transition(self) -> bool: - if (scene := self.scene()) == Scene.INDEX: - self.tap_themed_element("index_recruit") - elif scene == Scene.RECRUIT_MAIN: - segments = segment.recruit(self.recog.img) - - if self.can_refresh is None: - refresh_img = self.recog.img[100:150, 1390:1440] - - refresh_gray = cv2.cvtColor(refresh_img, cv2.COLOR_BGR2GRAY) - refresh_binary = cv2.threshold( - refresh_gray, 220, 255, cv2.THRESH_BINARY - )[1] - refresh_res = rapidocr.engine( - refresh_binary, use_det=False, use_cls=False, use_rec=True - )[0][0][0] - if refresh_res == "0" or refresh_res == "o" or refresh_res == "O": - refresh_res = 0 - self.can_refresh = False - else: - self.can_refresh = True - - logger.info(f"刷新次数:{refresh_res}") - try: - if self.permit_count is None: - template_ticket = loadimg( - f"{__rootdir__}/resources/recruit_ticket.png" - ) - img = self.recog.img - res = cv2.matchTemplate(img, template_ticket, cv2.TM_CCOEFF_NORMED) - min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) - h, w = template_ticket.shape[:-1] - p0 = max_loc - p1 = (p0[0] + w, p0[1] + h) +import unittest - template_stone = loadimg(f"{__rootdir__}/resources/stone.png") - res = cv2.matchTemplate(img, template_stone, cv2.TM_CCOEFF_NORMED) - min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) - p2 = max_loc +from arknights_mower.solvers.recruit import RecruitSolver - res = self.digitReader.get_recruit_ticket( - img[p2[1] : p1[1], p1[0] : p2[0]] - ) - if str(res).isdigit(): - self.permit_count = int(res) - logger.info(f"招募券数量:{res}") - except Exception: - # 设置为1 先保证后续流程能正常进行 - self.permit_count = 1 - logger.error("招募券数量读取失败") - if self.can_refresh is False and self.permit_count <= 0: - logger.info("无招募券和刷新次数,结束公招") - return True +class TestRecruitCal(unittest.TestCase): + @patch.object(RecruitSolver, "__init__", lambda x: None) + def setUp(self): + self.test_class = RecruitSolver() + self.test_class.recruit_order = [6, 5, 1, 4, 3, 2] - if self.permit_count <= 0: - self.has_ticket = False - - tapped = False - for idx, seg in enumerate(segments): - # 在主界面重置为-1 - self.recruit_pos = -1 - if self.recruiting & (1 << idx) != 0: - continue - if self.tap_element("recruit_finish", scope=seg, detected=True): - # 完成公招点击聘用候选人 - self.recruit_pos = idx - tapped = True - break - if not (self.has_ticket or self.enough_lmb) and not self.can_refresh: - continue - # 存在职业需求,说明正在进行招募 - required = self.find("job_requirements", scope=seg) - if required is None: - # 不在进行招募的位置 (1、空位 2、人力办公室等级不够没升的位置) - # 下一次循环进入对应位置,先存入值 - self.recruit_pos = idx - self.tap(seg) - tapped = True - self.recruiting |= 1 << idx - break - if not tapped: - return True - elif scene == Scene.RECRUIT_TAGS: - return self.recruit_tags() - elif scene == Scene.SKIP: - self.tap_element("skip") - elif scene == Scene.RECRUIT_AGENT: - return self.recruit_result() - elif scene == Scene.MATERIEL: - self.tap_element("materiel_ico") - elif scene == Scene.LOADING: - self.sleep(3) - elif scene == Scene.CONNECTING: - self.sleep(3) - elif self.get_navigation(): - self.tap_element("nav_recruit") - elif scene != Scene.UNKNOWN: - self.back_to_index() - else: - raise RecognizeError("Unknown scene") - - def recruit_tags(self, tags: list[str] = None): - recruit_cal_result = self.recruit_cal(tags) - recruit_result_level = -1 - - for index in self.recruit_order: - if recruit_cal_result[index]: - recruit_result_level = index - break - if recruit_result_level == -1: - logger.error("筛选结果为 {}".format(recruit_cal_result)) - raise "筛选tag失败" - if self.recruit_order.index(recruit_result_level) <= self.recruit_index: - if self.recruit_config["recruit_email_enable"]: - with open("recruit_rarity.html", "w", encoding="utf-8") as file: - file.write( - recruit_rarity.render( - recruit_results=recruit_cal_result[recruit_result_level], - title_text="基建报告", - ) - ) - logger.info("稀有tag,发送邮件") - - logger.info("稀有tag,发送邮件") - if recruit_result_level == 6: - logger.info("六星tag") - return - if recruit_result_level == 1 and self.recruit_config["recruit_robot"]: - logger.info("小车") - return - # 手动选择且单五星词条不自动 - if ( - self.recruit_config["recruit_auto_5"] == 2 - and not self.recruit_config["recruit_auto_only5"] - ): - logger.info("手动选择且单五星词条不自动") - return - # 手动选择且单五星词条自动,但词条不止一种 - if ( - self.recruit_config["recruit_auto_5"] == 2 - and len(recruit_cal_result[recruit_result_level]) > 1 - and self.recruit_config["recruit_auto_only5"] - ): - logger.info("手动选择且单五星词条自动,但词条不止一种") - return - if recruit_result_level == 3: - # refresh - if self.tap_element("recruit_refresh", detected=True): - self.tap_element("double_confirm", 0.8, interval=3, judge=False) - logger.info("刷新标签") - return - logger.info("选干员") - choose = [] - if recruit_cal_result[recruit_result_level]: - choose = recruit_cal_result[recruit_result_level][0]["tag"] - - # tap selected tags - logger.info(f"选择标签:{list(choose)}") - - logger.debug("开始选择时长") - recruit_time_choose = self.recruit_config["recruitment_time"]["3"] - if recruit_result_level >= 3: - if recruit_result_level == 1: - recruit_time_choose = 230 - else: - recruit_time_choose = self.recruit_config["recruitment_time"][ - str(recruit_result_level) - ] - - logger.info(recruit_time_choose) - - if recruit_result_level > 3: - self.agent_choose[str(self.recruit_pos + 1)] = { - "tags": choose, - "result": recruit_cal_result[recruit_result_level][0]["result"], - } - logger.info( - "第{}个位置上的公招预测结果:{}".format( - self.recruit_pos + 1, - recruit_cal_result[recruit_result_level][0]["result"], - ) - ) - else: - self.agent_choose[str(self.recruit_pos + 1)] = { - "tags": choose, - "result": [{"id": "", "name": "随机三星干员", "star": 3}], - } - logger.info( - f'第{self.recruit_pos + 1}个位置上的公招预测结果:{"随机三星干员"}' - ) - - def recruit_result(self): - try: - agent = None - gray_img = cropimg(self.recog.gray, ((800, 600), (1500, 1000))) - - img_binary = cv2.threshold(gray_img, 220, 255, cv2.THRESH_BINARY)[1] - max = 0 - get_path = "" - - for template_name in result_template_list: - tem_path = f"{__rootdir__}/resources/agent_name/{template_name}.png" - template_ = cv2.imdecode( - np.fromfile(tem_path.__str__(), dtype=np.uint8), - cv2.IMREAD_GRAYSCALE, - ) - res = cv2.matchTemplate(img_binary, template_, cv2.TM_CCORR_NORMED) - min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) - if max < max_val: - get_path = tem_path - max = max_val - if max > 0.7: - break - - if max > 0.7: - agent_id = os.path.basename(get_path) - agent_id = agent_id.replace(".png", "") - agent = recruit_agent[agent_id]["name"] - - if agent is not None: - # 汇总开包结果 - self.result_agent[str(self.recruit_pos + 1)] = agent - except Exception as e: - logger.error(f"公招开包异常{e}") - self.send_message(f"公招开包异常{e}") - except cv2.Error as e: - logger.error(f"公招开包异常{e}") - self.send_message(f"公招开包异常{e}") - except Exception: - pass - - self.tap((self.recog.w // 2, self.recog.h // 2)) - - def recruit_cal(self, tags: list[str]): - logger.debug(f"选择标签{tags}") - index_dict = {k: i for i, k in enumerate(self.recruit_order)} - combined_agent = {} - if "新手" in tags: - tags.remove("新手") - for item in combinations(tags, 1): - tmp = agent_with_tags[item[0]] - if len(tmp) == 0: - continue - tmp.sort(key=lambda k: k["star"], reverse=True) - combined_agent[item] = tmp - for item in combinations(tags, 2): - tmp = [j for j in agent_with_tags[item[0]] if j in agent_with_tags[item[1]]] - if len(tmp) == 0: - continue - tmp.sort(key=lambda k: k["star"]) - combined_agent[item] = tmp - for item in combinations(tags, 3): - tmp1 = [ - j for j in agent_with_tags[item[0]] if j in agent_with_tags[item[1]] - ] - tmp = [j for j in tmp1 if j in agent_with_tags[item[2]]] - if len(tmp) == 0: - continue - tmp.sort(key=lambda k: k["star"], reverse=True) - combined_agent[item] = tmp - - sorted_list = sorted( - combined_agent.items(), key=lambda x: index_dict[x[1][0]["star"]] - ) - - result_dict = {} - for item in sorted_list: - result_dict[item[0]] = [] - max_star = -1 - min_star = 7 - for agent in item[1]: - if "高级资深干员" not in item[0] and agent["star"] == 6: - continue - if agent["star"] > max_star: - max_star = agent["star"] - if agent["star"] < min_star: - min_star = agent["star"] - for agent in item[1]: - if max_star > 1 and agent["star"] == 2: - continue - if max_star > 1 and agent["star"] == 1: - continue - if max_star < 6 and agent["star"] == 6: - continue - result_dict[item[0]].append(agent) - logger.debug(item[0], agent) - - try: - for key in list(result_dict.keys()): - if len(result_dict[key]) == 0: - result_dict.pop(key) - result_dict[item[0]] = sorted( - result_dict[item[0]], key=lambda x: x["star"], reverse=True - ) - min_star = result_dict[item[0]][-1]["star"] - for res in result_dict[item[0]][:]: - if res["star"] > min_star: - result_dict[item[0]].remove(res) - except KeyError: - logger.debug("Recruit Cal Key Error :{}".format(result_dict)) - continue - - result = { - 6: [], - 5: [], - 4: [], - 3: [], - 2: [], - 1: [], - } - for tag in result_dict: - result[result_dict[tag][0]["star"]].append( - {"tag": tag, "result": result_dict[tag]} - ) - for item in result: - if result[item]: - logger.info("{}:{}".format(item, result[item])) - return result - - def get_recruit_tag(self, img): - for i in pathlib.Path( - "D:\\Git_Repositories\\Pycharm_Project\\Mower\\arknights-mower\\arknights_mower\\resources\\recruit_tags" - ).glob("*.png"): - tag = ( - i.__str__() - .replace( - "D:\\Git_Repositories\\Pycharm_Project\\Mower\\arknights-mower\\arknights_mower\\resources\\recruit_tags\\", - "", - ) - .replace(".png", "") - ) - - self.tag_template[tag] = loadimg(i.__str__()) - max_v = -1 - tag_res = None - for key in self.tag_template: - res = cv2.matchTemplate( - img, - self.tag_template[key], - cv2.TM_CCORR_NORMED, - ) - - min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) - if max_val > max_v: - tag_res = {"tag": key, "val": max_val} - max_v = max_val - return tag_res - - def split_tags(self, img): - tag_img = [] - h, w, _ = img.shape - ori_img = img - tag_h, tag_w = int(h / 2), int(w / 3) - for i in range(0, 2): - for j in range(0, 3): - if i * j == 2: - continue - tag_img.append(img[0:tag_h, 0:tag_w]) - img = img[0:h, tag_w:w] - img = ori_img[tag_h:h, 0:w] - - return tag_img + def test_recruit_cal_with_order_1(self): + recruit_tags = ["重装干员", "先锋干员", "高级资深干员", "支援", "支援机械"] + results = self.test_class.recruit_cal(recruit_tags) + print(f"顺序为 {self.test_class.recruit_order}") + print(results.keys()) + for i in results: + for result in results[i]: + for agent in result["result"]: + print(f"{i} {result['tag']} {agent['name']}") if __name__ == "__main__": - recruit_ = RecruitSolver() - needs = [349, 592], [486, 677] - avail_level = [1294, 234], [1495, 272] - up = needs[0][1] - 80 - down = needs[1][1] + 60 - left = needs[1][0] + 50 - right = avail_level[0][0] - for i in pathlib.Path("D:\\Git_Repositories\\Pycharm_Project\\Mower\\test").glob( - "*.png" - ): - img = cv2.imread(i.__str__()) - img = img[up:down, left:right] - tags_img = recruit_.split_tags(img) - tags = [] - h, w, _ = img.shape - for index, value in enumerate(tags_img): - res = recruit_.get_recruit_tag(value) - tag_pos = ( - left + (index % 3) * int(w / 3) + 30, - up + int(index / 3) * int(h / 2) + 30, - ) - - print(res["tag"], tag_pos, int(index / 3)) - print(" ") - cv2.imshow("1", img) - cv2.waitKey() - - # recruit_.recruit_config = { - # "recruitment_time": { - # "3": 460, - # "4": 540, - # "5": 540, - # "6": 540 - # }, - # "recruit_robot": True, - # "permit_target": 30, - # "recruit_auto_5": 2, - # "recruit_auto_only5": True, - # "recruit_email_enable": True, - # } - # print(recruit_.recruit_tags(['重装干员', '先锋干员', '高级资深干员', '支援', '支援机械'])) + unittest.main() diff --git a/arknights_mower/utils/recognize.py b/arknights_mower/utils/recognize.py index b6599a481..645b99f67 100644 --- a/arknights_mower/utils/recognize.py +++ b/arknights_mower/utils/recognize.py @@ -317,7 +317,7 @@ def get_scene(self) -> int: self.scene = Scene.MISSION_DAILY elif self.find("mission_weekly_on"): self.scene = Scene.MISSION_WEEKLY - elif self.find("agent_token"): + elif self.find("recruit/agent_token") or self.find("recruit/agent_token_first"): self.scene = Scene.RECRUIT_AGENT elif self.find("main_theme"): self.scene = Scene.TERMINAL_MAIN_THEME @@ -752,7 +752,6 @@ def find( return None template_matching = { - "agent_token": ((1740, 765), (1920, 805)), "arrange_check_in": ((30, 300), (175, 700)), "arrange_check_in_on": ((30, 300), (175, 700)), "biography": (768, 934), @@ -794,6 +793,29 @@ def find( "ope_finish": (87, 265), "ope_plan": (1278, 24), "ope_select_start_empty": ((0, 0), (400, 400)), + "recruit/agent_token": ((1740, 765), (1920, 805)), + "recruit/agent_token_first": ((1700, 760), (1920, 810)), + "recruit/available_level": (1294, 234), + "recruit/begin_recruit": scope, + "recruit/career_needs": (350, 593), + "recruit/lmb": (945, 27), + "recruit/recruit_done": scope, + "recruit/recruit_lock": scope, + "recruit/job_requirements": scope, + "recruit/ticket": ((900, 0), (1920, 120)), + "recruit/time": (1304, 112), + "recruit/refresh": (1366, 560), + "recruit/refresh_comfirm": (1237, 714), + "recruit/riic_res/CASTER": ((750, 730), (1920, 860)), + "recruit/riic_res/MEDIC": ((750, 730), (1920, 860)), + "recruit/riic_res/PIONEER": ((750, 730), (1920, 860)), + "recruit/riic_res/SPECIAL": ((750, 730), (1920, 860)), + "recruit/riic_res/SNIPER": ((750, 730), (1920, 860)), + "recruit/riic_res/SUPPORT": ((750, 730), (1920, 860)), + "recruit/riic_res/TANK": ((750, 730), (1920, 860)), + "recruit/riic_res/WARRIOR": ((750, 730), (1920, 860)), + "recruit/start_recruit": (1438, 849), + "recruit/stone": ((900, 0), (1920, 120)), "riic/assistants": ((1320, 400), (1600, 650)), "riic/iron": ((1570, 230), (1630, 340)), "riic/orundum": ((1500, 320), (1800, 550)), @@ -806,6 +828,19 @@ def find( "navigation/ope_hard_small": 0.7, "navigation/ope_normal": 0.7, "navigation/ope_normal_small": 0.7, + "recruit/agent_token": 0.8, + "recruit/agent_token_first": 0.8, + "recruit/lmb": 0.7, + "recruit/riic_res/CASTER": 0.7, + "recruit/riic_res/MEDIC": 0.7, + "recruit/riic_res/PIONEER": 0.7, + "recruit/riic_res/SPECIAL": 0.7, + "recruit/riic_res/SNIPER": 0.7, + "recruit/riic_res/SUPPORT": 0.7, + "recruit/riic_res/TANK": 0.7, + "recruit/riic_res/WARRIOR": 0.7, + "recruit/time": 0.8, + "recruit/stone": 0.7, } if res in template_matching: