Adds boost program options. Finds *all* solutions.
This commit is contained in:
parent
64952b9700
commit
b61b6c04ff
5 changed files with 117 additions and 42 deletions
|
@ -4,10 +4,10 @@ cmake_minimum_required(VERSION 2.8)
|
|||
include_directories(SYSTEM "${PROJECT_SOURCE_DIR}/include/")
|
||||
add_definitions(-std=c++1y)
|
||||
|
||||
find_package(Boost REQUIRED COMPONENTS)
|
||||
find_package(Boost REQUIRED COMPONENTS program_options system)
|
||||
include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
|
||||
set(libs ${libs} ${Boost_LIBRARIES})
|
||||
|
||||
aux_source_directory(. SRC_LIST)
|
||||
add_executable(${PROJECT_NAME} ${SRC_LIST})
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} ${libs})
|
||||
|
|
|
@ -17,9 +17,9 @@ struct DynamicGrid{
|
|||
using Position = std::pair<int, int>;
|
||||
|
||||
template <typename Input>
|
||||
DynamicGrid(int W, int H, Input it)
|
||||
: W(W)
|
||||
, H(H)
|
||||
DynamicGrid(int width, int height, Input it)
|
||||
: W(width)
|
||||
, H(height)
|
||||
, grid(W*H, 0)
|
||||
{
|
||||
std::copy_n(it, W*H, std::begin(grid));
|
||||
|
|
14
include/rules.hpp
Normal file
14
include/rules.hpp
Normal 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;
|
||||
};
|
|
@ -1,35 +1,52 @@
|
|||
#pragma once
|
||||
|
||||
#include "clusters.hpp"
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
|
||||
template <typename Field>
|
||||
template <typename Grid>
|
||||
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>
|
||||
auto solve_impl(Field const & field, Solution<Field> & s){
|
||||
for(auto&& p : field.all_positions()){
|
||||
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 T>
|
||||
auto pop(std::vector<T> & v){
|
||||
v.erase(v.end()-1);
|
||||
}
|
||||
|
||||
template <typename Field>
|
||||
auto solve(Field const & field){
|
||||
Solution<Field> s;
|
||||
solve_impl(field, s);
|
||||
template <typename Grid, typename Rules>
|
||||
auto solve_impl(Grid const & grid, Rules const & rules, Solution<Grid> & s){
|
||||
// are we done yet?
|
||||
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;
|
||||
}
|
||||
|
|
70
main.cpp
70
main.cpp
|
@ -3,31 +3,75 @@
|
|||
#include "clusters.hpp"
|
||||
#include "solver.hpp"
|
||||
#include "generator.hpp"
|
||||
#include "rules.hpp"
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <algorithm>
|
||||
|
||||
int main(){
|
||||
using namespace std;
|
||||
int main(int argc, char** argv){
|
||||
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::mt19937 gen(rd());
|
||||
|
||||
int c = 0;
|
||||
while(true){
|
||||
std::cout << "puzzle " << ++c << std::endl;
|
||||
auto field = random_dynamic_grid(5, 2, 3, gen);
|
||||
BasicRules rules(explosion_size);
|
||||
|
||||
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);
|
||||
for(auto&& t : solution.taps){
|
||||
std::cout << "(" << t.first << ", " << t.second << ")\n";
|
||||
}
|
||||
if(!solution.taps.empty()){
|
||||
break;
|
||||
// std::cout << "\n= puzzle " << count << " =\n";
|
||||
// field.print(std::cout);
|
||||
|
||||
auto solution = solve(field, rules);
|
||||
if(!solution.solution_traces.empty()){
|
||||
++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";
|
||||
}
|
||||
|
|
Reference in a new issue