diff --git a/resource/infrast.json b/resource/infrast.json index aef1c728d2..f6269d2973 100644 --- a/resource/infrast.json +++ b/resource/infrast.json @@ -355,11 +355,11 @@ "all": 30 }, "hash": { - "史都华德": "43174f1fefbae7abcfd3ce13e23bef3bcf0fcf0fcff24ff7ef04fe06be060a00", - "杰西卡": "27c427c4ffc6f88663c473df70dfb0dfaac4aac622c6e047ebc4ebc4cbc40844", - "调香师": "bbcfbb9f0a1a3bda9bdf999fbadf3a5f3fdf3bdf3a4f7bcfea52cbd2cbd20a42", - "香草": "7cff78ff5024fe24fe7e7c427c7ed67efe7e7c7e44187cff44187c187c184418", - "罗比菈塔": "e8f1e8f708f70961ed2eeeff0ef3eaf7a857a9d369f769af4d29cbf38bf38081" + "史都华德": "43774f3fefbfefafe7efcff7ef3fef3fef3fcf0fcb0fcff74bf7ef05fe07be07", + "杰西卡": "200427e427e7ffe7fbc473c473df73dfbbc4abc6aac62247ca45dbc4dbc4dbc4", + "调香师": "b8cfbbcfbbdf9b1a3fffbfffbb9fbbdfbfffbffffbdfebcffbd7ebd7cbd2cbd2", + "香草": "1e247eff7cff70fffe7efe7e7c7e7e7eff7eff7e7e7e7e187eff7eff7e187e18", + "罗比菈塔": "e8f3e8f708f70963e96feefe6ef7eaf7e817a857a9f76daf4d29cf29cff38bf3" } }, { @@ -371,8 +371,8 @@ "all": 20 }, "hash": { - "夜刀": "1000fe7efe7e68125e105e125a12da12fe32fc225c224c625e627ece72ce6000", - "流星": "887efe7e7e427e7e9642be7ebe7e3a584c7e4cfe4cfe6cfeac18eeffeeff0200" + "夜刀": "10001800ff7fff7f78197f195f195f19fe11fe31fe315c315e615f677fe773c6", + "流星": "c87eff7e7f7e7f7e1e7efe7eff7e7f781e7e5e7e5efe5e7eff7eff18afffafff" } } ] diff --git a/resource/tasks.json b/resource/tasks.json index a87ae2c4cd..a9265504e8 100644 --- a/resource/tasks.json +++ b/resource/tasks.json @@ -858,13 +858,13 @@ "InfrastSkillsHash": { "template": "empty.png", "templThreshold_Doc": "作为哈希距离的阈值使用", - "templThreshold": 60, + "templThreshold": 55, "rectMove_Doc": "基于笑脸的位置移动", "rectMove": [ 0, - 21, + 20, 113, - 20 + 22 ] }, "InfrastSmileyOnRest": { diff --git a/src/MeoAssistance/AsstInfrastDef.h b/src/MeoAssistance/AsstInfrastDef.h index 033b77daef..bd1d6f6d16 100644 --- a/src/MeoAssistance/AsstInfrastDef.h +++ b/src/MeoAssistance/AsstInfrastDef.h @@ -67,7 +67,18 @@ namespace asst { namespace infrast { - // 基建单个干员的技能 + struct Oper + { + ::std::string hash; // 有些干员的技能是完全一样的,做个hash区分一下不同干员 + ::std::string name; // 预留 + Smiley smiley; + double mood_ratio = 0; // 心情进度条的百分比 + Doing doing = Doing::Invalid; + bool selected = false; // 干员是否已被选择(蓝色的选择框) + ::std::unordered_set skills; + Rect rect; + }; + struct SkillsComb { SkillsComb() = default; @@ -92,34 +103,18 @@ namespace asst ::std::unordered_set skills; ::std::unordered_map efficient; ::std::unordered_map efficient_regex; - }; - struct Oper - { - ::std::string hash; // 有些干员的技能是完全一样的,做个hash区分一下不同干员 - ::std::string name; // 预留 - Smiley smiley; - double mood_ratio = 0; // 心情进度条的百分比 - Doing doing = Doing::Invalid; - bool selected = false; // 干员是否已被选择(蓝色的选择框) - SkillsComb skills_comb; - Rect rect; - }; - - struct SkillsCombWithCond - { - SkillsComb skills_comb; + ::std::string hash; bool hash_filter = false; - ::std::unordered_map hashs; // 限定只允许某些hash匹配的某些干员。若hash不相同,即使技能匹配了也不可用。hashs若为空,则不生效 + ::std::unordered_map possible_hashs; // 限定只允许某些hash匹配的某些干员。若hash不相同,即使技能匹配了也不可用。hashs若为空,则不生效 }; - // 基建技能组 struct SkillsGroup { ::std::string desc; // 文字介绍,实际不起作用 ::std::unordered_map conditions; // 技能组合可用条件,例如:key 发电站数量,value 3 - ::std::vector necessary; // 必选技能。这里面的缺少任一,则该技能组合不可用 - ::std::vector optional; // 可选技能。 + ::std::vector necessary; // 必选技能。这里面的缺少任一,则该技能组合不可用 + ::std::vector optional; // 可选技能。 bool allow_external = false; // 当干员数没满3个的时候,是否允许补充外部干员 }; diff --git a/src/MeoAssistance/InfrastConfiger.cpp b/src/MeoAssistance/InfrastConfiger.cpp index cc7b1de4dd..fad188c067 100644 --- a/src/MeoAssistance/InfrastConfiger.cpp +++ b/src/MeoAssistance/InfrastConfiger.cpp @@ -87,8 +87,7 @@ bool asst::InfrastConfiger::parse(const json::value& json) } } for (const json::value& necessary_json : group_json.at("necessary").as_array()) { - infrast::SkillsCombWithCond comb_with_cond; - infrast::SkillsComb& comb = comb_with_cond.skills_comb; + infrast::SkillsComb comb; comb.desc = necessary_json.get("desc", std::string()); for (const json::value& skill_json : necessary_json.at("skills").as_array()) { const auto& skill = m_skills.at(facility_name).at(skill_json.as_string()); @@ -135,15 +134,15 @@ bool asst::InfrastConfiger::parse(const json::value& json) } } if (necessary_json.exist("hash")) { + comb.hash_filter = true; for (const auto& [key, value] : necessary_json.at("hash").as_object()) { - comb_with_cond.hashs.emplace(key, value.as_string()); + comb.possible_hashs.emplace(key, value.as_string()); } } - group.necessary.emplace_back(std::move(comb_with_cond)); + group.necessary.emplace_back(std::move(comb)); } for (const json::value& opt_json : group_json.at("optional").as_array()) { - infrast::SkillsCombWithCond comb_with_cond; - infrast::SkillsComb& comb = comb_with_cond.skills_comb; + infrast::SkillsComb comb; comb.desc = opt_json.get("desc", std::string()); for (const json::value& skill_json : opt_json.at("skills").as_array()) { const auto& skill = m_skills.at(facility_name).at(skill_json.as_string()); @@ -190,11 +189,12 @@ bool asst::InfrastConfiger::parse(const json::value& json) } } if (opt_json.exist("hash")) { + comb.hash_filter = true; for (const auto& [key, value] : opt_json.at("hash").as_object()) { - comb_with_cond.hashs.emplace(key, value.as_string()); + comb.possible_hashs.emplace(key, value.as_string()); } } - group.optional.emplace_back(std::move(comb_with_cond)); + group.optional.emplace_back(std::move(comb)); } group_vec.emplace_back(std::move(group)); } diff --git a/src/MeoAssistance/InfrastOperImageAnalyzer.cpp b/src/MeoAssistance/InfrastOperImageAnalyzer.cpp index 087089d7a2..7beb1d4181 100644 --- a/src/MeoAssistance/InfrastOperImageAnalyzer.cpp +++ b/src/MeoAssistance/InfrastOperImageAnalyzer.cpp @@ -204,35 +204,46 @@ void asst::InfrastOperImageAnalyzer::hash_analyze() const Rect hash_rect_move = resource.task().task_ptr("InfrastSkillsHash")->rect_move; + cv::Mat gray; + cv::cvtColor(m_image, gray, cv::COLOR_BGR2GRAY); + for (auto&& oper : m_result) { Rect roi = hash_rect_move; roi.x += oper.smiley.rect.x; roi.y += oper.smiley.rect.y; - // 从左往右找到第一个白色点 - Rect white_roi = roi; - constexpr static int HashKernelSize = 16; - int threshold = 200; - bool find_point = false; - for (int i = 0; i != white_roi.width && !find_point; ++i) { - for (int j = 0; j != white_roi.height && !find_point; ++j) { - cv::Point point(white_roi.x + i, white_roi.y + j); - auto value = m_image.at(point); - if (value[0] > threshold && value[1] > threshold && value[2] > threshold) { - white_roi.x += i; - white_roi.width -= i; - find_point = true; - break; + constexpr static int threshold = 100; + auto check_point = [&](cv::Point point) -> bool { + auto value = gray.at(point); + return value > threshold; + }; + // 找到四个方向上最靠外的白色点,把ROI缩小裁出来 + int left = -1, right = -1, top = INT_MAX, bottom = -1; + for (int i = 0; i != roi.width; ++i) { + for (int j = 0; j != roi.height; ++j) { + cv::Point point(roi.x + i, roi.y + j); + if (check_point(point)) { + if (left < 0) { + left = i; + } + right = i; + top = (std::min)(top, j); + bottom = (std::max)(bottom, j); } } } - cv::Mat image_roi = m_image(utils::make_rect(white_roi)); + roi.x += left; + roi.width = right - left + 1; + roi.y += top; + roi.height = bottom - top + 1; + + cv::Mat image_roi = gray(utils::make_rect(roi)); cv::Mat bin; - cv::cvtColor(image_roi, image_roi, cv::COLOR_BGR2GRAY); cv::threshold(image_roi, bin, threshold, 255, cv::THRESH_BINARY); + constexpr static int HashKernelSize = 16; cv::resize(bin, bin, cv::Size(HashKernelSize, HashKernelSize)); std::stringstream hash_value; - uchar* pix = bin.data; + cv::uint8_t* pix = bin.data; int tmp_dec = 0; for (int ro = 0; ro < 256; ro++) { tmp_dec = tmp_dec << 1; @@ -359,7 +370,7 @@ void asst::InfrastOperImageAnalyzer::skill_analyze() #ifdef LOG_TRACE cv::Mat skill_mat = m_image(utils::make_rect(skill_rect)); #endif - oper.skills_comb.skills.emplace(std::move(most_confident_skills)); + oper.skills.emplace(std::move(most_confident_skills)); } log.trace(log_str, "]"); } diff --git a/src/MeoAssistance/InfrastProductionTask.cpp b/src/MeoAssistance/InfrastProductionTask.cpp index 2d119b29d3..3544d0653b 100644 --- a/src/MeoAssistance/InfrastProductionTask.cpp +++ b/src/MeoAssistance/InfrastProductionTask.cpp @@ -164,31 +164,43 @@ size_t asst::InfrastProductionTask::opers_detect() LogTraceFunction; const auto& image = ctrler.get_image(); - InfrastOperImageAnalyzer skills_analyzer(image); - skills_analyzer.set_facility(m_facility); + InfrastOperImageAnalyzer oper_analyzer(image); + oper_analyzer.set_facility(m_facility); - if (!skills_analyzer.analyze()) { + if (!oper_analyzer.analyze()) { return 0; } - const auto& cur_all_info = skills_analyzer.get_result(); - max_num_of_opers_per_page = (std::max)(max_num_of_opers_per_page, cur_all_info.size()); + const auto& cur_all_opers = oper_analyzer.get_result(); + max_num_of_opers_per_page = (std::max)(max_num_of_opers_per_page, cur_all_opers.size()); - for (const auto& cur_info : cur_all_info) { + int cur_available_num = cur_all_opers.size(); + for (const auto& cur_oper : cur_all_opers) { + if (cur_oper.skills.empty()) { + --cur_available_num; + continue; + } auto find_iter = std::find_if( m_all_available_opers.cbegin(), m_all_available_opers.cend(), - [&cur_info](const infrast::Oper& info) -> bool { - int dist = utils::hamming(cur_info.hash, info.hash); - return dist < m_hash_dist_threshold; + [&cur_oper](const infrast::Oper& oper) -> bool { + // 技能相同的有可能是同一个干员,比一下hash + if (oper.skills == cur_oper.skills) { + int dist = utils::hamming(cur_oper.hash, oper.hash); +#ifdef LOG_TRACE + log.trace("opers_detect hash dist |", dist, cur_oper.hash, oper.hash); +#endif + return dist < m_hash_dist_threshold; + } + else { // 技能不同肯定不是同一个干员,不比了 + return false; + } }); // 如果两个的hash距离过小,则认为是同一个干员,不进行插入 if (find_iter != m_all_available_opers.cend()) { continue; } - auto pred_info = cur_info; - pred_info.skills_comb = efficient_regex_calc(pred_info.skills_comb); - m_all_available_opers.emplace_back(std::move(pred_info)); + m_all_available_opers.emplace_back(cur_oper); } - return cur_all_info.size(); + return cur_available_num; } bool asst::InfrastProductionTask::optimal_calc() @@ -200,33 +212,40 @@ bool asst::InfrastProductionTask::optimal_calc() if (m_all_available_opers.size() < max_num_of_opers) { return false; } + std::vector all_avaliable_combs; + all_avaliable_combs.reserve(m_all_available_opers.size()); + for (auto&& oper : m_all_available_opers) { + auto comb = efficient_regex_calc(oper.skills); + comb.hash = oper.hash; + all_avaliable_combs.emplace_back(std::move(comb)); + } // 先把单个的技能按效率排个序,取效率最高的几个 - std::vector optimal_opers; - optimal_opers.reserve(max_num_of_opers); + std::vector optimal_combs; + optimal_combs.reserve(max_num_of_opers); double max_efficient = 0; - std::sort(m_all_available_opers.begin(), m_all_available_opers.end(), - [&](const infrast::Oper& lhs, const infrast::Oper& rhs) -> bool { - return lhs.skills_comb.efficient.at(m_product) > rhs.skills_comb.efficient.at(m_product); + std::sort(all_avaliable_combs.begin(), all_avaliable_combs.end(), + [&](const infrast::SkillsComb& lhs, const infrast::SkillsComb& rhs) -> bool { + return lhs.efficient.at(m_product) > rhs.efficient.at(m_product); }); - for (const auto& oper : m_all_available_opers) { + for (const auto& comb : all_avaliable_combs) { std::string skill_str; - for (const auto& skill : oper.skills_comb.skills) { + for (const auto& skill : comb.skills) { skill_str += skill.id + " "; } - log.trace(skill_str, oper.skills_comb.efficient.at(m_product)); + log.trace(skill_str, comb.efficient.at(m_product)); } for (int i = 0; i != max_num_of_opers; ++i) { - optimal_opers.emplace_back(m_all_available_opers.at(i)); - max_efficient += m_all_available_opers.at(i).skills_comb.efficient.at(m_product); + optimal_combs.emplace_back(all_avaliable_combs.at(i)); + max_efficient += all_avaliable_combs.at(i).efficient.at(m_product); } { std::string log_str = "[ "; - for (const auto& oper : optimal_opers) { - log_str += oper.skills_comb.desc.empty() ? oper.skills_comb.skills.begin()->names.front() : oper.skills_comb.desc; + for (const auto& comb : optimal_combs) { + log_str += comb.desc.empty() ? comb.skills.begin()->names.front() : comb.desc; log_str += "; "; } log_str += "]"; @@ -237,10 +256,10 @@ bool asst::InfrastProductionTask::optimal_calc() auto& all_group = resource.infrast().get_skills_group(m_facility); for (const infrast::SkillsGroup& group : all_group) { LogTraceScope(group.desc); - auto cur_available_opers = m_all_available_opers; + auto cur_available_opers = all_avaliable_combs; bool group_unavailable = false; - std::vector cur_opers; - cur_opers.reserve(max_num_of_opers); + std::vector cur_combs; + cur_combs.reserve(max_num_of_opers); double cur_efficient = 0; // 条件判断,不符合的直接过滤掉 bool meet_condition = true; @@ -264,23 +283,24 @@ bool asst::InfrastProductionTask::optimal_calc() continue; } // necessary里的技能,一个都不能少 - for (const infrast::SkillsCombWithCond& nec_skills : group.necessary) { + // TODO necessary暂时没做hash校验。因为没有需要比hash的necessary干员( + for (const infrast::SkillsComb& nec_skills : group.necessary) { auto find_iter = std::find_if( cur_available_opers.cbegin(), cur_available_opers.cend(), - [&](const infrast::Oper& arg) -> bool { - return arg.skills_comb == nec_skills.skills_comb; + [&](const infrast::SkillsComb& arg) -> bool { + return arg == nec_skills; }); if (find_iter == cur_available_opers.cend()) { group_unavailable = true; break; } - cur_opers.emplace_back(*find_iter); - if (auto iter = nec_skills.skills_comb.efficient_regex.find(m_product); - iter != nec_skills.skills_comb.efficient_regex.cend()) { - cur_efficient += efficient_regex_calc(nec_skills.skills_comb).efficient.at(m_product); + cur_combs.emplace_back(nec_skills); + if (auto iter = nec_skills.efficient_regex.find(m_product); + iter != nec_skills.efficient_regex.cend()) { + cur_efficient += efficient_regex_calc(nec_skills.skills).efficient.at(m_product); } else { - cur_efficient += nec_skills.skills_comb.efficient.at(m_product); + cur_efficient += nec_skills.efficient.at(m_product); } cur_available_opers.erase(find_iter); } @@ -290,32 +310,32 @@ bool asst::InfrastProductionTask::optimal_calc() // 排个序,因为产物不同,效率可能会发生变化,所以配置文件里默认的顺序不一定准确 auto optional = group.optional; for (auto&& opt : optional) { - if (auto iter = opt.skills_comb.efficient_regex.find(m_product); - iter != opt.skills_comb.efficient_regex.cend()) { - opt.skills_comb = efficient_regex_calc(opt.skills_comb); + if (auto iter = opt.efficient_regex.find(m_product); + iter != opt.efficient_regex.cend()) { + opt = efficient_regex_calc(opt.skills); } } std::sort(optional.begin(), optional.end(), - [&](const infrast::SkillsCombWithCond& lhs, - const infrast::SkillsCombWithCond& rhs) -> bool { - return lhs.skills_comb.efficient.at(m_product) > rhs.skills_comb.efficient.at(m_product); + [&](const infrast::SkillsComb& lhs, + const infrast::SkillsComb& rhs) -> bool { + return lhs.efficient.at(m_product) > rhs.efficient.at(m_product); }); // 可能有多个干员有同样的技能,所以这里需要循环找同一个技能,直到找不到为止 - for (const infrast::SkillsCombWithCond& opt : optional) { + for (const infrast::SkillsComb& opt : optional) { auto find_iter = cur_available_opers.cbegin(); - while (cur_opers.size() != max_num_of_opers) { + while (cur_combs.size() != max_num_of_opers) { find_iter = std::find_if( find_iter, cur_available_opers.cend(), - [&](const infrast::Oper& arg) -> bool { - return arg.skills_comb.skills == opt.skills_comb.skills; + [&](const infrast::SkillsComb& arg) -> bool { + return arg == opt; }); if (find_iter != cur_available_opers.cend()) { // 要求技能匹配的同时,hash也要匹配 bool hash_matched = false; - if (!opt.hashs.empty()) { - for (const auto& [key, hash] : opt.hashs) { + if (!opt.possible_hashs.empty()) { + for (const auto& [key, hash] : opt.possible_hashs) { int dist = utils::hamming(find_iter->hash, hash); log.trace("optimal_calc | hash dist", dist, hash, find_iter->hash); if (dist < m_hash_dist_threshold) { @@ -332,8 +352,8 @@ bool asst::InfrastProductionTask::optimal_calc() continue; } - cur_opers.emplace_back(*find_iter); - cur_efficient += opt.skills_comb.efficient.at(m_product); + cur_combs.emplace_back(opt); + cur_efficient += opt.efficient.at(m_product); find_iter = cur_available_opers.erase(find_iter); } else { @@ -343,12 +363,12 @@ bool asst::InfrastProductionTask::optimal_calc() } // 说明可选的没凑满人 - if (cur_opers.size() < max_num_of_opers) { + if (cur_combs.size() < max_num_of_opers) { // 允许外部的话,就把单个干员凑进来 if (group.allow_external) { - for (size_t i = cur_opers.size(); i != max_num_of_opers; ++i) { - cur_opers.emplace_back(cur_available_opers.at(i)); - cur_efficient += cur_available_opers.at(i).skills_comb.efficient.at(m_product); + for (size_t i = cur_combs.size(); i != max_num_of_opers; ++i) { + cur_combs.emplace_back(cur_available_opers.at(i)); + cur_efficient += cur_available_opers.at(i).efficient.at(m_product); } } else { // 否则这个组合人不够,就不可用了 @@ -357,8 +377,8 @@ bool asst::InfrastProductionTask::optimal_calc() } { std::string log_str = "[ "; - for (const auto& oper : cur_opers) { - log_str += oper.skills_comb.desc.empty() ? oper.skills_comb.skills.begin()->names.front() : oper.skills_comb.desc; + for (const auto& comb : cur_combs) { + log_str += comb.desc.empty() ? comb.skills.begin()->names.front() : comb.desc; log_str += "; "; } log_str += "]"; @@ -366,21 +386,21 @@ bool asst::InfrastProductionTask::optimal_calc() } if (cur_efficient > max_efficient) { - optimal_opers = std::move(cur_opers); + optimal_combs = std::move(cur_combs); max_efficient = cur_efficient; } } { std::string log_str = "[ "; - for (const auto& oper : optimal_opers) { - log_str += oper.skills_comb.desc.empty() ? oper.skills_comb.skills.begin()->names.front() : oper.skills_comb.desc; + for (const auto& comb : optimal_combs) { + log_str += comb.desc.empty() ? comb.skills.begin()->names.front() : comb.desc; log_str += "; "; } log_str += "]"; log.trace("optimal efficient", max_efficient, " , skills:", log_str); } - m_optimal_opers = std::move(optimal_opers); + m_optimal_combs = std::move(optimal_combs); return true; } @@ -395,18 +415,18 @@ bool asst::InfrastProductionTask::opers_choose() } const auto& image = ctrler.get_image(); - InfrastOperImageAnalyzer skills_analyzer(image); - skills_analyzer.set_facility(m_facility); + InfrastOperImageAnalyzer oper_analyzer(image); + oper_analyzer.set_facility(m_facility); - if (!skills_analyzer.analyze()) { + if (!oper_analyzer.analyze()) { return false; } - skills_analyzer.sort_by_loc(); + oper_analyzer.sort_by_loc(); - auto cur_all_info = skills_analyzer.get_result(); + auto cur_all_opers = oper_analyzer.get_result(); // 这个情况一般是滑动/识别出错了,把所有的干员都滑过去了 - if (cur_all_info.empty()) { + if (cur_all_opers.empty()) { if (!has_error) { has_error = true; // 倒回去再来一遍 @@ -420,38 +440,49 @@ bool asst::InfrastProductionTask::opers_choose() } std::vector selected_hash; - for (auto opt_iter = m_optimal_opers.begin(); opt_iter != m_optimal_opers.end();) { - auto find_iter = std::find_if( - cur_all_info.cbegin(), cur_all_info.cend(), - [&](const infrast::Oper& lhs) -> bool { + for (auto opt_iter = m_optimal_combs.begin(); opt_iter != m_optimal_combs.end();) { + auto oper_equal = [&](const infrast::Oper& lhs) -> bool { + if (lhs.skills != opt_iter->skills) { + return false; + } + if (!opt_iter->hash_filter) { + return true; + } + else { // 既要技能相同,也要hash相同,双重校验 - int dist = utils::hamming(lhs.hash, opt_iter->hash); - log.trace("opers_choose | hash dist", dist, lhs.hash, opt_iter->hash); - return dist < m_hash_dist_threshold - && lhs.skills_comb == opt_iter->skills_comb; - }); - if (find_iter == cur_all_info.cend()) { + for (const auto& [_, hash] : opt_iter->possible_hashs) { + int dist = utils::hamming(lhs.hash, hash); + log.trace("opers_choose | hash dist", dist, lhs.hash, hash); + if (dist < m_hash_dist_threshold) { + return true; + } + } + return false; + } + }; + + auto find_iter = std::find_if( + cur_all_opers.cbegin(), cur_all_opers.cend(), oper_equal); + + if (find_iter == cur_all_opers.cend()) { ++opt_iter; continue; } if (find_iter->selected == true) { - cur_all_info.erase(find_iter); + cur_all_opers.erase(find_iter); continue; } ctrler.click(find_iter->rect); selected_hash.emplace_back(find_iter->hash); { auto avlb_iter = std::find_if( - m_all_available_opers.cbegin(), m_all_available_opers.cend(), - [&](const infrast::Oper& lhs) -> bool { - return lhs.skills_comb == opt_iter->skills_comb; - }); + m_all_available_opers.cbegin(), m_all_available_opers.cend(), oper_equal); m_all_available_opers.erase(avlb_iter); } - cur_all_info.erase(find_iter); - opt_iter = m_optimal_opers.erase(opt_iter); + cur_all_opers.erase(find_iter); + opt_iter = m_optimal_combs.erase(opt_iter); } - if (m_optimal_opers.empty()) { + if (m_optimal_combs.empty()) { break; } @@ -464,10 +495,11 @@ bool asst::InfrastProductionTask::opers_choose() asst::infrast::SkillsComb asst::InfrastProductionTask::efficient_regex_calc( - asst::infrast::SkillsComb skills_comb) const + std::unordered_set skills) const { + infrast::SkillsComb comb(std::move(skills)); // 根据正则,计算当前干员的实际效率 - for (auto&& [product, formula] : skills_comb.efficient_regex) { + for (auto&& [product, formula] : comb.efficient_regex) { std::string cur_formula = formula; for (size_t pos = 0; pos != std::string::npos;) { pos = cur_formula.find('[', pos); @@ -489,9 +521,9 @@ asst::InfrastProductionTask::efficient_regex_calc( } int eff = calculator::eval(cur_formula); - skills_comb.efficient[product] = eff; + comb.efficient[product] = eff; } - return skills_comb; + return comb; } bool asst::InfrastProductionTask::facility_list_detect() diff --git a/src/MeoAssistance/InfrastProductionTask.h b/src/MeoAssistance/InfrastProductionTask.h index 3ec5cc8be7..e659e005a1 100644 --- a/src/MeoAssistance/InfrastProductionTask.h +++ b/src/MeoAssistance/InfrastProductionTask.h @@ -29,14 +29,15 @@ namespace asst size_t opers_detect(); // 返回当前页面的干员数 bool optimal_calc(); bool opers_choose(); - infrast::SkillsComb efficient_regex_calc(infrast::SkillsComb skill_info) const; + infrast::SkillsComb efficient_regex_calc( + std::unordered_set skills) const; static int m_hash_dist_threshold; std::string m_facility; std::string m_product; std::vector m_all_available_opers; - std::vector m_optimal_opers; + std::vector m_optimal_combs; std::vector m_facility_list_tabs; size_t max_num_of_opers_per_page = 0; };