Compare commits

2 Commits

Author SHA1 Message Date
4771b5eed2 try some python-scrap from kiranico db 2022-09-02 00:00:33 +02:00
7e368c75de think armor part rather than armor 2022-09-01 18:09:25 +02:00
14 changed files with 1301 additions and 179 deletions

4
armors/heads.toml Normal file
View File

@@ -0,0 +1,4 @@
["Kamura Legacy Head Scarf"]
rarity = 8
resistances = [ 10, 0, 0, 0, 0 ]
defense = 90

View File

@@ -12,34 +12,6 @@
#include "mhache_skill.h"
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 {

View File

@@ -0,0 +1,73 @@
#ifndef MHACHE_ARMOR_PART_H
#define MHACHE_ARMOR_PART_H
#include <array>
#include <cstddef>
#include <string>
#include <string_view>
#include <optional>
#include "mhache_skill.h"
#include "mhache_tools.h"
class MHacheArmorPart {
public:
enum class Element : unsigned char {
FIRE = 0,
WATER,
THUNDER,
ICE,
DRAGON,
count
};
enum class Label : unsigned char {
HEAD = 0,
CHEST,
ARMS,
WAIST,
LEGS,
count
};
using ElementalResistances =
std::array<char, static_cast<unsigned char>(Element::count)>;
static constexpr std::array<std::string_view, static_cast<unsigned char>(Label::count)>
labels = { "head", "chest", "arms", "waist", "legs" };
private:
std::string _name;
Label _label;
unsigned char _rarity;
unsigned char _minimum_defense;
ElementalResistances _resistances;
std::vector<unsigned char> _slots;
MappedSkillLevels _skills;
MHacheArmorPart() = delete;
public:
MHacheArmorPart(std::string_view name, Label label, unsigned char rarity,
unsigned char defense, ElementalResistances&& resistances,
std::vector<unsigned char>&& slots, MappedSkillLevels&& skills);
MHacheArmorPart(MHacheArmorPart&& ) = delete;
MHacheArmorPart(const MHacheArmorPart&) = delete;
bool operator < (const MHacheArmorPart& other) const;
bool operator == (const MHacheArmorPart& other) const;
size_t compute_hash() const;
virtual ~MHacheArmorPart() {};
};
template <>
struct std::hash<MHacheArmorPart> {
size_t operator()(const MHacheArmorPart& part) const {
return part.compute_hash();
};
};
#endif

View File

@@ -3,16 +3,17 @@
#include <filesystem>
#include <set>
#include <string_view>
#include <toml++/toml.h>
#include "mhache_skill.h"
#include "mhache_armor.h"
// #include "mhache_armor.h"
class MHacheFactory {
private:
std::set<MHacheSkill, MHacheSkillLessOperator> _skills;
std::set<MHacheArmor, MHacheArmorLessOperator> _armors;
std::set<MHacheSkill> _skills;
// std::set<MHacheArmor, MHacheArmorLessOperator> _armors;
MHacheFactory() = default;
@@ -112,7 +113,7 @@ public:
bool load_armors(const std::filesystem::path&);
inline const auto& available_skills() const { return _skills; }
inline const auto& available_armors() const { return _armors; }
// inline const auto& available_armors() const { return _armors; }
void find_builds(const MappedSkillLevels& skill_names) const;
};

View File

@@ -2,9 +2,12 @@
#define MHACHE_SKILL_H
#include <string>
#include <string_view>
#include <vector>
#include <map>
#include "mhache_color.h"
#include "mhache_tools.h"
class MHacheSkill {
private:
@@ -37,16 +40,8 @@ public:
inline bool operator == (const MHacheSkill& obj) const { return _name == obj._name; };
};
template<>
struct std::hash<MHacheSkill>
{
size_t operator() (const MHacheSkill& skill) const
{
return std::hash<std::string>{}(skill.name());
}
};
struct MHacheSkillLessOperator {
template <>
struct std::less<MHacheSkill> {
using is_transparent = void;
bool operator() (const MHacheSkill& a, const MHacheSkill& b) const { return a < b; }
@@ -54,4 +49,8 @@ struct MHacheSkillLessOperator {
bool operator() (std::string_view a, const MHacheSkill& b) const { return a < b.name(); }
};
using MappedSkillLevels =
std::map<const MHacheSkill*, unsigned char,
MHacheTools::PtrLessComparator<MHacheSkill>>;
#endif

65
include/mhache_tools.h Normal file
View File

@@ -0,0 +1,65 @@
#ifndef MHACHE_TOOLS_H
#define MHACHE_TOOLS_H
#include <functional>
#include <string>
#include <string_view>
#include <type_traits>
#include <vector>
namespace MHacheTools {
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);
}
};
class BytesArray {
private:
std::vector<char> _buffer;
public:
BytesArray() = default;
~BytesArray() = default;
template <class M>
void append(M object)
{
const char* c = nullptr;
if constexpr (std::is_pointer<M>::value)
c = reinterpret_cast<const char*>(object);
else
c = reinterpret_cast<const char*>(&object);
if (c) _buffer.insert(_buffer.end(), c, c + sizeof(object));
}
size_t digest() const
{
return std::hash<std::string_view>{}(std::string_view(_buffer.data(), _buffer.size()));
}
};
};
#endif

