예제 #1
0
def try_solve(craft: Craft, line_to_finish, timeLimit=None):
    # 一个传统的bfs
    best = (craft, [])  # 目前最佳项 第一个坑是数据,第二个是历史
    queue = [(craft, [])]  # 待办事项
    start = time.perf_counter()  # 开始的计时
    last_print = start  # 最后一次打印“临时方案”的时间
    while queue:  # 还有待办事项就继续
        if timeLimit is not None and time.perf_counter() - start > timeLimit:
            return best  # 超时了就直接返回
        if time.perf_counter() > last_print + 1:  # 打印一下临时方案证明不是程序炸了
            last_print = time.perf_counter()
            debug(
                "solver bfs",
                "plan in {:.2f}s:{}({})".format(last_print - start, best[1],
                                                best[0].current_quality))
        t_craft, t_history = queue.pop(0)  # 获取一个待办事项
        for skill in allowSkills(t_craft):  # 获取可用的技能
            try:
                tt_craft = t_craft.clone()
                tt_craft.use_skill(skill, True)
            except CheckUnpass:
                continue
            if tt_craft.current_cp < cpReq:
                continue
            tt_craft.status = DEFAULT_STATUS()
            new_data = (tt_craft, t_history + [skill]
                        )  # 往上一坨都是模拟使用技能然后组成一个新的事项
            if tt_craft.current_durability >= durReq and tt_craft.current_quality > best[
                    0].current_quality:
                if best[0].current_quality >= line_to_finish:
                    return new_data  # 如果高于斩杀线就直接返回
                best = new_data  # 如果品质高点就存best
            queue.append(new_data)  # 把数据塞进去待办事项
    return best
예제 #2
0
def try_solve(craft: Craft, timeLimit=None):
    best = (craft, [])
    queue = [(craft, [])]
    start = time.perf_counter()
    last_print = start
    while queue:
        if timeLimit is not None and time.perf_counter() - start > timeLimit:
            return best
        if time.perf_counter() > last_print + 1:
            last_print = time.perf_counter()
            debug(
                "solver bfs",
                "plan in {:.2f}s:{}({})".format(last_print - start, best[1],
                                                best[0].current_quality),
            )
        t_craft, t_history = queue.pop(0)
        for skill in allowSkills(t_craft):
            try:
                tt_craft = t_craft.clone()
                tt_craft.use_skill(skill, True)
            except Exception:
                continue
            if tt_craft.current_cp < cpReq:
                continue
            tt_craft.status = DEFAULT_STATUS()
            new_data = (tt_craft, t_history + [skill])
            if (tt_craft.current_durability >= durReq
                    and tt_craft.current_quality > best[0].current_quality):
                best = new_data
            queue.append(new_data)
    return best
예제 #3
0
 def is_finished(self, craft, prev_skill=None):
     if not bool(self.queue) or craft.status.name in SpecialStatus:
         start = time.perf_counter()
         ans = try_solve(craft, 8)
         if ans is not None:
             self.queue = ans[1]
             debug(
                 "solver dfs", "new plan in {:.2f}s:{}({})".format(
                     time.perf_counter() - start, self.queue,
                     ans[0].current_quality))
     return not bool(self.queue)
예제 #4
0
 def is_finished(self, craft, prev_skill=None):
     if craft.current_quality >= craft.recipe.max_quality:
         return True
     if self.is_first:
         debug("solver astar", "try to solve:\n%s" % craft.simple_str())
         self.is_first = False
     if not bool(
             self.queue
     ) or craft.status.name in SpecialStatus or prev_skill != self.prev_skill:
         start = time.perf_counter()
         ans = try_solve(craft, TIME_LIMIT)
         if ans[1]:
             debug(
                 "solver astar", "new plan in {:.2f}s:{}({})".format(
                     time.perf_counter() - start, ans[1],
                     ans[0].current_quality))
             self.queue = ans[
                 1]  # if time.perf_counter() - start < TIME_LIMIT else ans[1][:4]
     return not bool(self.queue)
예제 #5
0
 def is_finished(self, craft, prev_skill=None):
     if self.line_to_finish is None:
         temp = Craft(craft.recipe, craft.player)
         temp.add_effect('内静', 11)
         temp.merge_effects()
         for s in ['阔步', '改革', '观察', '注视加工', '阔步', '比尔格的祝福', '制作']:
             temp.use_skill(s)
         self.line_to_finish = temp.recipe.max_quality - temp.current_quality
         debug("solver bfs", f"the line to finish is {self.line_to_finish}")
     if not bool(
             self.queue
     ) or craft.status.name in SpecialStatus or prev_skill != self.prev_skill:
         start = time.perf_counter()
         ans = try_solve(craft, self.line_to_finish, 8)
         if ans[1]:
             self.queue = ans[1]
             debug(
                 "solver bfs", "new plan in {:.2f}s:{}({})".format(
                     time.perf_counter() - start, self.queue,
                     ans[0].current_quality))
     return len(
         self.queue
     ) < 3 or craft.current_quality >= self.line_to_finish  # 这里是为了配合后续astar,让它有一点调整空间,同时如果高于斩杀线就直接下一步
