refactor usage of std::string to refer to states + improve initial mass positioning
This commit is contained in:
@ -190,7 +190,7 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
State(std::string state)
|
explicit 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,15 +278,30 @@ public:
|
|||||||
|
|
||||||
auto GetNextStates() const -> std::vector<State>;
|
auto GetNextStates() const -> std::vector<State>;
|
||||||
|
|
||||||
auto Closure() const
|
auto Closure() const -> std::pair<std::unordered_set<State>,
|
||||||
-> std::pair<std::unordered_set<std::string>,
|
std::vector<std::pair<State, State>>>;
|
||||||
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
|
||||||
|
|||||||
@ -5,7 +5,6 @@
|
|||||||
#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>
|
||||||
|
|
||||||
@ -87,6 +86,7 @@ public:
|
|||||||
|
|
||||||
class MassSpringSystem {
|
class MassSpringSystem {
|
||||||
private:
|
private:
|
||||||
|
// 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;
|
||||||
@ -95,8 +95,10 @@ private:
|
|||||||
int last_springs_count;
|
int last_springs_count;
|
||||||
|
|
||||||
public:
|
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(REPULSION_GRID_REFRESH) {};
|
||||||
@ -112,8 +114,7 @@ private:
|
|||||||
auto BuildGrid() -> void;
|
auto BuildGrid() -> void;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
auto AddMass(float mass, Vector3 position, bool fixed, const State &state)
|
auto AddMass(float mass, bool fixed, const State &state) -> void;
|
||||||
-> void;
|
|
||||||
|
|
||||||
auto GetMass(const State &state) -> Mass &;
|
auto GetMass(const State &state) -> Mass &;
|
||||||
|
|
||||||
|
|||||||
@ -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, Vector3Zero(), false, current_state);
|
mass_springs.AddMass(MASS, false, current_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
StateManager(const StateManager ©) = delete;
|
StateManager(const StateManager ©) = delete;
|
||||||
|
|||||||
@ -262,11 +262,10 @@ auto State::GetNextStates() const -> std::vector<State> {
|
|||||||
return new_states;
|
return new_states;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto State::Closure() const
|
auto State::Closure() const -> std::pair<std::unordered_set<State>,
|
||||||
-> std::pair<std::unordered_set<std::string>,
|
std::vector<std::pair<State, State>>> {
|
||||||
std::vector<std::pair<std::string, std::string>>> {
|
std::unordered_set<State> states;
|
||||||
std::unordered_set<std::string> states;
|
std::vector<std::pair<State, State>> links;
|
||||||
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);
|
||||||
@ -276,10 +275,10 @@ auto State::Closure() const
|
|||||||
remaining_states.erase(current);
|
remaining_states.erase(current);
|
||||||
|
|
||||||
std::vector<State> new_states = current.GetNextStates();
|
std::vector<State> new_states = current.GetNextStates();
|
||||||
for (State &s : new_states) {
|
for (const State &s : new_states) {
|
||||||
if (!states.contains(s.state)) {
|
if (!states.contains(s)) {
|
||||||
remaining_states.insert(s);
|
remaining_states.insert(s);
|
||||||
states.insert(s.state);
|
states.insert(s);
|
||||||
}
|
}
|
||||||
links.emplace_back(current.state, s.state);
|
links.emplace_back(current.state, s.state);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
#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(); }
|
||||||
@ -76,33 +77,39 @@ auto Spring::CalculateSpringForce() const -> void {
|
|||||||
massB.force = Vector3Add(massB.force, force_b);
|
massB.force = Vector3Add(massB.force, force_b);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto MassSpringSystem::AddMass(float mass, Vector3 position, bool fixed,
|
auto MassSpringSystem::AddMass(float mass, bool fixed, const State &state)
|
||||||
const State &state) -> void {
|
-> void {
|
||||||
if (!masses.contains(state.state)) {
|
if (!masses.contains(state)) {
|
||||||
masses.insert(std::make_pair(state.state, Mass(mass, position, fixed)));
|
masses.insert(
|
||||||
|
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.state);
|
return masses.at(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::string states;
|
std::pair<State, State> key = std::make_pair(massA, massB);
|
||||||
if (std::hash<std::string>{}(massA.state) <
|
if (!springs.contains(key)) {
|
||||||
std::hash<std::string>{}(massB.state)) {
|
Mass &a = GetMass(massA);
|
||||||
states = std::format("{}{}", massA.state, massB.state);
|
Mass &b = GetMass(massB);
|
||||||
} else {
|
|
||||||
states = std::format("{}{}", massB.state, massA.state);
|
Vector3 position = a.position;
|
||||||
|
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(
|
||||||
states, Spring(GetMass(massA), GetMass(massB), spring_constant,
|
key, Spring(a, b, spring_constant, dampening_constant, rest_length)));
|
||||||
dampening_constant, rest_length)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -90,7 +90,7 @@ auto OrbitCamera3D::Update(const Mass ¤t_mass) -> void {
|
|||||||
|
|
||||||
auto Renderer::UpdateCamera(const MassSpringSystem &masssprings,
|
auto Renderer::UpdateCamera(const MassSpringSystem &masssprings,
|
||||||
const State ¤t) -> void {
|
const State ¤t) -> void {
|
||||||
const Mass &c = masssprings.masses.at(current.state);
|
const Mass &c = masssprings.masses.at(current);
|
||||||
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.state) {
|
if (state == current) {
|
||||||
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.state).position,
|
DrawLine3D(mass.position, masssprings.masses.at(current).position,
|
||||||
PURPLE);
|
PURPLE);
|
||||||
}
|
}
|
||||||
} else if (masssprings.masses.size() <= DRAW_VERTICES_LIMIT) {
|
} else if (masssprings.masses.size() <= DRAW_VERTICES_LIMIT) {
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
#include "state.hpp"
|
#include "state.hpp"
|
||||||
|
#include "config.hpp"
|
||||||
#include "presets.hpp"
|
#include "presets.hpp"
|
||||||
|
|
||||||
#include <raymath.h>
|
#include <raymath.h>
|
||||||
@ -33,18 +34,10 @@ auto StateManager::NextPreset() -> void {
|
|||||||
auto StateManager::FillGraph() -> void {
|
auto StateManager::FillGraph() -> void {
|
||||||
ClearGraph();
|
ClearGraph();
|
||||||
|
|
||||||
std::pair<std::unordered_set<std::string>,
|
std::pair<std::unordered_set<State>, std::vector<std::pair<State, State>>>
|
||||||
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) {
|
||||||
// TODO: Insert masses in the spring loop and choose the position based on
|
mass_springs.AddMass(MASS, false, state);
|
||||||
// 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,
|
||||||
@ -64,15 +57,9 @@ auto StateManager::FillGraph() -> void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto StateManager::UpdateGraph() -> void {
|
auto StateManager::UpdateGraph() -> void {
|
||||||
if (previous_state != current_state.state) {
|
if (previous_state != current_state) {
|
||||||
mass_springs.AddMass(
|
mass_springs.AddMass(MASS, false, current_state);
|
||||||
MASS,
|
mass_springs.AddSpring(current_state, previous_state, SPRING_CONSTANT,
|
||||||
// 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);
|
||||||
@ -83,7 +70,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, Vector3Zero(), false, current_state);
|
mass_springs.AddMass(MASS, 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;
|
||||||
|
|||||||
Reference in New Issue
Block a user