1004
scripts/skills.toml Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,37 @@
from multiprocessing.dummy import Array
from bs4 import BeautifulSoup
import requests
import tomli_w
response = requests.get("https://mhrise.kiranico.com/data/skills")
soup = BeautifulSoup(response.content, 'html.parser')
tbody = soup.tbody
output = { 'skill': {} }
for line in tbody.find_all('tr'):
columns = line.find_all('td')
skill_name = columns[0].find('p').string
skill_description = columns[1].find('p').string
skill_levels = []
smalls = columns[1].find_all('small')
for small in smalls:
if small.string:
# Remove the "Lvl x " prefix from level description.
skill_levels.append(small.string[5:])
output['skill'][skill_name] = {
'description': ''.join(skill_description),
'levels': skill_levels
}
print(skill_levels)
with open('skills.toml', 'wb') as tomlfile:
tomli_w.dump(output, tomlfile)

View File

@@ -3,9 +3,10 @@ find_package(OpenGL REQUIRED)
add_executable(
${PROJECT_NAME}
main.cpp
mhache_tools.cpp
mhache_color.cpp
mhache_skill.cpp
mhache_armor.cpp
mhache_armor_part.cpp
mhache_factory.cpp
mhache_window.cpp
)

80
src/mhache_armor_part.cpp Normal file
View File

@@ -0,0 +1,80 @@
#include <string_view>
#include <utility>
#include "mhache_armor_part.h"
#include "mhache_skill.h"
MHacheArmorPart::MHacheArmorPart(
std::string_view name, Label label, unsigned char rarity,
unsigned char defense, ElementalResistances&& resistances,
std::vector<unsigned char>&& slots, MappedSkillLevels&& skills
)
: _name(name)
, _label(label)
, _rarity(rarity)
, _minimum_defense(defense)
, _resistances(std::move(resistances))
, _slots(std::move(slots))
, _skills(std::move(skills))
{}
size_t
MHacheArmorPart::compute_hash() const
{
MHacheTools::BytesArray buffer;
buffer.append(_name);
buffer.append(_label);
buffer.append(_rarity);
buffer.append(_minimum_defense);
for (auto r: _resistances)
buffer.append(r);
for (auto s: _slots)
buffer.append(s);
for (auto pair: _skills) {
buffer.append(pair.first);
buffer.append(pair.second);
}
return buffer.digest();
}
bool
MHacheArmorPart::operator < (const MHacheArmorPart &other) const
{
return compute_hash() < other.compute_hash();
}
bool
MHacheArmorPart::operator==(const MHacheArmorPart &other) const
{
if (_name == other._name
&& _label == other._label
&& _rarity == other._rarity
&& _minimum_defense == other._minimum_defense
&& _resistances.size() == other._resistances.size()
&& _slots.size() == other._slots.size()
&& _skills.size() == other._skills.size())
{
for (size_t i = 0; i < _resistances.size(); ++i)
if (_resistances[i] != other._resistances[i])
return false;
for (size_t i = 0; i < _slots.size(); ++i)
if (_slots[i] != other._slots[i])
return false;
for (auto pair: _skills) {
auto it = other._skills.find(pair.first);
if (other._skills.end() == it) return false;
if (it->second != pair.second) return false;
}
return true;
}
return false;
}