예제 #6
0
def try_solve(craft: Craft, timeLimit=None):
    best = (craft, [])
    best_un_finish = None
    best_start_with = None
    best_start_with_l = 0
    queue = [(craft, [])]
    start = time.perf_counter()
    last_print = start
    while queue:
        if timeLimit is not None and time.perf_counter() - start > timeLimit:
            return best
        if time.perf_counter() > last_print + 1:
            last_print = time.perf_counter()
            debug(
                "solver astar",
                "plan in {:.2f}s:{}({})".format(last_print - start, best[1],
                                                best[0].current_quality))
        t_craft, t_history = queue.pop(0)
        if best_start_with is not None and len(
                t_history
        ) > 8 and t_history[:best_start_with_l] != best_start_with:
            continue
        skills = allowSkills(t_craft)
        for skill in skills:
            try:
                try:
                    tt_craft = t_craft.clone()
                    tt_craft.use_skill(skill, True)
                except CheckUnpass:
                    continue
            except Exception:
                debug("solver astar",
                      'error at testing skill %s:\n%s' % (skill, t_craft))
                debug("solver astar", format_exc())
                continue
            tt_craft.status = DEFAULT_STATUS()
            new_data = (tt_craft, t_history + [skill])
            if tt_craft.current_durability >= 1 and tt_craft.current_quality > best[
                    0].current_quality:
                if tt_craft.current_quality >= tt_craft.recipe.max_quality:
                    return new_data
                best = new_data
            if skill != "比尔格的祝福":
                if tt_craft.current_durability >= 1 and (
                        best_un_finish is None or tt_craft.current_quality >
                        best_un_finish[0].current_quality):
                    best_un_finish = new_data
                    l = len(new_data[1])
                    c = (l // 4) + 1
                    if l > 9:
                        best_start_with = new_data[1][:c]
                        best_start_with_l = c
                queue.append(new_data)
    return best
예제 #7
0
    def global_cool_down_ability(
            self, data: LogicData
    ) -> Optional[Union[UseAbility, UseItem, UseCommon]]:
        if data.config.query_skill:
            return data.config.get_query_skill()  # 队列技能
        res = res_lv(data)
        lv = data.me.level
        dis = data.target_distance
        min_mana = min(data.gauge.white_mana, data.gauge.black_mana)
        max_mana = max(data.gauge.white_mana, data.gauge.black_mana)
        use_white = data.gauge.white_mana < data.gauge.black_mana
        has_swift = 1249 in data.effects or 167 in data.effects
        swift_res_target = search_swift_res(data)

        if data.target is None and swift_res_target is not None and data.me.currentMP >= (
                2400 if has_swift else 3100):
            if has_swift:
                return UseAbility(7523, swift_res_target.id)
            elif not data.is_moving:
                return UseAbility(7514, data.me.id)
            elif not data[7561]:
                return UseAbility(7561)

        if dis > 25 or not data.valid_enemies: return

        if data.me.level >= 52 and count_enemy(data, 2) > 2 and min_mana >= (
                90 if not res else 20 if data[7521] else 50):
            return UseAbility(7513)  # 人数够了就画圆

        "处理魔连击开始"
        if data.combo_id == 7504 and lv >= 35:
            return UseAbility(7512) if dis < 4 else None
        elif data.combo_id == 7512 and lv >= 50:
            return UseAbility(7516) if dis < 4 else None
        elif data.combo_id == 7529 and lv >= 68:
            if lv < 70: return UseAbility(7525)
            if data.gauge.white_mana == data.gauge.black_mana:
                if 1234 in data.effects: return UseAbility(7526)
                if 1235 in data.effects: return UseAbility(7525)
            return UseAbility(7526 if use_white else 7525)
        elif (data.combo_id == 7525 or data.combo_id == 7526) and lv >= 80:
            return UseAbility(16530)
        "处理魔连击结束"

        if min_mana >= 5:  # 续斩处理溢出魔元、走位
            if max_mana >= (90 if res else 97) and dis > 10:
                return UseAbility(16529)
            # if res and data.is_moving and not has_swift:
            #     if data.gcd:
            #         return None
            #     else:
            #         return UseAbility(16529)  # 续斩处理溢出魔元、走位

        if (lv < 2 or res and min_mana >=
            (80 if lv >= 50 else 55 if lv >= 35 else 30)) and dis < 4:
            return UseAbility(7516)  # 魔回刺、判断是否适合开始魔连击

        cnt = count_enemy(data, 0)
        if has_swift:  # 有瞬发
            if swift_res_target is not None and data.me.currentMP >= 2400:
                debug('swift_res', swift_res_target.Name,
                      hex(swift_res_target.id))
                return UseAbility(7523, swift_res_target.id)
            if lv >= 15 and cnt > (1 if lv >= 66 else 2):
                return UseAbility(7509)  # aoe 散碎、冲击
            if lv >= 4:
                return UseAbility(
                    7507 if use_white and lv >= 10 else 7505)  # 闪雷、疾风
        if not data.is_moving and lv >= 2:
            if cnt > 2 and lv >= 18:
                return UseAbility(16525 if use_white and lv >= 22 else 16524)
            if use_white:
                if 1234 in data.effects: return UseAbility(7510)
                if 1235 in data.effects: return UseAbility(7511)
            else:
                if 1235 in data.effects: return UseAbility(7511)
                if 1234 in data.effects: return UseAbility(7510)
            return UseAbility(7503)