重构clue_new为Solve

This commit is contained in:
Elaina 2024-09-24 01:03:47 +08:00
parent 74a9c79786
commit 1dbf508120
11 changed files with 437 additions and 365 deletions

View file

@ -7,17 +7,15 @@ from ctypes import CFUNCTYPE, c_char_p, c_int, c_void_p
from datetime import datetime, timedelta
from typing import Literal
import cv2
from arknights_mower.data import agent_list, base_room_list
from arknights_mower.solvers.credit import CreditSolver
from arknights_mower.solvers.credit_fight import CreditFight
from arknights_mower.solvers.cultivate_depot import cultivate as cultivateDepotSolver
from arknights_mower.solvers.depotREC import depotREC as DepotSolver
from arknights_mower.solvers.infra.base_mixin import BaseMixin
from arknights_mower.solvers.infra.clue import ClueSolver
from arknights_mower.solvers.infra.enter_room import EnterRoomSolver
from arknights_mower.solvers.infra.get_agent_from_room import GetAgentFromRoomSolver
from arknights_mower.solvers.infra.get_clue_count import GetClueCountSolver
from arknights_mower.solvers.infra.reload import (
ReloadSolver,
)
@ -29,18 +27,16 @@ from arknights_mower.solvers.operation import OperationSolver
from arknights_mower.solvers.reclamation_algorithm import ReclamationAlgorithm
from arknights_mower.solvers.recruit import RecruitSolver
from arknights_mower.solvers.secret_front import SecretFront
from arknights_mower.solvers.shop import CreditShop
from arknights_mower.solvers.sign_in import SignInSolver
from arknights_mower.solvers.skland import SKLand
from arknights_mower.solvers.sss_navi import SSSNaviSolver
from arknights_mower.utils import config, detector, rapidocr
from arknights_mower.utils import config, detector
from arknights_mower.utils import typealias as tp
from arknights_mower.utils.csleep import MowerExit, csleep
from arknights_mower.utils.datetime import format_time, get_server_weekday
from arknights_mower.utils.digit_reader import DigitReader
from arknights_mower.utils.email import send_message
from arknights_mower.utils.graph import SceneGraphSolver
from arknights_mower.utils.image import cropimg, loadres, thres2
from arknights_mower.utils.log import logger
from arknights_mower.utils.operators import Operator, Operators
from arknights_mower.utils.path import get_path
@ -1696,357 +1692,18 @@ class BaseSchedulerSolver(SceneGraphSolver, BaseMixin):
self.todo_task = True
def clue_new(self):
logger.info("基建:线索")
self.scene_graph_navigation(Scene.INFRA_MAIN)
self.enter_room("meeting")
clue_size = (162, 216)
clue_top_left = {
"daily": (1118, 334),
"receive": (1305, 122),
"give_away": (30, 208),
# 摆放线索界面,线索框的左上角
1: (72, 228),
2: (374, 334),
3: (679, 198),
4: (1003, 265),
5: (495, 660),
6: (805, 573),
7: (154, 608),
}
dot_offset = (168, -8)
main_offset = (425, 0)
main_time_offset = (443, 257)
def va(a, b):
return a[0] + b[0], a[1] + b[1]
def tl2p(top_left):
return top_left, va(top_left, clue_size)
def is_orange(dot):
orange_dot = (255, 104, 1)
return all([abs(dot[i] - orange_dot[i]) < 3 for i in range(3)])
clue_scope = {}
for index, top_left in clue_top_left.items():
clue_scope[index] = tl2p(top_left)
clue_dots = {}
main_dots = {}
main_time = {}
main_scope = {}
for i in range(1, 8):
clue_dots[i] = va(clue_top_left[i], dot_offset)
main_dots[i] = va(clue_dots[i], main_offset)
main_time[i] = va(clue_top_left[i], main_time_offset)
main_scope[i] = tl2p(va(clue_top_left[i], main_offset))
class ClueTaskManager:
def __init__(self):
# 操作顺序:领取每日线索、接收好友线索、摆线索、送线索、更新线索交流结束时间
self.task_list = [
"daily",
"receive",
"place",
"give_away",
"party_time",
]
self.task = self.task_list[0]
def complete(self, task):
task = task or self.task
if task in self.task_list:
self.task_list.remove(task)
self.task = self.task_list[0] if self.task_list else None
tm_thres = 0.6
def clue_cls(scope):
scope_dict = clue_scope if isinstance(scope, str) else main_scope
img = cropimg(config.recog.img, scope_dict[scope])
for i in range(1, 8):
res = loadres(f"clue/{i}")
result = cv2.matchTemplate(img, res, cv2.TM_CCOEFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
if max_val > tm_thres:
return i
return None
exit_pos = (1239, 144)
ctm = ClueTaskManager()
friend_clue = []
clue_status = {}
def place_index():
for cl, st in clue_status.items():
if st in ["available", "self", "available_self_only"]:
return cl, st
return None, None
def detect_unlock():
unlock_pos = self.find("clue/button_unlock")
if unlock_pos is None:
return None
color = self.get_color(self.get_pos(unlock_pos))
if all(color > [252] * 3):
return unlock_pos
return None
while ctm.task:
scene = self.scene()
if scene == Scene.INFRA_DETAILS:
if ctm.task == "party_time":
if self.find("clue/title_party", scope=((1600, 190), (1880, 260))):
self.party_time = self.double_read_time(
((1768, 438), (1902, 480))
)
logger.info(f"线索交流结束时间:{self.party_time}")
if not find_next_task(
self.tasks,
task_type=TaskTypes.CLUE_PARTY,
):
self.tasks.append(
SchedulerTask(
time=self.party_time - timedelta(milliseconds=1),
task_type=TaskTypes.CLUE_PARTY,
)
)
else:
self.party_time = None
logger.info("线索交流未开启")
ctm.complete("party_time")
else:
# 点击左下角,关闭进驻信息,进入线索界面
self.tap((725, 850))
elif scene == Scene.INFRA_CONFIDENTIAL:
if ctm.task == "daily":
# 检查是否领过线索
daily_scope = ((1815, 200), (1895, 250))
if self.find("clue/badge_new", scope=daily_scope):
self.tap((1800, 270))
else:
ctm.complete("daily")
elif ctm.task == "receive":
receive_scope = ((1815, 360), (1895, 410))
if self.find("clue/badge_new", scope=receive_scope):
self.ctap((1800, 430))
else:
ctm.complete("receive")
elif ctm.task == "place":
if unlock_pos := detect_unlock():
self.tap(unlock_pos)
continue
for i in range(1, 8):
if is_orange(self.get_color(main_dots[i])):
clue_status[i] = "available"
elif clue_cls(i):
hsv = config.recog.hsv
if 160 < hsv[main_time[i][1]][main_time[i][0]][0] < 180:
clue_status[i] = "friend"
else:
clue_status[i] = "self"
else:
clue_status[i] = None
cl, st = place_index()
if st in ["available", "self", "available_self_only"]:
self.tap(main_scope[cl])
continue
else:
ctm.complete("place")
elif ctm.task == "give_away":
self.ctap((1799, 578))
elif ctm.task == "party_time":
self.back()
elif scene == Scene.CLUE_DAILY:
if not self.find(
"clue/icon_notification", scope=((1400, 0), (1920, 400))
) and (clue := clue_cls("daily")):
logger.info(f"领取今日线索({clue}号)")
self.tap_element("clue/button_get")
ctm.complete("daily")
else:
# 今日线索已领取点X退出
self.tap((1484, 152))
elif scene == Scene.CLUE_RECEIVE:
if self.find(
"infra_trust_complete", scope=((1230, 0), (1920, 1080)), score=0.1
):
self.sleep()
continue
if clue := clue_cls("receive"):
name_scope = ((1580, 220), (1880, 255))
name_img = cropimg(config.recog.gray, name_scope)
name_img = cv2.copyMakeBorder(
name_img, 48, 48, 48, 48, cv2.BORDER_REPLICATE
self.party_time = ClueSolver().run()
if self.party_time:
if not find_next_task(
self.tasks,
task_type=TaskTypes.CLUE_PARTY,
):
self.tasks.append(
SchedulerTask(
time=self.party_time - timedelta(milliseconds=1),
task_type=TaskTypes.CLUE_PARTY,
)
name = rapidocr.engine(
name_img,
use_det=True,
use_cls=False,
use_rec=True,
)[0][0][1]
name = name.strip() if name else "好友"
logger.info(f"接收{name}{clue}号线索")
self.tap(name_scope)
else:
ctm.complete("receive")
self.tap(exit_pos)
elif scene == Scene.CLUE_PLACE:
cl, st = place_index()
if cl is None:
if unlock_pos := detect_unlock():
self.tap(unlock_pos)
else:
ctm.complete("place")
self.tap(exit_pos)
continue
if self.get_color((1328 + 77 * cl, 114))[0] < 150:
# 右上角 1-7
self.tap(clue_scope[cl])
continue
receive = st in ["available", "self"]
filter_receive = (1900, 45)
filter_self = (1610, 70)
filter_pos = filter_receive if receive else filter_self
if not all(self.get_color(filter_pos) > [252] * 3):
self.tap(filter_pos)
continue
clue_pos = ((1305, 208), (1305, 503), (1305, 797))
clue_list = []
for cp in clue_pos:
clue_img = cropimg(config.recog.img, tl2p(cp))
res = loadres(f"clue/{cl}")
result = cv2.matchTemplate(clue_img, res, cv2.TM_CCOEFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
if max_val > tm_thres:
name_scope = (va(cp, (274, 99)), va(cp, (580, 134)))
name_img = cropimg(config.recog.gray, name_scope)
name_img = cv2.copyMakeBorder(
name_img, 48, 48, 48, 48, cv2.BORDER_REPLICATE
)
name = rapidocr.engine(
name_img,
use_det=True,
use_cls=False,
use_rec=True,
)[0][0][1]
if name:
name = name.strip()
time_scope = (va(cp, (45, 222)), va(cp, (168, 255)))
time_hsv = cropimg(config.recog.hsv, time_scope)
if 165 < time_hsv[0][0][0] < 175:
time_img = thres2(
cropimg(config.recog.gray, time_scope), 180
)
time_img = cv2.copyMakeBorder(
time_img, 48, 48, 48, 48, cv2.BORDER_REPLICATE
)
time = rapidocr.engine(
time_img,
use_det=True,
use_cls=False,
use_rec=True,
)[0][0][1]
if time:
time = time.strip()
else:
time = None
clue_list.append(
{"name": name, "time": time, "scope": tl2p(cp)}
)
else:
break
if clue_list:
list_name = "接收库" if receive else "自有库"
logger.info(f"{cl}号线索{list_name}{clue_list}")
selected = None
for c in clue_list:
if c["time"]:
selected = c
break
selected = selected or clue_list[0]
self.tap(selected["scope"])
if clue_status[cl] == "available":
clue_status[cl] = "friend"
elif clue_status[cl] == "available_self_only":
clue_status[cl] = "self_only"
elif clue_status[cl] == "self":
clue_status[cl] = "friend"
else:
clue_status[cl] = None
else:
if clue_status[cl] == "available":
clue_status[cl] = "available_self_only"
elif clue_status[cl] == "available_self_only":
clue_status[cl] = None
elif clue_status[cl] == "self":
clue_status[cl] = "self_only"
else:
clue_status[cl] = None
elif scene == Scene.CLUE_GIVE_AWAY:
give_away_true = self.leifeng_mode or (
not self.leifeng_mode and self.clue_count > self.clue_count_limit
)
if (c := clue_cls("give_away")) and give_away_true:
if not friend_clue:
if self.find(
"clue/icon_notification", scope=((1400, 0), (1920, 400))
):
self.sleep()
continue
for i in range(4):
label_scope = ((1450, 228 + i * 222), (1580, 278 + i * 222))
if not self.find("clue/label_give_away", scope=label_scope):
break
name_top_left = (870, 127 + 222 * i)
name_scope = (name_top_left, va(name_top_left, (383, 62)))
name = rapidocr.engine(
cropimg(config.recog.gray, name_scope),
use_det=True,
use_cls=False,
use_rec=True,
)[0][0][1]
if name:
name = name.strip()
data = {"name": name}
for j in range(1, 8):
pos = (1230 + j * 64, 142 + i * 222)
data[j] = self.get_color(pos)[0] < 137
friend_clue.append(data)
logger.debug(friend_clue)
friend = None
for idx, fc in enumerate(friend_clue):
if not fc[c]:
friend = idx
fc[c] = True
break
friend = friend or 0
logger.info(f"{friend_clue[friend]['name']}送一张线索{c}")
self.tap(clue_scope["give_away"])
self.clue_count -= 1
self.tap((1790, 200 + friend * 222))
else:
ctm.complete("give_away")
self.tap((1868, 54))
elif scene == Scene.CLUE_SUMMARY:
self.back()
else:
self.scene_graph_navigation(Scene.INFRA_MAIN)
self.enter_room("meeting")
shop_solver = CreditShop()
shop_solver.run()
self.scene_graph_navigation(Scene.INFRA_MAIN)
def adjust_order_time(self, accelerate, room):
@ -2590,11 +2247,9 @@ class BaseSchedulerSolver(SceneGraphSolver, BaseMixin):
def turn_on_room_detail(self, room):
EnterRoomSolver().run(room)
def get_agent_from_room(self, room, read_time_index=None):
def get_agent_from_room(self, room: str, read_time_index=None):
if read_time_index is None:
read_time_index = []
if room == "meeting" and not config.conf.leifeng_mode:
self.clue_count = GetClueCountSolver().run()
if room.startswith("dorm"):
read_time_index = [
i

View file

@ -1,9 +1,9 @@
#import lzma
#import pickle
# import lzma
# import pickle
import cv2
#from matplotlib import pyplot as plt
# from matplotlib import pyplot as plt
import numpy as np
from arknights_mower.models import secret_front
@ -17,7 +17,7 @@ from arknights_mower.utils.graph import SceneGraphSolver
from arknights_mower.utils.image import cropimg
from arknights_mower.utils.log import logger
#from arknights_mower import __rootdir__
# from arknights_mower import __rootdir__
from arknights_mower.utils.scene import Scene
from arknights_mower.utils.vector import sa
@ -217,8 +217,8 @@ class BaseChoose(SceneGraphSolver):
y21,
) = rect2[0]
x22, y22 = rect2[1]
#a = (x22 + x21) / 2
#b = (y22 + y21) / 2
# a = (x22 + x21) / 2
# b = (y22 + y21) / 2
# 如果rect2的左上角在rect1内并且rect2完全在rect1的边界内则认为rect2被rect1包含
return x11 < (x22 + x21) / 2 < x12 and y11 < (y22 + y21) / 2 < y12

View file

@ -0,0 +1,22 @@
from arknights_mower.solvers.shop import CreditShop
from arknights_mower.utils.log import logger
from .daily import DailySolver
from .get_clue_count import GetClueCountSolver
from .give_away import GiveAwaySolver
from .party_time import PartyTimeSolver
from .place import PlaceSolver
from .receive import ReceiveSolver
class ClueSolver:
def run(self) -> None:
logger.info("基建:线索")
clue_count = GetClueCountSolver().run()
DailySolver().run()
ReceiveSolver().run()
PlaceSolver().run()
GiveAwaySolver().run(clue_count)
party_time = PartyTimeSolver().run()
CreditShop().run()
return party_time

View file

@ -0,0 +1,34 @@
from arknights_mower.solvers.infra.enter_room import EnterRoomSolver
from arknights_mower.utils.graph import SceneGraphSolver
from arknights_mower.utils.log import logger
from arknights_mower.utils.recognize import Scene
from .utils import clue_cls
class DailySolver(SceneGraphSolver):
def run(self) -> None:
super().run()
def transition(self) -> bool:
if (scene := self.scene()) == Scene.INFRA_DETAILS:
self.tap((725, 850))
elif scene == Scene.INFRA_CONFIDENTIAL:
# 检查是否领过线索
daily_scope = ((1815, 200), (1895, 250))
if self.find("clue/badge_new", scope=daily_scope):
self.tap((1800, 270))
else:
return True
elif scene == Scene.CLUE_DAILY:
if not self.find(
"clue/icon_notification", scope=((1400, 0), (1920, 400))
) and (clue := clue_cls("daily")):
logger.info(f"领取今日线索({clue}号)")
self.tap_element("clue/button_get")
else:
# 今日线索已领取点X退出
self.tap((1484, 152))
return True
else:
EnterRoomSolver().run("meeting", detail=False)

View file

@ -0,0 +1,70 @@
from arknights_mower.solvers.infra.enter_room import EnterRoomSolver
from arknights_mower.utils import config, rapidocr
from arknights_mower.utils.graph import SceneGraphSolver
from arknights_mower.utils.image import cropimg
from arknights_mower.utils.log import logger
from arknights_mower.utils.recognize import Scene
from arknights_mower.utils.vector import va
from .utils import clue_cls, clue_scope
friend_clue = []
class GiveAwaySolver(SceneGraphSolver):
def run(self, clue_count) -> None:
self.clue_count = clue_count
super().run()
def transition(self) -> bool:
if (scene := self.scene()) == Scene.INFRA_DETAILS:
self.tap((725, 850))
elif scene == Scene.INFRA_CONFIDENTIAL:
self.ctap((1799, 578))
elif scene == Scene.CLUE_GIVE_AWAY:
give_away_true = config.conf.leifeng_mode or (
not config.conf.leifeng_mode and self.clue_count > 9
)
if (c := clue_cls("give_away")) and give_away_true:
if not friend_clue:
if self.find(
"clue/icon_notification", scope=((1400, 0), (1920, 400))
):
self.sleep()
return
for i in range(4):
label_scope = ((1450, 228 + i * 222), (1580, 278 + i * 222))
if not self.find("clue/label_give_away", scope=label_scope):
break
name_top_left = (870, 127 + 222 * i)
name_scope = (name_top_left, va(name_top_left, (383, 62)))
name = rapidocr.engine(
cropimg(config.recog.gray, name_scope),
use_det=True,
use_cls=False,
use_rec=True,
)[0][0][1]
if name:
name = name.strip()
data = {"name": name}
for j in range(1, 8):
pos = (1230 + j * 64, 142 + i * 222)
data[j] = self.get_color(pos)[0] < 137
friend_clue.append(data)
logger.debug(friend_clue)
friend = None
for idx, fc in enumerate(friend_clue):
if not fc[c]:
friend = idx
fc[c] = True
break
friend = friend or 0
logger.info(f"{friend_clue[friend]['name']}送一张线索{c}")
self.tap(clue_scope["give_away"])
self.clue_count -= 1
self.tap((1790, 200 + friend * 222))
else:
self.tap((1868, 54))
return True
else:
EnterRoomSolver().run("meeting", detail=False)

View file

@ -0,0 +1,25 @@
from arknights_mower.solvers.infra.base_mixin import BaseMixin
from arknights_mower.solvers.infra.enter_room import EnterRoomSolver
from arknights_mower.utils.graph import SceneGraphSolver
from arknights_mower.utils.log import logger
from arknights_mower.utils.recognize import Scene
class PartyTimeSolver(SceneGraphSolver, BaseMixin):
def run(self):
super().run()
return self.party_time
def transition(self) -> bool:
if self.scene() == Scene.INFRA_DETAILS:
if self.find("clue/title_party", scope=((1600, 190), (1880, 260))):
self.party_time = self.double_read_time(((1768, 438), (1902, 480)))
logger.info(f"线索交流结束时间:{self.party_time}")
return True
else:
self.party_time = None
logger.info("线索交流未开启")
return True
else:
EnterRoomSolver().run("meeting", detail=False)

View file

@ -0,0 +1,156 @@
import cv2
from arknights_mower.solvers.infra.enter_room import EnterRoomSolver
from arknights_mower.utils import config, rapidocr
from arknights_mower.utils.graph import SceneGraphSolver
from arknights_mower.utils.image import cropimg, loadres, thres2
from arknights_mower.utils.log import logger
from arknights_mower.utils.recognize import Scene
from arknights_mower.utils.vector import va
from .utils import (
clue_cls,
clue_scope,
exit_pos,
is_orange,
main_dots,
main_scope,
main_time,
tl2p,
tm_thres,
)
clue_status = {}
clue_pos = ((1305, 208), (1305, 503), (1305, 797))
clue_list = []
filter_receive = (1900, 45)
filter_self = (1610, 70)
def place_index():
for cl, st in clue_status.items():
if st in ["available", "self", "available_self_only"]:
return cl, st
return None, None
class PlaceSolver(SceneGraphSolver):
def run(self) -> None:
super().run()
def detect_unlock(self):
unlock_pos = self.find("clue/button_unlock")
if unlock_pos is None:
return None
color = self.get_color(self.get_pos(unlock_pos))
if all(color > [252] * 3):
return unlock_pos
return None
def transition(self) -> bool:
if (scene := self.scene()) == Scene.INFRA_DETAILS:
self.tap((725, 850))
elif scene == Scene.INFRA_CONFIDENTIAL:
if unlock_pos := self.detect_unlock():
self.tap(unlock_pos)
for i in range(1, 8):
if is_orange(self.get_color(main_dots[i])):
clue_status[i] = "available"
elif clue_cls(i):
hsv = config.recog.hsv
if 160 < hsv[main_time[i][1]][main_time[i][0]][0] < 180:
clue_status[i] = "friend"
else:
clue_status[i] = "self"
else:
clue_status[i] = None
cl, st = place_index()
if st in ["available", "self", "available_self_only"]:
self.tap(main_scope[cl])
else:
return True
elif scene == Scene.CLUE_PLACE:
cl, st = place_index()
receive = st in ["available", "self"]
filter_pos = filter_receive if receive else filter_self
if cl is None:
if unlock_pos := self.detect_unlock():
self.tap(unlock_pos)
else:
self.tap(exit_pos)
return True
elif self.get_color((1328 + 77 * cl, 114))[0] < 150:
# 右上角 1-7
self.tap(clue_scope[cl])
elif not all(self.get_color(filter_pos) > [252] * 3):
self.tap(filter_pos)
return
for cp in clue_pos:
clue_img = cropimg(config.recog.img, tl2p(cp))
res = loadres(f"clue/{cl}")
result = cv2.matchTemplate(clue_img, res, cv2.TM_CCOEFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
if max_val > tm_thres:
name_scope = (va(cp, (274, 99)), va(cp, (580, 134)))
name_img = cropimg(config.recog.gray, name_scope)
name_img = cv2.copyMakeBorder(
name_img, 48, 48, 48, 48, cv2.BORDER_REPLICATE
)
name = rapidocr.engine(
name_img,
use_det=True,
use_cls=False,
use_rec=True,
)[0][0][1]
if name:
name = name.strip()
time_scope = (va(cp, (45, 222)), va(cp, (168, 255)))
time_hsv = cropimg(config.recog.hsv, time_scope)
if 165 < time_hsv[0][0][0] < 175:
time_img = thres2(cropimg(config.recog.gray, time_scope), 180)
time_img = cv2.copyMakeBorder(
time_img, 48, 48, 48, 48, cv2.BORDER_REPLICATE
)
time = rapidocr.engine(
time_img,
use_det=True,
use_cls=False,
use_rec=True,
)[0][0][1]
if time:
time = time.strip()
else:
time = None
clue_list.append({"name": name, "time": time, "scope": tl2p(cp)})
else:
break
if clue_list:
list_name = "接收库" if receive else "自有库"
logger.info(f"{cl}号线索{list_name}{clue_list}")
selected = None
for c in clue_list:
if c["time"]:
selected = c
break
selected = selected or clue_list[0]
self.tap(selected["scope"])
if clue_status[cl] == "available":
clue_status[cl] = "friend"
elif clue_status[cl] == "available_self_only":
clue_status[cl] = "self_only"
elif clue_status[cl] == "self":
clue_status[cl] = "friend"
else:
clue_status[cl] = None
else:
if clue_status[cl] == "available":
clue_status[cl] = "available_self_only"
elif clue_status[cl] == "available_self_only":
clue_status[cl] = None
elif clue_status[cl] == "self":
clue_status[cl] = "self_only"
else:
clue_status[cl] = None
else:
EnterRoomSolver().run("meeting", detail=False)

View file

@ -0,0 +1,50 @@
import cv2
from arknights_mower.solvers.infra.enter_room import EnterRoomSolver
from arknights_mower.utils import config, rapidocr
from arknights_mower.utils.graph import SceneGraphSolver
from arknights_mower.utils.image import cropimg
from arknights_mower.utils.log import logger
from arknights_mower.utils.recognize import Scene
from .utils import clue_cls, exit_pos
class ReceiveSolver(SceneGraphSolver):
def run(self) -> None:
super().run()
def transition(self) -> bool:
if (scene := self.scene()) == Scene.INFRA_DETAILS:
self.tap((725, 850))
elif scene == Scene.INFRA_CONFIDENTIAL:
receive_scope = ((1815, 360), (1895, 410))
if self.find("clue/badge_new", scope=receive_scope):
self.ctap((1800, 430))
else:
return True
elif scene == Scene.CLUE_RECEIVE:
if self.find(
"infra_trust_complete", scope=((1230, 0), (1920, 1080)), score=0.1
):
self.sleep()
elif clue := clue_cls("receive"):
name_scope = ((1580, 220), (1880, 255))
name_img = cropimg(config.recog.gray, name_scope)
name_img = cv2.copyMakeBorder(
name_img, 48, 48, 48, 48, cv2.BORDER_REPLICATE
)
name = rapidocr.engine(
name_img,
use_det=True,
use_cls=False,
use_rec=True,
)[0][0][1]
name = name.strip() if name else "好友"
logger.info(f"接收{name}{clue}号线索")
self.tap(name_scope)
else:
self.tap(exit_pos)
return True
else:
EnterRoomSolver().run("meeting", detail=False)

View file

@ -0,0 +1,60 @@
import cv2
from arknights_mower.utils import config
from arknights_mower.utils.image import cropimg, loadres
from arknights_mower.utils.vector import va
clue_size = (162, 216)
clue_top_left = {
"daily": (1118, 334),
"receive": (1305, 122),
"give_away": (30, 208),
# 摆放线索界面,线索框的左上角
1: (72, 228),
2: (374, 334),
3: (679, 198),
4: (1003, 265),
5: (495, 660),
6: (805, 573),
7: (154, 608),
}
dot_offset = (168, -8)
main_offset = (425, 0)
main_time_offset = (443, 257)
def tl2p(top_left):
return top_left, va(top_left, clue_size)
def is_orange(dot):
orange_dot = (255, 104, 1)
return all([abs(dot[i] - orange_dot[i]) < 3 for i in range(3)])
clue_scope = {}
for index, top_left in clue_top_left.items():
clue_scope[index] = tl2p(top_left)
clue_dots = {}
main_dots = {}
main_time = {}
main_scope = {}
for i in range(1, 8):
clue_dots[i] = va(clue_top_left[i], dot_offset)
main_dots[i] = va(clue_dots[i], main_offset)
main_time[i] = va(clue_top_left[i], main_time_offset)
main_scope[i] = tl2p(va(clue_top_left[i], main_offset))
tm_thres = 0.6
exit_pos = (1239, 144)
def clue_cls(scope):
scope_dict = clue_scope if isinstance(scope, str) else main_scope
img = cropimg(config.recog.img, scope_dict[scope])
for i in range(1, 8):
res = loadres(f"clue/{i}")
result = cv2.matchTemplate(img, res, cv2.TM_CCOEFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
if max_val > tm_thres:
return i
return None

View file

@ -1,6 +1,6 @@
import cv2
#from matplotlib import pyplot as plt
# from matplotlib import pyplot as plt
import numpy as np
from arknights_mower.utils import config