Files
MHache/src/mhache_factory.cpp
2022-08-09 00:17:10 +02:00

282 lines
9.3 KiB
C++

#include <iostream>
#include <string>
#include <set>
#include <numeric>
#include "mhache_factory.h"
#include "mhache_skill.h"
#include "mhache_color.h"
MHacheFactory&
MHacheFactory::singleton()
{
static MHacheFactory factory;
return factory;
}
bool
MHacheFactory::parse_root_table(const std::filesystem::path& tomlfile, toml::table& root)
{
auto result = toml::parse_file(tomlfile.u8string());
if (!result) {
std::cerr << "Parsing of TOML file << " << tomlfile << " failed." << std::endl;
std::cerr << "-> " << result.error().description() << std::endl;
return false;
}
root = std::move(result.table());
return true;
}
bool
MHacheFactory::load_skills(const std::filesystem::path& tomlfile)
{
toml::table skills;
{
toml::table root;
if (!parse_root_table(tomlfile, root) || root.empty())
return false;
if (!deserialize_table_node<toml::table>(root, "skills", skills))
return false;
}
skills.for_each([this](const toml::key& skill_name, const toml::table& skill)
{
const std::string name = std::string(skill_name.str());
if (name.empty()) return false;
MHacheColor* color = nullptr;
{
std::string skill_color;
if (!deserialize_table_node(skill, "color", skill_color))
return false;
color = MHacheColor::get_color(skill_color);
} if (!color) return false;
std::string description;
if (!deserialize_table_node(skill, "description", description) || description.empty())
return false;
std::vector<std::string> levels;
if (!deserialize_table_node(skill, "levels", levels) || levels.empty())
return false;
_skills.emplace(name, description, color, std::move(levels));
return true;
});
return !(_skills.empty());
}
bool
MHacheFactory::load_armors(const std::filesystem::path& tomlfile)
{
toml::table sets;
{
toml::table root;
if (!parse_root_table(tomlfile, root) || root.empty())
return false;
if (!deserialize_table_node(root, "sets", sets))
return false;
}
sets.for_each([this](const toml::key& set_name, const toml::table& set)
{
const std::string name = std::string(set_name.str());
if (name.empty()) return false;
unsigned char rarity;
if (!deserialize_table_node(set, "rarity", rarity))
return false;
unsigned short defense;
if (!deserialize_table_node(set, "defense", defense))
return false;
MHacheArmor::ElementalResistances resistances;
if (!deserialize_table_node(set, "resistances", resistances))
return false;
// Prepare the armor
MHacheArmor armor(name, rarity, defense, std::move(resistances));
// Attach its parts
for (size_t label = 0; label < MHacheArmor::Part::Label::count; ++label)
{
toml::table part;
if (!deserialize_table_node(set, MHacheArmor::Part::label_names[label], part))
continue;
std::string part_name;
if (!deserialize_table_node(part, "name", part_name))
continue;
std::vector<unsigned char> part_slots;
if (!deserialize_table_node(part, "slots", part_slots))
continue;
toml::table part_skills;
if (!deserialize_table_node(part, "skills", part_skills))
continue;
armor[label]
.is_called(part_name)
.define_jewel_slots(std::move(part_slots));
part_skills.for_each([this, &armor, label](const toml::key& skill_name, toml::value<int64_t> skill_level)
{
const auto it_skill = _skills.find(skill_name.str());
if ((_skills.end() == it_skill) || 0 >= skill_level)
return false;
armor[label].add_skill(&(*it_skill), static_cast<unsigned char>(skill_level.get()));
return true;
});
if (armor[label].skills().empty())
{
armor[label].detach();
continue;
}
}
if (armor.attached_parts().size() > 0)
_armors.insert(std::move(armor));
return true;
});
return !_armors.empty();
}
void
MHacheFactory::find_builds(const MappedSkillLevels& skills_levels) const
{
std::array<
std::set<const MHacheArmor::Part*, PtrLessComparator<MHacheArmor::Part>>,
MHacheArmor::Part::Label::count
> armors_parts;
for (const auto& skill_level: skills_levels)
{
const MHacheSkill* p_skill = skill_level.first;
if (!p_skill) continue;
const std::string_view skill_name = p_skill->name();
for (const MHacheArmor& armor: _armors) {
const auto matching_parts = armor.search_for_skill(skill_name);
for (const size_t idx: matching_parts)
armors_parts[idx].insert(&armor[idx]);
}
}
if (armors_parts.empty())
return;
MappedSkillLevels build;
std::vector<std::array<const MHacheArmor::Part*, MHacheArmor::Part::count>> results;
std::array<const MHacheArmor::Part*, MHacheArmor::Part::count> result;
auto accumulate_skills = [](const MappedSkillLevels& AdditionalSkills, MappedSkillLevels& OutputSkills)
{
for (const auto& s: AdditionalSkills)
OutputSkills[s.first] += s.second;
};
auto is_matching_build = [](const MappedSkillLevels& Skills, const MappedSkillLevels& ExpectedSkills)
{
size_t cpt = 0;
for (const auto& s: ExpectedSkills) {
auto it = Skills.find(s.first);
if (Skills.end() == it) break;
if (it->second >= s.second) ++cpt;
}
return (cpt == ExpectedSkills.size());
};
std::array<size_t, MHacheArmor::Part::count> parts_modulo;
parts_modulo[MHacheArmor::Part::LEGS] = 1;
for (size_t i = (MHacheArmor::Part::count - 1); i-- > 0;)
{
parts_modulo[i] = (armors_parts[i + 1].empty() ? 1 : armors_parts[i + 1].size()) * parts_modulo[i + 1];
}
/*
const size_t modulo_legs = 1;
const size_t modulo_waist = (armors_parts[MHacheArmor::Part::LEGS ].empty() ? 1 : armors_parts[MHacheArmor::Part::LEGS ].size()) * modulo_legs;
const size_t modulo_arms = (armors_parts[MHacheArmor::Part::WAIST].empty() ? 1 : armors_parts[MHacheArmor::Part::WAIST].size()) * modulo_waist;
const size_t modulo_chest = (armors_parts[MHacheArmor::Part::ARMS ].empty() ? 1 : armors_parts[MHacheArmor::Part::ARMS ].size()) * modulo_arms;
const size_t modulo_head = (armors_parts[MHacheArmor::Part::CHEST].empty() ? 1 : armors_parts[MHacheArmor::Part::CHEST].size()) * modulo_chest;
*/
const size_t combinations =
(armors_parts[MHacheArmor::Part::HEAD ].empty() ? 1 : armors_parts[MHacheArmor::Part::HEAD ].size()) * parts_modulo[MHacheArmor::Part::HEAD];
std::array<
std::set<const MHacheArmor::Part*, PtrLessComparator<MHacheArmor::Part>>::iterator,
MHacheArmor::Part::count
> parts_iterator;
for (unsigned char label = 0; label < MHacheArmor::Part::count; ++label)
parts_iterator[label] = armors_parts[label].begin();
/*
std::set<const MHacheArmor::Part*, PtrLessComparator<MHacheArmor::Part>>::iterator it_head = armors_parts[MHacheArmor::Part::HEAD].begin();
std::set<const MHacheArmor::Part*, PtrLessComparator<MHacheArmor::Part>>::iterator it_chest = armors_parts[MHacheArmor::Part::CHEST].begin();
std::set<const MHacheArmor::Part*, PtrLessComparator<MHacheArmor::Part>>::iterator it_arms = armors_parts[MHacheArmor::Part::ARMS].begin();
std::set<const MHacheArmor::Part*, PtrLessComparator<MHacheArmor::Part>>::iterator it_waist = armors_parts[MHacheArmor::Part::WAIST].begin();
std::set<const MHacheArmor::Part*, PtrLessComparator<MHacheArmor::Part>>::iterator it_legs = armors_parts[MHacheArmor::Part::LEGS].begin();
*/
for (size_t i = 0; i < combinations; ++i)
{
build = {};
result = {};
for (unsigned char label = 0; label < MHacheArmor::Part::count; ++label)
{
if (!armors_parts[label].empty() && (0 == (i % parts_modulo[label])))
{
if (std::next(parts_iterator[label]) == armors_parts[label].end()) {
parts_iterator[label] = armors_parts[label].begin();
}
else
parts_iterator[label] = std::next(parts_iterator[label]);
}
if (parts_iterator[label] != armors_parts[label].end()) {
accumulate_skills((*parts_iterator[label])->skills(), build);
result[label] = (*parts_iterator[label]);
if (is_matching_build(build, skills_levels)) {
results.push_back(std::move(result));
break;
}
}
}
}
for (const auto& r: results) {
MappedSkillLevels rlevels;
for (unsigned char i = 0; i < MHacheArmor::Part::count; ++i)
{
accumulate_skills(r[i]->skills(), rlevels);
}
for (const auto& s: rlevels) {
std::cerr << s.first->name() << " -> " << s.second << std::endl;
}
}
}