Compare commits

..

1 Commits

7 changed files with 59 additions and 70 deletions

View File

@ -190,7 +190,7 @@ public:
#endif #endif
} }
explicit State(std::string state) State(std::string state)
: width(std::stoi(state.substr(1, 1))), : width(std::stoi(state.substr(1, 1))),
height(std::stoi(state.substr(3, 1))), height(std::stoi(state.substr(3, 1))),
restricted(state.substr(0, 1) == "R"), state(state) { restricted(state.substr(0, 1) == "R"), state(state) {
@ -278,30 +278,15 @@ public:
auto GetNextStates() const -> std::vector<State>; auto GetNextStates() const -> std::vector<State>;
auto Closure() const -> std::pair<std::unordered_set<State>, auto Closure() const
std::vector<std::pair<State, State>>>; -> std::pair<std::unordered_set<std::string>,
std::vector<std::pair<std::string, std::string>>>;
}; };
template <> struct std::hash<State> { template <> struct std::hash<State> {
std::size_t operator()(const State &s) const noexcept { return s.Hash(); } std::size_t operator()(const State &s) const noexcept { return s.Hash(); }
}; };
template <> struct std::hash<std::pair<State, State>> {
std::size_t operator()(const std::pair<State, State> &s) const noexcept {
auto h1 = std::hash<State>{}(s.first);
auto h2 = std::hash<State>{}(s.second);
return h1 + h2 + (h1 * h2);
}
};
template <> struct std::equal_to<std::pair<State, State>> {
bool operator()(const std::pair<State, State> &a,
const std::pair<State, State> &b) const noexcept {
return (a.first == b.first && a.second == b.second) ||
(a.first == b.second && a.second == b.first);
}
};
using WinCondition = std::function<bool(const State &)>; using WinCondition = std::function<bool(const State &)>;
#endif #endif

View File

