1
Fork 0

Adds boost program options. Finds *all* solutions.

This commit is contained in:
Joshua Moerman 2014-02-14 15:31:27 +01:00
parent 64952b9700
commit b61b6c04ff
5 changed files with 117 additions and 42 deletions

View file

@ -4,10 +4,10 @@ cmake_minimum_required(VERSION 2.8)
include_directories(SYSTEM "${PROJECT_SOURCE_DIR}/include/") include_directories(SYSTEM "${PROJECT_SOURCE_DIR}/include/")
add_definitions(-std=c++1y) add_definitions(-std=c++1y)
find_package(Boost REQUIRED COMPONENTS) find_package(Boost REQUIRED COMPONENTS program_options system)
include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
set(libs ${libs} ${Boost_LIBRARIES}) set(libs ${libs} ${Boost_LIBRARIES})
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
add_executable(${PROJECT_NAME} ${SRC_LIST}) add_executable(${PROJECT_NAME} ${SRC_LIST})
target_link_libraries(${PROJECT_NAME} ${libs})

View file

@ -17,9 +17,9 @@ struct DynamicGrid{
using Position = std::pair<int, int>; using Position = std::pair<int, int>;
template <typename Input> template <typename Input>
DynamicGrid(int W, int H, Input it) DynamicGrid(int width, int height, Input it)
: W(W) : W(width)
, H(H) , H(height)
, grid(W*H, 0) , grid(W*H, 0)
{ {
std::copy_n(it, W*H, std::begin(grid)); std::copy_n(it, W*H, std::begin(grid));

14
include/rules.hpp Normal file
View file

@ -0,0 +1,14 @@
#pragma once
struct BasicRules {
BasicRules(int minimal_cluster_size)
: min_size(minimal_cluster_size)
{}
auto min_cluster_size() const {
return min_size;
}
private:
int min_size;
};

View file

@ -1,35 +1,52 @@
#pragma once #pragma once
#include "clusters.hpp" #include "clusters.hpp"
#include <deque> #include <vector>
template <typename Field> template <typename Grid>
struct Solution { struct Solution {
std::deque<typename Field::Position> taps; using Trace = std::vector<typename Grid::Position>;
Trace current_trace;
std::vector<Trace> solution_traces;
}; };
template <typename Field> template <typename T>
auto solve_impl(Field const & field, Solution<Field> & s){ auto pop(std::vector<T> & v){
for(auto&& p : field.all_positions()){ v.erase(v.end()-1);
if(!field.empty(p)) goto analyse;
}
return true;
analyse:
for(auto&& c : all_clusters(field)){
if(c.size() < 3) continue;
auto new_field = make_empty(field, c);
if(solve_impl(new_field, s)) {
s.taps.push_front(*c.begin());
return true;
}
}
return false;
} }
template <typename Field> template <typename Grid, typename Rules>
auto solve(Field const & field){ auto solve_impl(Grid const & grid, Rules const & rules, Solution<Grid> & s){
Solution<Field> s; // are we done yet?
solve_impl(field, s); for(auto&& p : grid.all_positions()){
if(!grid.empty(p)) goto analyse;
}
// yes -> record the solution
s.solution_traces.push_back(s.current_trace);
return;
// no -> try all clusters
analyse:
for(auto&& c : all_clusters(grid)){
if(c.size() < rules.min_cluster_size()) continue;
// remove the cluster
s.current_trace.push_back(*c.begin());
auto new_grid = make_empty(grid, c);
// recurse
solve_impl(new_grid, rules, s);
// go on with next cluster
pop(s.current_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; return s;
} }

View file

@ -3,31 +3,75 @@
#include "clusters.hpp" #include "clusters.hpp"
#include "solver.hpp" #include "solver.hpp"
#include "generator.hpp" #include "generator.hpp"
#include "rules.hpp"
#include <boost/program_options.hpp>
#include <iostream> #include <iostream>
#include <random> #include <random>
#include <chrono> #include <chrono>
#include <thread> #include <thread>
#include <algorithm>
int main(){ int main(int argc, char** argv){
using namespace std; namespace po = boost::program_options;
int w = 5;
int h = 5;
int c = 3;
int explosion_size = 3;
// Describe program options
po::options_description opts;
opts.add_options()
("w", po::value(&w), "width of puzzles")
("h", po::value(&h), "height of puzzles")
("c", po::value(&c), "number of colors")
("explosion_size", po::value(&explosion_size), "minimum explosion size")
("help", po::bool_switch(), "show this help");
// Parse and store them in a vm
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, opts), vm);
po::notify(vm);
if(vm["help"].as<bool>()){
std::cout << "Puzzle Wuzzle Generator, version " << __DATE__ << std::endl;
std::cout << opts << std::endl;
return 0;
}
#define OUT(x) std::cout << #x << " = " << x << "\n"
OUT(w); OUT(h); OUT(c); OUT(explosion_size);
#undef OUT
std::random_device rd; std::random_device rd;
std::mt19937 gen(rd()); std::mt19937 gen(rd());
int c = 0; BasicRules rules(explosion_size);
while(true){
std::cout << "puzzle " << ++c << std::endl;
auto field = random_dynamic_grid(5, 2, 3, gen);
field.print(std::cout); int count = 50000;
int solvable = 0;
int unsolvable = 0;
while(--count){
auto field = random_dynamic_grid(w, h, c, gen);
auto solution = solve(field); // std::cout << "\n= puzzle " << count << " =\n";
for(auto&& t : solution.taps){ // field.print(std::cout);
std::cout << "(" << t.first << ", " << t.second << ")\n";
} auto solution = solve(field, rules);
if(!solution.taps.empty()){ if(!solution.solution_traces.empty()){
break; ++solvable;
// std::cout << solution.solution_traces.size() << " solutions\n";
// for(auto&& t : solution.solution_traces[0]){
// std::cout << "(" << t.first << ", " << t.second << ")\n";
// }
} else {
++unsolvable;
// std::cout << "no solutions\n";
} }
} }
std::cout << solvable << " solvable\n";
std::cout << unsolvable << " unsolvable\n";
} }