diff --git a/include/klotski.hpp b/include/klotski.hpp index 5017751..3e54937 100644 --- a/include/klotski.hpp +++ b/include/klotski.hpp @@ -190,7 +190,7 @@ public: #endif } - State(std::string state) + explicit State(std::string state) : width(std::stoi(state.substr(1, 1))), height(std::stoi(state.substr(3, 1))), restricted(state.substr(0, 1) == "R"), state(state) { @@ -278,15 +278,30 @@ public: auto GetNextStates() const -> std::vector; - auto Closure() const - -> std::pair, - std::vector>>; + auto Closure() const -> std::pair, + std::vector>>; }; template <> struct std::hash { std::size_t operator()(const State &s) const noexcept { return s.Hash(); } }; +template <> struct std::hash> { + std::size_t operator()(const std::pair &s) const noexcept { + auto h1 = std::hash{}(s.first); + auto h2 = std::hash{}(s.second); + return h1 + h2 + (h1 * h2); + } +}; + +template <> struct std::equal_to> { + bool operator()(const std::pair &a, + const std::pair &b) const noexcept { + return (a.first == b.first && a.second == b.second) || + (a.first == b.second && a.second == b.first); + } +}; + using WinCondition = std::function; #endif diff --git a/include/mass_springs.hpp b/include/mass_springs.hpp index 964adab..33e5873 100644 --- a/include/mass_springs.hpp +++ b/include/mass_springs.hpp @@ -5,7 +5,6 @@ #include "klotski.hpp" #include #include -#include #include #include @@ -87,6 +86,7 @@ public: class MassSpringSystem { private: + // TODO: Use references std::vector mass_vec; std::vector indices; std::vector cell_ids; @@ -95,8 +95,10 @@ private: int last_springs_count; public: - std::unordered_map masses; - std::unordered_map springs; + // This is the main ownership of all the states/masses/springs. + // Everything is stored multiple times but idc. + std::unordered_map masses; + std::unordered_map, Spring> springs; public: MassSpringSystem() : last_build(REPULSION_GRID_REFRESH) {}; @@ -112,8 +114,7 @@ private: auto BuildGrid() -> void; public: - auto AddMass(float mass, Vector3 position, bool fixed, const State &state) - -> void; + auto AddMass(float mass, bool fixed, const State &state) -> void; auto GetMass(const State &state) -> Mass &; diff --git a/include/state.hpp b/include/state.hpp index fdd1358..dc7e3e9 100644 --- a/include/state.hpp +++ b/include/state.hpp @@ -25,7 +25,7 @@ public: : mass_springs(mass_springs), current_preset(0), current_state(generators[current_preset]()), previous_state(current_state), edited(false) { - mass_springs.AddMass(MASS, Vector3Zero(), false, current_state); + mass_springs.AddMass(MASS, false, current_state); } StateManager(const StateManager ©) = delete; diff --git a/src/klotski.cpp b/src/klotski.cpp index bd0e722..58d2497 100644 --- a/src/klotski.cpp +++ b/src/klotski.cpp @@ -262,11 +262,10 @@ auto State::GetNextStates() const -> std::vector { return new_states; } -auto State::Closure() const - -> std::pair, - std::vector>> { - std::unordered_set states; - std::vector> links; +auto State::Closure() const -> std::pair, + std::vector>> { + std::unordered_set states; + std::vector> links; std::unordered_set remaining_states; remaining_states.insert(*this); @@ -276,10 +275,10 @@ auto State::Closure() const remaining_states.erase(current); std::vector new_states = current.GetNextStates(); - for (State &s : new_states) { - if (!states.contains(s.state)) { + for (const State &s : new_states) { + if (!states.contains(s)) { remaining_states.insert(s); - states.insert(s.state); + states.insert(s); } links.emplace_back(current.state, s.state); } diff --git a/src/mass_springs.cpp b/src/mass_springs.cpp index 017321c..4aaf670 100644 --- a/src/mass_springs.cpp +++ b/src/mass_springs.cpp @@ -1,10 +1,11 @@ #include "mass_springs.hpp" #include "config.hpp" -#include #include +#include #include #include +#include #include auto Mass::ClearForce() -> void { force = Vector3Zero(); } @@ -76,33 +77,39 @@ auto Spring::CalculateSpringForce() const -> void { massB.force = Vector3Add(massB.force, force_b); } -auto MassSpringSystem::AddMass(float mass, Vector3 position, bool fixed, - const State &state) -> void { - if (!masses.contains(state.state)) { - masses.insert(std::make_pair(state.state, Mass(mass, position, fixed))); +auto MassSpringSystem::AddMass(float mass, bool fixed, const State &state) + -> void { + if (!masses.contains(state)) { + masses.insert( + std::make_pair(state.state, Mass(mass, Vector3Zero(), fixed))); } } auto MassSpringSystem::GetMass(const State &state) -> Mass & { - return masses.at(state.state); + return masses.at(state); } auto MassSpringSystem::AddSpring(const State &massA, const State &massB, float spring_constant, float dampening_constant, float rest_length) -> void { - std::string states; - if (std::hash{}(massA.state) < - std::hash{}(massB.state)) { - states = std::format("{}{}", massA.state, massB.state); - } else { - states = std::format("{}{}", massB.state, massA.state); - } + std::pair key = std::make_pair(massA, massB); + if (!springs.contains(key)) { + Mass &a = GetMass(massA); + Mass &b = GetMass(massB); + + Vector3 position = a.position; + Vector3 offset = Vector3(static_cast(GetRandomValue(-100, 100)), + static_cast(GetRandomValue(-100, 100)), + static_cast(GetRandomValue(-100, 100))); + offset = Vector3Scale(Vector3Normalize(offset), REST_LENGTH); + + if (b.position == Vector3Zero()) { + b.position = Vector3Add(position, offset); + } - if (!springs.contains(states)) { springs.insert(std::make_pair( - states, Spring(GetMass(massA), GetMass(massB), spring_constant, - dampening_constant, rest_length))); + key, Spring(a, b, spring_constant, dampening_constant, rest_length))); } } diff --git a/src/renderer.cpp b/src/renderer.cpp index 5fc3e27..7af2911 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -90,7 +90,7 @@ auto OrbitCamera3D::Update(const Mass ¤t_mass) -> void { auto Renderer::UpdateCamera(const MassSpringSystem &masssprings, const State ¤t) -> void { - const Mass &c = masssprings.masses.at(current.state); + const Mass &c = masssprings.masses.at(current); camera.Update(c); } @@ -130,7 +130,7 @@ auto Renderer::DrawMassSprings(const MassSpringSystem &masssprings, // Draw masses (high performance impact) for (const auto &[state, mass] : masssprings.masses) { - if (state == current.state) { + if (state == current) { DrawCube(mass.position, 4 * VERTEX_SIZE, 4 * VERTEX_SIZE, 4 * VERTEX_SIZE, RED); } else if (winning_states.contains(state)) { @@ -140,7 +140,7 @@ auto Renderer::DrawMassSprings(const MassSpringSystem &masssprings, 4 * VERTEX_SIZE, BLUE); } if (connect_solutions) { - DrawLine3D(mass.position, masssprings.masses.at(current.state).position, + DrawLine3D(mass.position, masssprings.masses.at(current).position, PURPLE); } } else if (masssprings.masses.size() <= DRAW_VERTICES_LIMIT) { diff --git a/src/state.cpp b/src/state.cpp index 7a151b6..11f8467 100644 --- a/src/state.cpp +++ b/src/state.cpp @@ -1,4 +1,5 @@ #include "state.hpp" +#include "config.hpp" #include "presets.hpp" #include @@ -33,18 +34,10 @@ auto StateManager::NextPreset() -> void { auto StateManager::FillGraph() -> void { ClearGraph(); - std::pair, - std::vector>> + std::pair, std::vector>> closure = current_state.Closure(); for (const auto &state : closure.first) { - // TODO: Insert masses in the spring loop and choose the position based on - // the existing mass - Vector3 pos = - Vector3(static_cast(GetRandomValue(-10000, 10000)) / 1000.0, - static_cast(GetRandomValue(-10000, 10000)) / 1000.0, - static_cast(GetRandomValue(-10000, 10000)) / 1000.0); - - mass_springs.AddMass(MASS, pos, false, state); + mass_springs.AddMass(MASS, false, state); } for (const auto &[from, to] : closure.second) { mass_springs.AddSpring(from, to, SPRING_CONSTANT, DAMPENING_CONSTANT, @@ -64,15 +57,9 @@ auto StateManager::FillGraph() -> void { } auto StateManager::UpdateGraph() -> void { - if (previous_state != current_state.state) { - mass_springs.AddMass( - MASS, - // TODO: Add beside previous_state - Vector3(static_cast(GetRandomValue(-1000, 1000)) / 1000.0, - static_cast(GetRandomValue(-1000, 1000)) / 1000.0, - static_cast(GetRandomValue(-1000, 1000)) / 1000.0), - false, current_state.state); - mass_springs.AddSpring(current_state.state, previous_state, SPRING_CONSTANT, + if (previous_state != current_state) { + mass_springs.AddMass(MASS, false, current_state); + mass_springs.AddSpring(current_state, previous_state, SPRING_CONSTANT, DAMPENING_CONSTANT, REST_LENGTH); if (win_conditions[current_preset](current_state)) { winning_states.insert(current_state); @@ -83,7 +70,7 @@ auto StateManager::UpdateGraph() -> void { auto StateManager::ClearGraph() -> void { winning_states.clear(); mass_springs.Clear(); - mass_springs.AddMass(MASS, Vector3Zero(), false, current_state); + mass_springs.AddMass(MASS, false, current_state); // The previous_state is no longer in the graph previous_state = current_state;