mr. propre

This commit is contained in:
Thibault Heckel 2022-08-09 00:17:10 +02:00
parent 5d62062803
commit 2096e6814a
9 changed files with 537 additions and 133 deletions

View File

@ -2,7 +2,5 @@ cmake_minimum_required(VERSION 3.23)
project(MHache VERSION 0.1)
set (CMAKE_CXX_STANDARD 17)
add_subdirectory(dependencies)
add_subdirectory(src)

View File

@ -3,6 +3,11 @@ add_library(
"${tomlplusplus_SOURCE_DIR}/src/toml++/toml.cpp"
)
target_compile_features(
tomlplusplus PUBLIC
cxx_std_17
)
target_compile_definitions(
tomlplusplus PUBLIC
TOML_EXCEPTIONS=0

View File

@ -14,14 +14,32 @@ class MHacheSkill;
template <class P, class LessOperator = std::less<P>>
struct PtrLessComparator {
using is_transparent = void;
bool operator () (const P* a, const P* b) const
{
if (!a) return true;
if (!b) return false;
return LessOperator()(*a, *b);
}
bool operator() (std::string_view a, const P* b) const
{
if (!b) return false;
return LessOperator()(a, *b);
}
bool operator() (const P* a, std::string_view b) const
{
if (!a) return false;
return LessOperator()(*a, b);
}
};
using MappedSkillLevels =
std::map<const MHacheSkill*, unsigned char,
PtrLessComparator<MHacheSkill, MHacheSkillLessOperator>>;
class MHacheArmor {
public:
typedef enum: unsigned char {
@ -33,149 +51,99 @@ public:
count
} ResistanceElement;
using ElementalResistances = std::array<char, ResistanceElement::count>;
class Part {
public:
typedef enum : unsigned char {
enum Label : unsigned char {
HEAD,
CHEST,
ARMS,
WAIST,
LEGS,
count
} Appellation;
static const constexpr std::array<std::string_view, Appellation::count> AppellationStr =
{
"head", "chest", "arms", "waist", "legs"
};
static constexpr std::array<std::string_view, Label::count> label_names =
{ "head", "chest", "arms", "waist", "legs" };
private:
friend class MHacheArmor;
Appellation _label;
Label _label;
std::string _name;
std::vector<unsigned char> _slots;
MappedSkillLevels _skills;
const MHacheArmor* _armor;
std::string _name;
std::vector<unsigned char> _slots;
std::map<const MHacheSkill*, unsigned char,
PtrLessComparator<MHacheSkill>> _skills;
const MHacheArmor* _armor;
Part()
: _label(Appellation::HEAD)
, _name()
, _slots({})
, _skills({})
, _armor(nullptr)
{}
Part();
public:
~Part() = default;
const std::string& name() const { return _name; }
const std::vector<unsigned char> slots() const { return _slots; }
const auto& skills() const { return _skills; }
Part(const Part&);
Part(Part&&);
Part& set_name(std::string&& name)
{
_name = std::move(name);
return *this;
}
Part& operator =(const Part&);
Part& operator =(Part&&);
Part& set_slots(std::vector<unsigned char>&& slots)
{
_slots = std::move(slots);
return *this;
}
Part& add_skill(const MHacheSkill* skill, unsigned char level)
{
if (skill && level > 0)
_skills.insert_or_assign(skill, level);
return *this;
}
bool operator < (const Part& other) const;
bool operator == (const Part& other) const;
Part& detach()
{
_armor = nullptr;
return *this;
}
const std::string& name() const;
const std::vector<unsigned char>& slots() const;
const MappedSkillLevels& skills() const;
ElementalResistances resistances() const;
unsigned char has_skill(const std::string& skill_name) const
{
for (const auto skill: _skills) {
if (skill.first && skill.first->name() == skill_name)
return skill.second;
}
unsigned char has_skill(std::string_view skill_name) const;
return 0;
}
Part& is_called(std::string_view name);
Part& define_jewel_slots(std::vector<unsigned char>&& slots);
Part& add_skill(const MHacheSkill* skill, unsigned char level);
Part& detach();
};
using PartList = std::array<Part, Part::Label::count>;
using LabelList = std::vector<Part::Label>;
private:
std::string _name;
unsigned char _rarity;
unsigned short _defense;
std::array<char, ResistanceElement::count> _resistances;
std::array<Part, Part::count> _parts;
std::string _name;
unsigned char _rarity;
unsigned short _defense;
ElementalResistances _resistances;
PartList _parts;
private:
MHacheArmor() = delete;
MHacheArmor();
public:
MHacheArmor(std::string_view name, unsigned char rarity, unsigned short defense, std::array<char, ResistanceElement::count>&& resistances)
: _name(name), _rarity(rarity), _defense(defense), _resistances(std::move(resistances)), _parts({})
{}
MHacheArmor(std::string_view name, unsigned char rarity, unsigned short defense,
ElementalResistances&& resistances);
MHacheArmor(const MHacheArmor&);
MHacheArmor(MHacheArmor&&);
MHacheArmor(const MHacheArmor&) = default;
MHacheArmor(MHacheArmor&&) = default;
~MHacheArmor() = default;
~MHacheArmor() = default;
MHacheArmor& operator=(const MHacheArmor&);
MHacheArmor& operator=(MHacheArmor&&);
MHacheArmor& operator=(const MHacheArmor&) = default;
MHacheArmor& operator=(MHacheArmor&&) = default;
bool operator < (const MHacheArmor& armor) const;
bool operator == (const MHacheArmor& armor) const;
bool operator < (const MHacheArmor& armor) const { return _name < armor._name; }
bool operator == (const MHacheArmor& armor) const { return _name == armor._name; }
const std::string& name() const;
unsigned char rarity() const;
unsigned char defense() const;
const ElementalResistances& resistances() const;
const std::string& name() const { return _name; }
std::vector<size_t> attached_parts() const
{
std::vector<size_t> ap;
LabelList attached_parts() const;
LabelList search_for_skill(std::string_view skill_name) const;
for (const auto& p: _parts)
if (p._armor)
ap.push_back(p._label);
const Part& operator[](size_t label) const;
Part& operator[](size_t label);
return ap;
}
const Part& operator[](size_t label) const
{
return _parts.at(label);
}
Part& operator[](size_t label)
{
Part& p = _parts.at(label);
p._label = Part::Appellation(label);
p._armor = this;
return p;
}
std::vector<size_t> search_for_skill(const std::string& skill_name) const
{
std::vector<size_t> ap;
for (const auto& p: _parts)
if (p._armor && p.has_skill(skill_name) > 0)
ap.push_back(p._label);
return ap;
}
const Part& operator[](Part::Label label) const;
Part& operator[](Part::Label label);
};
template<>
@ -187,4 +155,12 @@ struct std::hash<MHacheArmor>
}
};
struct MHacheArmorLessOperator {
using is_transparent = void;
bool operator() (const MHacheArmor& a, const MHacheArmor& b) const { return a < b; }
bool operator() (const MHacheArmor& a, std::string_view b) const { return a.name() < b; }
bool operator() (std::string_view a, const MHacheArmor& b) const { return a < b.name(); }
};
#endif

