splits data from algorithms
This commit is contained in:
parent
570bc18976
commit
f1116a8bb7
8 changed files with 102 additions and 69 deletions
|
@ -1,29 +1,15 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "data.hpp"
|
||||||
#include "dynamic_grid.hpp"
|
#include "dynamic_grid.hpp"
|
||||||
#include "solver.hpp"
|
#include "solver.hpp"
|
||||||
#include "rules.hpp"
|
#include "rules.hpp"
|
||||||
|
|
||||||
#include <boost/archive/text_oarchive.hpp>
|
#include <boost/archive/text_oarchive.hpp>
|
||||||
#include <boost/archive/text_iarchive.hpp>
|
#include <boost/archive/text_iarchive.hpp>
|
||||||
#include <boost/serialization/serialization.hpp>
|
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
template <typename Grid>
|
|
||||||
struct AnalyzedGrid {
|
|
||||||
Grid grid;
|
|
||||||
Solution<Grid> analysis;
|
|
||||||
BasicRules rules;
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class boost::serialization::access;
|
|
||||||
template<class Archive>
|
|
||||||
void serialize(Archive & ar, const unsigned int /*version*/){
|
|
||||||
ar & grid & analysis.solution_traces;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
inline auto grid_from_file(std::string file_path){
|
inline auto grid_from_file(std::string file_path){
|
||||||
std::ifstream file(file_path);
|
std::ifstream file(file_path);
|
||||||
boost::archive::text_iarchive ar(file);
|
boost::archive::text_iarchive ar(file);
|
||||||
|
|
67
include/data.hpp
Normal file
67
include/data.hpp
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <boost/serialization/vector.hpp>
|
||||||
|
#include <boost/serialization/utility.hpp>
|
||||||
|
#include <boost/serialization/serialization.hpp>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
struct BasicRulesBase {
|
||||||
|
unsigned int min_size;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class boost::serialization::access;
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive & ar, const unsigned int /*version*/){
|
||||||
|
ar & min_size;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Grid>
|
||||||
|
struct Solutions {
|
||||||
|
using Trace = std::vector<typename Grid::Position>;
|
||||||
|
std::vector<Trace> traces;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class boost::serialization::access;
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive & ar, const unsigned int /*version*/){
|
||||||
|
ar & traces;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Grid>
|
||||||
|
struct AnalyzedGrid {
|
||||||
|
Grid grid;
|
||||||
|
Solutions<Grid> solutions;
|
||||||
|
BasicRulesBase rules;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class boost::serialization::access;
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive & ar, const unsigned int /*version*/){
|
||||||
|
ar & grid & solutions & rules;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DynamicGridBase {
|
||||||
|
using Position = std::pair<int, int>;
|
||||||
|
|
||||||
|
int W;
|
||||||
|
int H;
|
||||||
|
std::vector<int> grid;
|
||||||
|
std::vector<Position> positions;
|
||||||
|
|
||||||
|
DynamicGridBase() = default;
|
||||||
|
DynamicGridBase(int width, int height, std::vector<int> && data)
|
||||||
|
: W(width), H(height), grid(std::move(data))
|
||||||
|
{}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class boost::serialization::access;
|
||||||
|
template<class Archive>
|
||||||
|
void serialize(Archive & ar, const unsigned int /*version*/){
|
||||||
|
ar & W & H & grid & positions;
|
||||||
|
// archiving positions is redundant (I'm being lazy here)
|
||||||
|
// consider make_nvp for readable json
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,10 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "utilities.hpp"
|
#include "utilities.hpp"
|
||||||
|
#include "data.hpp"
|
||||||
#include <boost/serialization/vector.hpp>
|
|
||||||
#include <boost/serialization/utility.hpp>
|
|
||||||
#include <boost/serialization/serialization.hpp>
|
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
@ -16,8 +13,8 @@
|
||||||
// Position {0,0} is bottom left.
|
// Position {0,0} is bottom left.
|
||||||
// Position {W-1, H-1} is top right.
|
// Position {W-1, H-1} is top right.
|
||||||
// template <typename T>
|
// template <typename T>
|
||||||
struct DynamicGrid{
|
struct DynamicGrid : public DynamicGridBase {
|
||||||
using Position = std::pair<int, int>;
|
using Position = DynamicGridBase::Position;
|
||||||
|
|
||||||
DynamicGrid(int width, int height, std::vector<int> && data);
|
DynamicGrid(int width, int height, std::vector<int> && data);
|
||||||
|
|
||||||
|
@ -74,11 +71,6 @@ struct DynamicGrid{
|
||||||
size_t hash() const;
|
size_t hash() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int W;
|
|
||||||
int H;
|
|
||||||
std::vector<int> grid;
|
|
||||||
std::vector<Position> positions;
|
|
||||||
|
|
||||||
//! \brief Single vertical collapsing step
|
//! \brief Single vertical collapsing step
|
||||||
auto vcollapse();
|
auto vcollapse();
|
||||||
|
|
||||||
|
@ -87,16 +79,6 @@ private:
|
||||||
|
|
||||||
//! \brief Returns true if the whole column at x is empty
|
//! \brief Returns true if the whole column at x is empty
|
||||||
auto empty_column(int x);
|
auto empty_column(int x);
|
||||||
|
|
||||||
friend class boost::serialization::access;
|
|
||||||
|
|
||||||
//! \brief Serializes the grid
|
|
||||||
template<class Archive>
|
|
||||||
void serialize(Archive & ar, const unsigned int /*version*/){
|
|
||||||
ar & W & H & grid & positions;
|
|
||||||
// archiving positions is redundant (I'm being lazy here)
|
|
||||||
// consider make_nvp for readable json
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename URNG>
|
template <typename URNG>
|
||||||
|
|
|
@ -1,9 +1,15 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
struct BasicRules {
|
#include "data.hpp"
|
||||||
|
|
||||||
|
struct BasicRules : public BasicRulesBase {
|
||||||
BasicRules() = default;
|
BasicRules() = default;
|
||||||
BasicRules(unsigned int minimal_cluster_size)
|
BasicRules(unsigned int minimal_cluster_size)
|
||||||
: min_size(minimal_cluster_size)
|
: BasicRulesBase{minimal_cluster_size}
|
||||||
|
{}
|
||||||
|
|
||||||
|
BasicRules(BasicRulesBase base)
|
||||||
|
: BasicRulesBase(base)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
auto min_cluster_size() const {
|
auto min_cluster_size() const {
|
||||||
|
@ -13,13 +19,4 @@ struct BasicRules {
|
||||||
auto same_cluster(int x, int y) const {
|
auto same_cluster(int x, int y) const {
|
||||||
return x == y;
|
return x == y;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
unsigned int min_size;
|
|
||||||
|
|
||||||
friend class boost::serialization::access;
|
|
||||||
template<class Archive>
|
|
||||||
void serialize(Archive & ar, const unsigned int /*version*/){
|
|
||||||
ar & min_size;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "data.hpp"
|
||||||
#include "clusters.hpp"
|
#include "clusters.hpp"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
template <typename Grid>
|
template <typename Grid>
|
||||||
struct Solution {
|
struct State {
|
||||||
using Trace = std::vector<typename Grid::Position>;
|
using Trace = typename Solutions<Grid>::Trace;
|
||||||
Trace current_trace;
|
Trace trace; // current trace being considered
|
||||||
std::vector<Trace> solution_traces;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -16,10 +16,10 @@ auto pop(std::vector<T> & v){
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Grid, typename Rules>
|
template <typename Grid, typename Rules>
|
||||||
auto solve_impl(Grid const & grid, Rules const & rules, Solution<Grid> & s){
|
auto solve_impl(Grid const & grid, Rules const & rules, State<Grid> & state, Solutions<Grid> & solutions){
|
||||||
if(grid.empty()){
|
if(grid.empty()){
|
||||||
// solved path
|
// solved path
|
||||||
s.solution_traces.push_back(s.current_trace);
|
solutions.traces.push_back(state.trace);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,22 +31,23 @@ auto solve_impl(Grid const & grid, Rules const & rules, Solution<Grid> & s){
|
||||||
|
|
||||||
for(auto&& c : clusters){
|
for(auto&& c : clusters){
|
||||||
// remove the cluster
|
// remove the cluster
|
||||||
s.current_trace.push_back(*c.begin());
|
state.trace.push_back(*c.begin());
|
||||||
auto new_grid = make_empty(grid, c);
|
auto new_grid = make_empty(grid, c);
|
||||||
|
|
||||||
// recurse
|
// recurse
|
||||||
solve_impl(new_grid, rules, s);
|
solve_impl(new_grid, rules, state, solutions);
|
||||||
|
|
||||||
// go on with next cluster
|
// go on with next cluster
|
||||||
pop(s.current_trace);
|
pop(state.trace);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Grid, typename Rules>
|
template <typename Grid, typename Rules>
|
||||||
auto solve(Grid const & grid, Rules const & rules){
|
auto solve(Grid const & grid, Rules const & rules){
|
||||||
Solution<Grid> s;
|
Solutions<Grid> solutions;
|
||||||
s.current_trace.reserve(10);
|
State<Grid> state;
|
||||||
solve_impl(grid, rules, s);
|
state.trace.reserve(10);
|
||||||
return s;
|
solve_impl(grid, rules, state, solutions);
|
||||||
|
return solutions;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ static auto all_positions_impl(int W, int H) {
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicGrid::DynamicGrid(int width, int height, std::vector<int> && data)
|
DynamicGrid::DynamicGrid(int width, int height, std::vector<int> && data)
|
||||||
: W(width), H(height), grid(std::move(data)) {
|
: DynamicGridBase(width, height, std::move(data)) {
|
||||||
assert(grid.size() == W*H);
|
assert(grid.size() == W*H);
|
||||||
positions = all_positions_impl(W, H);
|
positions = all_positions_impl(W, H);
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,25 +51,25 @@ int main(int argc, char** argv){
|
||||||
unsigned int unsolvable = 0;
|
unsigned int unsolvable = 0;
|
||||||
while(n--){
|
while(n--){
|
||||||
auto field = random_dynamic_grid(w, h, c, gen);
|
auto field = random_dynamic_grid(w, h, c, gen);
|
||||||
auto solution = solve(field, rules);
|
auto solutions = solve(field, rules);
|
||||||
|
|
||||||
if(!solution.solution_traces.empty()){
|
if(!solutions.traces.empty()){
|
||||||
++solvable;
|
++solvable;
|
||||||
} else {
|
} else {
|
||||||
++unsolvable;
|
++unsolvable;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string s = solution.solution_traces.empty() ? "u" : "s";
|
std::string s = solutions.traces.empty() ? "u" : "s";
|
||||||
std::string filename = "levels/" + std::to_string(w) + "_" + std::to_string(h) + "_" + std::to_string(c) + "_" + s + "_" + std::to_string(field.hash()) + ".lvl";
|
std::string filename = "levels/" + std::to_string(w) + "_" + std::to_string(h) + "_" + std::to_string(c) + "_" + s + "_" + std::to_string(field.hash()) + ".lvl";
|
||||||
|
|
||||||
if(verbose){
|
if(verbose){
|
||||||
std::cout << "= Puzzle " << n << " =\n";
|
std::cout << "= Puzzle " << n << " =\n";
|
||||||
field.print(std::cout);
|
field.print(std::cout);
|
||||||
std::cout << solution.solution_traces.size() << " solutions\n";
|
std::cout << solutions.traces.size() << " solutions\n";
|
||||||
std::cout << filename << "\n\n";
|
std::cout << filename << "\n\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
grid_to_file({std::move(field), std::move(solution), rules}, filename);
|
grid_to_file({std::move(field), std::move(solutions), rules}, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << solvable << " solvable (= " << 100 * solvable / double(solvable + unsolvable) << "%)\n";
|
std::cout << solvable << " solvable (= " << 100 * solvable / double(solvable + unsolvable) << "%)\n";
|
||||||
|
|
|
@ -32,10 +32,10 @@ int main(int argc, char** argv){
|
||||||
std::cout << "= The puzzle =\n";
|
std::cout << "= The puzzle =\n";
|
||||||
auto level = grid_from_file(vm["file"].as<std::string>());
|
auto level = grid_from_file(vm["file"].as<std::string>());
|
||||||
level.grid.print(std::cout);
|
level.grid.print(std::cout);
|
||||||
std::cout << "has " << level.analysis.solution_traces.size() << " solutions\n\n";
|
std::cout << "has " << level.solutions.traces.size() << " solutions\n\n";
|
||||||
|
|
||||||
int count = 1;
|
int count = 1;
|
||||||
for(auto && solution : level.analysis.solution_traces){
|
for(auto && solution : level.solutions.traces){
|
||||||
std::cout << "= Solution " << count++ << " =\n";
|
std::cout << "= Solution " << count++ << " =\n";
|
||||||
|
|
||||||
auto grid = level.grid;
|
auto grid = level.grid;
|
||||||
|
@ -43,7 +43,7 @@ int main(int argc, char** argv){
|
||||||
|
|
||||||
for(auto && tap : solution){
|
for(auto && tap : solution){
|
||||||
std::cout << "Tapping on " << tap.first << ", " << tap.second << " => \n";
|
std::cout << "Tapping on " << tap.first << ", " << tap.second << " => \n";
|
||||||
grid = make_empty(grid, cluster_at(grid, level.rules, tap));
|
grid = make_empty(grid, cluster_at(grid, BasicRules{level.rules}, tap));
|
||||||
grid.print(std::cout);
|
grid.print(std::cout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue