1
Fork 0

splits data from algorithms

This commit is contained in:
Joshua Moerman 2014-03-04 14:38:13 +01:00
parent 570bc18976
commit f1116a8bb7
8 changed files with 102 additions and 69 deletions

View file

@ -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
View 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
}
};

View file

@ -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>

View file

@ -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;
}
}; };

View file

@ -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;
} }

View file

@ -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);
} }

View file

@ -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";

View file

@ -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);
} }
} }