View File

@ -12,7 +12,7 @@
class MHacheFactory {
private:
std::set<MHacheSkill, MHacheSkillLessOperator> _skills;
std::set<MHacheArmor> _armors;
std::set<MHacheArmor, MHacheArmorLessOperator> _armors;
MHacheFactory() = default;
@ -113,6 +113,8 @@ public:
inline const auto& available_skills() const { return _skills; }
inline const auto& available_armors() const { return _armors; }
void find_builds(const MappedSkillLevels& skill_names) const;
};
#endif

View File

@ -22,8 +22,8 @@ private:
public:
inline
MHacheSkill(const std::string& name, const std::string& description, const MHacheColor* color, const std::vector<std::string>& levels)
: _name(name), _description(description), _color(color), _levels(levels)
MHacheSkill(std::string_view name, std::string_view description, const MHacheColor* color, std::vector<std::string>&& levels)
: _name(name), _description(description), _color(color), _levels(std::move(levels))
{}
~MHacheSkill() = default;

View File

@ -10,6 +10,11 @@ add_executable(
mhache_window.cpp
)
target_compile_definitions(
${PROJECT_NAME} PUBLIC
cxx_std_17
)
target_compile_options(
${PROJECT_NAME} PUBLIC
-Wall

View File

@ -1 +1,288 @@
#include <utility>
#include "mhache_armor.h"
// -- PART --
MHacheArmor::Part::Part()
: _label(MHacheArmor::Part::count)
, _name("")
, _slots({})
, _skills({})
, _armor(nullptr)
{}
MHacheArmor::Part::Part(const Part& other)
: MHacheArmor::Part()
{
*this = other;
}
MHacheArmor::Part::Part(Part&& other)
: MHacheArmor::Part()
{
*this = std::move(other);
}
MHacheArmor::Part&
MHacheArmor::Part::operator =(const Part& other)
{
if (this != &other) {
_label = other._label;
_name = other._name;
_slots = other._slots;
_skills = other._skills;
_armor = other._armor;
}
return *this;
}
MHacheArmor::Part&
MHacheArmor::Part::operator =(Part&& other)
{
if (this != &other) {
_label = std::exchange(other._label, MHacheArmor::Part::count);
_name = std::exchange(other._name, "");
_slots = std::exchange(other._slots, {});
_skills = std::exchange(other._skills, {});
_armor = std::exchange(other._armor, nullptr);
}
return *this;
}
bool
MHacheArmor::Part::operator <(const MHacheArmor::Part& other) const
{
return _name < other._name;
}
bool
MHacheArmor::Part::operator ==(const MHacheArmor::Part& other) const
{
return _name == other._name;
}
const std::string&
MHacheArmor::Part::name() const
{
return _name;
}
const std::vector<unsigned char>&
MHacheArmor::Part::slots() const
{
return _slots;
}
const MappedSkillLevels&
MHacheArmor::Part::skills() const
{
return _skills;
}
MHacheArmor::ElementalResistances
MHacheArmor::Part::resistances() const
{
MHacheArmor::ElementalResistances resistances;
if (_armor) {
const size_t nb_parts = _armor->attached_parts().size();
if (nb_parts > 0) {
resistances = _armor->resistances();
for (char& res: resistances)
res /= nb_parts;
}
}
return resistances;
}
unsigned char
MHacheArmor::Part::has_skill(std::string_view name) const
{
unsigned char level = 0;
const auto it = _skills.find(name);
if (_skills.end() != it)
level = it->second;
return level;
}
MHacheArmor::Part&
MHacheArmor::Part::is_called(std::string_view name)
{
_name = name;
return *this;
}
MHacheArmor::Part&
MHacheArmor::Part::define_jewel_slots(std::vector<unsigned char>&& slots)
{
_slots = std::exchange(slots, {});
return *this;
}
MHacheArmor::Part&
MHacheArmor::Part::add_skill(const MHacheSkill* skill, unsigned char level)
{
if (skill && level > 0 && level <= skill->levels().size())
_skills[skill] = level;
return *this;
}
MHacheArmor::Part&
MHacheArmor::Part::detach()
{
*this = MHacheArmor::Part();
return *this;
}
// -- PART --
// -------------------------------------------------------------------------------------------------
// -- ARMOR --
MHacheArmor::MHacheArmor()
: _name("")
, _rarity(0)
, _defense(0)
, _resistances({ 0, 0, 0, 0, 0 })
, _parts({})
{}
MHacheArmor::MHacheArmor(std::string_view name, unsigned char rarity, unsigned short defense,
ElementalResistances&& elemental_resistances)
: _name(name)
, _rarity(rarity)
, _defense(defense)
, _resistances(std::move(elemental_resistances))
, _parts({})
{}
MHacheArmor::MHacheArmor(const MHacheArmor& other)
: MHacheArmor()
{
*this = other;
}
MHacheArmor::MHacheArmor(MHacheArmor&& other)
: MHacheArmor()
{
*this = std::move(other);
}
MHacheArmor&
MHacheArmor::operator =(const MHacheArmor& other)
{
if (this != &other) {
_name = other._name;
_rarity = other._rarity;
_defense = other._defense;
_resistances = other._resistances;
_parts = other._parts;
}
return *this;
}
MHacheArmor&
MHacheArmor::operator =(MHacheArmor&& other)
{
if (this != &other) {
_name = std::exchange(other._name, "");
_rarity = std::exchange(other._rarity, 0);
_defense = std::exchange(other._defense, 0);
_resistances = std::exchange(other._resistances, {});
_parts = std::exchange(other._parts, {});
}
return *this;
}
bool
MHacheArmor::operator <(const MHacheArmor& other) const
{
return _name < other._name;
}
bool
MHacheArmor::operator ==(const MHacheArmor& other) const
{
return _name == other._name;
}
const std::string&
MHacheArmor::name() const
{
return _name;
}
unsigned char
MHacheArmor::rarity() const
{
return _rarity;
}
unsigned char
MHacheArmor::defense() const
{
return _defense;
}
const MHacheArmor::ElementalResistances&
MHacheArmor::resistances() const
{
return _resistances;
}
MHacheArmor::LabelList
MHacheArmor::attached_parts() const
{
LabelList labels;
for (const auto& p: _parts)
if (p._armor)
labels.push_back(p._label);
return labels;
}
MHacheArmor::LabelList
MHacheArmor::search_for_skill(std::string_view skill_name) const
{
LabelList labels;
for (const auto& p: _parts)
if (p.has_skill(skill_name))
labels.push_back(p._label);
return labels;
}
const MHacheArmor::Part&
MHacheArmor::operator[](size_t label) const
{
return _parts[label];
}
MHacheArmor::Part&
MHacheArmor::operator[](size_t label)
{
_parts[label]._armor = this;
_parts[label]._label = MHacheArmor::Part::Label(label);
return _parts[label];
}
const MHacheArmor::Part&
MHacheArmor::operator[](MHacheArmor::Part::Label label) const
{
return _parts[static_cast<size_t>(label)];
}
MHacheArmor::Part&
MHacheArmor::operator[](MHacheArmor::Part::Label label)
{
return _parts[static_cast<size_t>(label)];
}

View File

@ -1,5 +1,7 @@
#include <iostream>
#include <string>
#include <set>
#include <numeric>
#include "mhache_factory.h"
#include "mhache_skill.h"
@ -40,35 +42,32 @@ MHacheFactory::load_skills(const std::filesystem::path& tomlfile)
return false;
}
for (const auto& skill_entry: skills) {
const auto p_skill = skill_entry.second.as_table();
if (!p_skill) continue;
const auto& skill = *p_skill;
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))
continue;
return false;
color = MHacheColor::get_color(skill_color);
if (!color) continue;
}
} if (!color) return false;
std::string description;
if (!deserialize_table_node(skill, "description", description) || description.empty())
continue;
return false;
std::vector<std::string> levels;
if (!deserialize_table_node(skill, "levels", levels) || levels.empty())
continue;
return false;
std::string name = std::string(skill_entry.first.str());
if (name.empty()) continue;
_skills.emplace(name, description, color, std::move(levels));
_skills.emplace(std::move(name), std::move(description), color, std::move(levels));
}
return true;
});
return !(_skills.empty());
}
@ -99,7 +98,7 @@ MHacheFactory::load_armors(const std::filesystem::path& tomlfile)
if (!deserialize_table_node(set, "defense", defense))
return false;
std::array<char, MHacheArmor::ResistanceElement::count> resistances;
MHacheArmor::ElementalResistances resistances;
if (!deserialize_table_node(set, "resistances", resistances))
return false;
@ -107,10 +106,10 @@ MHacheFactory::load_armors(const std::filesystem::path& tomlfile)
MHacheArmor armor(name, rarity, defense, std::move(resistances));
// Attach its parts
for (unsigned char label = 0; label < MHacheArmor::Part::Appellation::count; ++label)
for (size_t label = 0; label < MHacheArmor::Part::Label::count; ++label)
{
toml::table part;
if (!deserialize_table_node(set, MHacheArmor::Part::AppellationStr[label], part))
if (!deserialize_table_node(set, MHacheArmor::Part::label_names[label], part))
continue;
std::string part_name;
@ -125,6 +124,10 @@ MHacheFactory::load_armors(const std::filesystem::path& tomlfile)
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());
@ -141,10 +144,6 @@ MHacheFactory::load_armors(const std::filesystem::path& tomlfile)
armor[label].detach();
continue;
}
armor[label]
.set_name(std::move(part_name))
.set_slots(std::move(part_slots));
}
if (armor.attached_parts().size() > 0)
@ -155,3 +154,128 @@ MHacheFactory::load_armors(const std::filesystem::path& tomlfile)
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;
}
}
}

View File

@ -179,11 +179,18 @@ MHacheWindow::build_widgets()
for (const auto& armor: armors) {
for (const auto skill: filtered_skills) {
if (!armor.search_for_skill(skill->name()).empty()) {
ImGui::Text(armor.name().c_str());
ImGui::Text("%s", armor.name().c_str());
break;
}
}
}
MappedSkillLevels seeklevels;
for (const auto skill: filtered_skills) {
seeklevels.insert({ skill, 1 });
}
MHacheFactory::singleton().find_builds(seeklevels);
}
//--