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
|
||||
|
||||
#include "data.hpp"
|
||||
#include "dynamic_grid.hpp"
|
||||
#include "solver.hpp"
|
||||
#include "rules.hpp"
|
||||
|
||||
#include <boost/archive/text_oarchive.hpp>
|
||||
#include <boost/archive/text_iarchive.hpp>
|
||||
#include <boost/serialization/serialization.hpp>
|
||||
|
||||
#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){
|
||||
std::ifstream file(file_path);
|
||||
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
|
||||
|
||||
#include "utilities.hpp"
|
||||
|
||||
#include <boost/serialization/vector.hpp>
|
||||
#include <boost/serialization/utility.hpp>
|
||||
#include <boost/serialization/serialization.hpp>
|
||||
#include "data.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
|
@ -16,8 +13,8 @@
|
|||
// Position {0,0} is bottom left.
|
||||
// Position {W-1, H-1} is top right.
|
||||
// template <typename T>
|
||||
struct DynamicGrid{
|
||||
using Position = std::pair<int, int>;
|
||||
struct DynamicGrid : public DynamicGridBase {
|
||||
using Position = DynamicGridBase::Position;
|
||||
|
||||
DynamicGrid(int width, int height, std::vector<int> && data);
|
||||
|
||||
|
@ -74,11 +71,6 @@ struct DynamicGrid{
|
|||
size_t hash() const;
|
||||
|
||||
private:
|
||||
int W;
|
||||
int H;
|
||||
std::vector<int> grid;
|
||||
std::vector<Position> positions;
|
||||
|
||||
//! \brief Single vertical collapsing step
|
||||
auto vcollapse();
|
||||
|
||||
|
@ -87,16 +79,6 @@ private:
|
|||
|
||||
//! \brief Returns true if the whole column at x is empty
|
||||
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>
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
struct BasicRules {
|
||||
#include "data.hpp"
|
||||
|
||||
struct BasicRules : public BasicRulesBase {
|
||||
BasicRules() = default;
|
||||
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 {
|
||||
|
@ -13,13 +19,4 @@ struct BasicRules {
|
|||
auto same_cluster(int x, int y) const {
|
||||
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
|
||||
|
||||
#include "data.hpp"
|
||||
#include "clusters.hpp"
|
||||
#include <vector>
|
||||
|
||||
template <typename Grid>
|
||||
struct Solution {
|
||||
using Trace = std::vector<typename Grid::Position>;
|
||||
Trace current_trace;
|
||||
std::vector<Trace> solution_traces;
|
||||
struct State {
|
||||
using Trace = typename Solutions<Grid>::Trace;
|
||||
Trace trace; // current trace being considered
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
@ -16,10 +16,10 @@ auto pop(std::vector<T> & v){
|
|||
}
|
||||
|
||||
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()){
|
||||
// solved path
|
||||
s.solution_traces.push_back(s.current_trace);
|
||||
solutions.traces.push_back(state.trace);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -31,22 +31,23 @@ auto solve_impl(Grid const & grid, Rules const & rules, Solution<Grid> & s){
|
|||
|
||||
for(auto&& c : clusters){
|
||||
// remove the cluster
|
||||
s.current_trace.push_back(*c.begin());
|
||||
state.trace.push_back(*c.begin());
|
||||
auto new_grid = make_empty(grid, c);
|
||||
|
||||
// recurse
|
||||
solve_impl(new_grid, rules, s);
|
||||
solve_impl(new_grid, rules, state, solutions);
|
||||
|
||||
// go on with next cluster
|
||||
pop(s.current_trace);
|
||||
pop(state.trace);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
template <typename Grid, typename Rules>
|
||||
auto solve(Grid const & grid, Rules const & rules){
|
||||
Solution<Grid> s;
|
||||
s.current_trace.reserve(10);
|
||||
solve_impl(grid, rules, s);
|
||||
return s;
|
||||
Solutions<Grid> solutions;
|
||||
State<Grid> state;
|
||||
state.trace.reserve(10);
|
||||
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)
|
||||
: W(width), H(height), grid(std::move(data)) {
|
||||
: DynamicGridBase(width, height, std::move(data)) {
|
||||
assert(grid.size() == W*H);
|
||||
positions = all_positions_impl(W, H);
|
||||
}
|
||||
|
|
|
@ -51,25 +51,25 @@ int main(int argc, char** argv){
|
|||
unsigned int unsolvable = 0;
|
||||
while(n--){
|
||||
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;
|
||||
} else {
|
||||
++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";
|
||||
|
||||
if(verbose){
|
||||
std::cout << "= Puzzle " << n << " =\n";
|
||||
field.print(std::cout);
|
||||
std::cout << solution.solution_traces.size() << " solutions\n";
|
||||
std::cout << solutions.traces.size() << " solutions\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";
|
||||
|
|
|
@ -32,10 +32,10 @@ int main(int argc, char** argv){
|
|||
std::cout << "= The puzzle =\n";
|
||||
auto level = grid_from_file(vm["file"].as<std::string>());
|
||||
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;
|
||||
for(auto && solution : level.analysis.solution_traces){
|
||||
for(auto && solution : level.solutions.traces){
|
||||
std::cout << "= Solution " << count++ << " =\n";
|
||||
|
||||
auto grid = level.grid;
|
||||
|
@ -43,7 +43,7 @@ int main(int argc, char** argv){
|
|||
|
||||
for(auto && tap : solution){
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
Reference in a new issue