View File

@@ -78,5 +78,5 @@ MHacheColor::get_color(const std::string& name)
MHacheColor*
MHacheColor::save_color(const std::string& name, MHacheColor&& color)
{
return &(_colors.insert_or_assign(name, std::forward<MHacheColor>(color)).first->second);
return &(_colors.insert_or_assign(name, std::move(color)).first->second);
}

View File

@@ -38,7 +38,7 @@ MHacheFactory::load_skills(const std::filesystem::path& tomlfile)
if (!parse_root_table(tomlfile, root) || root.empty())
return false;
if (!deserialize_table_node<toml::table>(root, "skills", skills))
if (!deserialize_table_node<toml::table>(root, "skill", skills))
return false;
}
@@ -50,11 +50,13 @@ MHacheFactory::load_skills(const std::filesystem::path& tomlfile)
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;
if (deserialize_table_node(skill, "color", skill_color))
color = MHacheColor::get_color(skill_color);
if (!color)
color = MHacheColor::get_color("white");
}
if (!color) return false;
std::string description;
if (!deserialize_table_node(skill, "description", description) || description.empty())
@@ -62,7 +64,7 @@ MHacheFactory::load_skills(const std::filesystem::path& tomlfile)
std::vector<std::string> levels;
if (!deserialize_table_node(skill, "levels", levels) || levels.empty())
return false;
// return false;
_skills.emplace(name, description, color, std::move(levels));
@@ -75,6 +77,7 @@ MHacheFactory::load_skills(const std::filesystem::path& tomlfile)
bool
MHacheFactory::load_armors(const std::filesystem::path& tomlfile)
{
/*
toml::table sets;
{
toml::table root;
@@ -152,130 +155,12 @@ MHacheFactory::load_armors(const std::filesystem::path& tomlfile)
return true;
});
return !_armors.empty();
return !_armors.empty();*/
return true;
}
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;
}
}
}

1
src/mhache_tools.cpp Normal file
View File

@@ -0,0 +1 @@
#include "mhache_tools.h"

View File

@@ -49,14 +49,13 @@ MHacheWindow::MHacheWindow(int width, int height)
if (std::filesystem::exists(filefont)) {
ImGui::GetIO().Fonts->AddFontFromFileTTF(filefont.u8string().c_str(), 16);
}
else
ImGui::GetIO().Fonts->AddFontDefault();
}
}
MHacheFactory& mhf = MHacheFactory::singleton();
mhf.load_skills("../../skills.toml");
mhf.load_skills("../../scripts/skills.toml");
mhf.load_armors("../../armors.toml");
}
@@ -126,11 +125,11 @@ MHacheWindow::build_widgets()
window_flags |= ImGuiWindowFlags_NoCollapse;
window_flags |= ImGuiWindowFlags_NoTitleBar;
const ImGuiViewport* main_viewport = ImGui::GetMainViewport();
if (main_viewport) {
ImGui::SetNextWindowPos(main_viewport->WorkPos);
ImGui::SetNextWindowSize(main_viewport->WorkSize);
ImGui::SetNextWindowSizeConstraints(main_viewport->WorkSize, main_viewport->WorkSize);
const ImGuiViewport* viewport = ImGui::GetMainViewport();
if (viewport) {
ImGui::SetNextWindowPos(viewport->WorkPos);
ImGui::SetNextWindowSize(viewport->WorkSize);
ImGui::SetNextWindowSizeConstraints(viewport->WorkSize, viewport->WorkSize);
}
ImGui::Begin(_title, nullptr, window_flags);
@@ -175,6 +174,7 @@ MHacheWindow::build_widgets()
}
}
/*
if (ImGui::CollapsingHeader("Armors")) {
const auto& armors = MHacheFactory::singleton().available_armors();
@@ -193,7 +193,7 @@ MHacheWindow::build_widgets()
}
MHacheFactory::singleton().find_builds(seeklevels);
}
}*/
//--
ImGui::End();