@ -1,10 +1,10 @@
#ifndef __MASS_SPRINGS_HPP_ #ifndef __MASS_SPRINGS_HPP_
#define __MASS_SPRINGS_HPP_ #define __MASS_SPRINGS_HPP_
#include "config.hpp"
#include "klotski.hpp" #include "klotski.hpp"
#include <raylib.h> #include <raylib.h>
#include <raymath.h> #include <raymath.h>
#include <string>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
@ -85,8 +85,7 @@ public:
}; };
class MassSpringSystem { class MassSpringSystem {
private: public:
// TODO: Use references
std::vector<Mass *> mass_vec; std::vector<Mass *> mass_vec;
std::vector<int> indices; std::vector<int> indices;
std::vector<int64_t> cell_ids; std::vector<int64_t> cell_ids;
@ -94,14 +93,11 @@ private:
int last_masses_count; int last_masses_count;
int last_springs_count; int last_springs_count;
public: std::unordered_map<std::string, Mass> masses;
// This is the main ownership of all the states/masses/springs. std::unordered_map<std::string, Spring> springs;
// Everything is stored multiple times but idc.
std::unordered_map<State, Mass> masses;
std::unordered_map<std::pair<State, State>, Spring> springs;
public: public:
MassSpringSystem() : last_build(REPULSION_GRID_REFRESH) {}; MassSpringSystem() : last_build(1000) {};
MassSpringSystem(const MassSpringSystem &copy) = delete; MassSpringSystem(const MassSpringSystem &copy) = delete;
MassSpringSystem &operator=(const MassSpringSystem &copy) = delete; MassSpringSystem &operator=(const MassSpringSystem &copy) = delete;
@ -114,7 +110,8 @@ private:
auto BuildGrid() -> void; auto BuildGrid() -> void;
public: public:
auto AddMass(float mass, bool fixed, const State &state) -> void; auto AddMass(float mass, Vector3 position, bool fixed, const State &state)
-> void;
auto GetMass(const State &state) -> Mass &; auto GetMass(const State &state) -> Mass &;

View File

@ -25,7 +25,7 @@ public:
: mass_springs(mass_springs), current_preset(0), : mass_springs(mass_springs), current_preset(0),
current_state(generators[current_preset]()), current_state(generators[current_preset]()),
previous_state(current_state), edited(false) { previous_state(current_state), edited(false) {
mass_springs.AddMass(MASS, false, current_state); mass_springs.AddMass(MASS, Vector3Zero(), false, current_state);
} }
StateManager(const StateManager &copy) = delete; StateManager(const StateManager &copy) = delete;

View File

@ -262,10 +262,11 @@ auto State::GetNextStates() const -> std::vector<State> {
return new_states; return new_states;
} }
auto State::Closure() const -> std::pair<std::unordered_set<State>, auto State::Closure() const
std::vector<std::pair<State, State>>> { -> std::pair<std::unordered_set<std::string>,
std::unordered_set<State> states; std::vector<std::pair<std::string, std::string>>> {
std::vector<std::pair<State, State>> links; std::unordered_set<std::string> states;
std::vector<std::pair<std::string, std::string>> links;
std::unordered_set<State> remaining_states; std::unordered_set<State> remaining_states;
remaining_states.insert(*this); remaining_states.insert(*this);
@ -275,10 +276,10 @@ auto State::Closure() const -> std::pair<std::unordered_set<State>,
remaining_states.erase(current); remaining_states.erase(current);
std::vector<State> new_states = current.GetNextStates(); std::vector<State> new_states = current.GetNextStates();
for (const State &s : new_states) { for (State &s : new_states) {
if (!states.contains(s)) { if (!states.contains(s.state)) {
remaining_states.insert(s); remaining_states.insert(s);
states.insert(s); states.insert(s.state);
} }
links.emplace_back(current.state, s.state); links.emplace_back(current.state, s.state);
} }

View File

@ -1,11 +1,10 @@
#include "mass_springs.hpp" #include "mass_springs.hpp"
#include "config.hpp" #include "config.hpp"
#include <format>
#include <numeric> #include <numeric>
#include <raylib.h>
#include <raymath.h> #include <raymath.h>
#include <unordered_map> #include <unordered_map>
#include <utility>
#include <vector> #include <vector>
auto Mass::ClearForce() -> void { force = Vector3Zero(); } auto Mass::ClearForce() -> void { force = Vector3Zero(); }
@ -77,39 +76,33 @@ auto Spring::CalculateSpringForce() const -> void {
massB.force = Vector3Add(massB.force, force_b); massB.force = Vector3Add(massB.force, force_b);
} }
auto MassSpringSystem::AddMass(float mass, bool fixed, const State &state) auto MassSpringSystem::AddMass(float mass, Vector3 position, bool fixed,
-> void { const State &state) -> void {
if (!masses.contains(state)) { if (!masses.contains(state.state)) {
masses.insert( masses.insert(std::make_pair(state.state, Mass(mass, position, fixed)));
std::make_pair(state.state, Mass(mass, Vector3Zero(), fixed)));
} }
} }
auto MassSpringSystem::GetMass(const State &state) -> Mass & { auto MassSpringSystem::GetMass(const State &state) -> Mass & {
return masses.at(state); return masses.at(state.state);
} }
auto MassSpringSystem::AddSpring(const State &massA, const State &massB, auto MassSpringSystem::AddSpring(const State &massA, const State &massB,
float spring_constant, float spring_constant,
float dampening_constant, float rest_length) float dampening_constant, float rest_length)
-> void { -> void {
std::pair<State, State> key = std::make_pair(massA, massB); std::string states;
if (!springs.contains(key)) { if (std::hash<std::string>{}(massA.state) <
Mass &a = GetMass(massA); std::hash<std::string>{}(massB.state)) {
Mass &b = GetMass(massB); states = std::format("{}{}", massA.state, massB.state);
} else {
Vector3 position = a.position; states = std::format("{}{}", massB.state, massA.state);
Vector3 offset = Vector3(static_cast<float>(GetRandomValue(-100, 100)),
static_cast<float>(GetRandomValue(-100, 100)),
static_cast<float>(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( springs.insert(std::make_pair(
key, Spring(a, b, spring_constant, dampening_constant, rest_length))); states, Spring(GetMass(massA), GetMass(massB), spring_constant,
dampening_constant, rest_length)));
} }
} }

View File

@ -90,7 +90,7 @@ auto OrbitCamera3D::Update(const Mass &current_mass) -> void {
auto Renderer::UpdateCamera(const MassSpringSystem &masssprings, auto Renderer::UpdateCamera(const MassSpringSystem &masssprings,
const State &current) -> void { const State &current) -> void {
const Mass &c = masssprings.masses.at(current); const Mass &c = masssprings.masses.at(current.state);
camera.Update(c); camera.Update(c);
} }
@ -130,7 +130,7 @@ auto Renderer::DrawMassSprings(const MassSpringSystem &masssprings,
// Draw masses (high performance impact) // Draw masses (high performance impact)
for (const auto &[state, mass] : masssprings.masses) { for (const auto &[state, mass] : masssprings.masses) {
if (state == current) { if (state == current.state) {
DrawCube(mass.position, 4 * VERTEX_SIZE, 4 * VERTEX_SIZE, 4 * VERTEX_SIZE, DrawCube(mass.position, 4 * VERTEX_SIZE, 4 * VERTEX_SIZE, 4 * VERTEX_SIZE,
RED); RED);
} else if (winning_states.contains(state)) { } else if (winning_states.contains(state)) {
@ -140,7 +140,7 @@ auto Renderer::DrawMassSprings(const MassSpringSystem &masssprings,
4 * VERTEX_SIZE, BLUE); 4 * VERTEX_SIZE, BLUE);
} }
if (connect_solutions) { if (connect_solutions) {
DrawLine3D(mass.position, masssprings.masses.at(current).position, DrawLine3D(mass.position, masssprings.masses.at(current.state).position,
PURPLE); PURPLE);
} }
} else if (masssprings.masses.size() <= DRAW_VERTICES_LIMIT) { } else if (masssprings.masses.size() <= DRAW_VERTICES_LIMIT) {

View File

@ -1,5 +1,4 @@
#include "state.hpp" #include "state.hpp"
#include "config.hpp"
#include "presets.hpp" #include "presets.hpp"
#include <raymath.h> #include <raymath.h>
@ -34,10 +33,18 @@ auto StateManager::NextPreset() -> void {
auto StateManager::FillGraph() -> void { auto StateManager::FillGraph() -> void {
ClearGraph(); ClearGraph();
std::pair<std::unordered_set<State>, std::vector<std::pair<State, State>>> std::pair<std::unordered_set<std::string>,
std::vector<std::pair<std::string, std::string>>>
closure = current_state.Closure(); closure = current_state.Closure();
for (const auto &state : closure.first) { for (const auto &state : closure.first) {
mass_springs.AddMass(MASS, false, state); // TODO: Insert masses in the spring loop and choose the position based on
// the existing mass
Vector3 pos =
Vector3(static_cast<float>(GetRandomValue(-10000, 10000)) / 1000.0,
static_cast<float>(GetRandomValue(-10000, 10000)) / 1000.0,
static_cast<float>(GetRandomValue(-10000, 10000)) / 1000.0);
mass_springs.AddMass(MASS, pos, false, state);
} }
for (const auto &[from, to] : closure.second) { for (const auto &[from, to] : closure.second) {
mass_springs.AddSpring(from, to, SPRING_CONSTANT, DAMPENING_CONSTANT, mass_springs.AddSpring(from, to, SPRING_CONSTANT, DAMPENING_CONSTANT,
@ -57,9 +64,15 @@ auto StateManager::FillGraph() -> void {
} }
auto StateManager::UpdateGraph() -> void { auto StateManager::UpdateGraph() -> void {
if (previous_state != current_state) { if (previous_state != current_state.state) {
mass_springs.AddMass(MASS, false, current_state); mass_springs.AddMass(
mass_springs.AddSpring(current_state, previous_state, SPRING_CONSTANT, MASS,
// TODO: Add beside previous_state
Vector3(static_cast<float>(GetRandomValue(-1000, 1000)) / 1000.0,
static_cast<float>(GetRandomValue(-1000, 1000)) / 1000.0,
static_cast<float>(GetRandomValue(-1000, 1000)) / 1000.0),
false, current_state.state);
mass_springs.AddSpring(current_state.state, previous_state, SPRING_CONSTANT,
DAMPENING_CONSTANT, REST_LENGTH); DAMPENING_CONSTANT, REST_LENGTH);
if (win_conditions[current_preset](current_state)) { if (win_conditions[current_preset](current_state)) {
winning_states.insert(current_state); winning_states.insert(current_state);
@ -70,7 +83,7 @@ auto StateManager::UpdateGraph() -> void {
auto StateManager::ClearGraph() -> void { auto StateManager::ClearGraph() -> void {
winning_states.clear(); winning_states.clear();
mass_springs.Clear(); mass_springs.Clear();
mass_springs.AddMass(MASS, false, current_state); mass_springs.AddMass(MASS, Vector3Zero(), false, current_state);
// The previous_state is no longer in the graph // The previous_state is no longer in the graph
previous_state = current_state; previous_state = current_state;