Adds a random generator. Fixes some warnings. Adds some comments
This commit is contained in:
parent
083141d346
commit
a137e31ba0
5 changed files with 60 additions and 45 deletions
|
@ -45,4 +45,12 @@ auto all_clusters(Field const & field){
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef Set
|
template <typename Field, typename Cluster>
|
||||||
|
auto make_empty(Field field, Cluster const & c){
|
||||||
|
using namespace std;
|
||||||
|
for(auto&& p : c){
|
||||||
|
field.get(p) = 0;
|
||||||
|
}
|
||||||
|
field.collapse();
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -23,7 +24,7 @@ struct small_vector{
|
||||||
|
|
||||||
// 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 <size_t W, size_t H, typename T>
|
template <int W, int H, typename T>
|
||||||
struct Field{
|
struct Field{
|
||||||
using Position = std::pair<int, int>;
|
using Position = std::pair<int, int>;
|
||||||
|
|
||||||
|
@ -31,15 +32,20 @@ struct Field{
|
||||||
std::copy(std::begin(g), std::end(g), std::begin(grid));
|
std::copy(std::begin(g), std::end(g), std::begin(grid));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! \brief Returns true if p represents a valid position
|
||||||
auto valid(Position const & p) const {
|
auto valid(Position const & p) const {
|
||||||
return p.first >= 0 && p.second >= 0
|
return p.first >= 0 && p.second >= 0
|
||||||
&& p.first < W && p.second < H;
|
&& p.first < W && p.second < H;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! \brief Returns true if p represents an empty cell
|
||||||
auto empty(Position const & p) const {
|
auto empty(Position const & p) const {
|
||||||
|
assert(valid(p));
|
||||||
return get(p) == 0;
|
return get(p) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! \brief Returns all neighbors of p
|
||||||
|
//! Only returns valid neighbors (and p does not need to be valid)
|
||||||
auto neighbors(Position const & p) const {
|
auto neighbors(Position const & p) const {
|
||||||
small_vector<Position, 4> ret;
|
small_vector<Position, 4> ret;
|
||||||
|
|
||||||
|
@ -57,24 +63,31 @@ struct Field{
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! \brief Let the block fall (all the way)
|
||||||
auto collapse(){
|
auto collapse(){
|
||||||
while(vcollapse());
|
while(vcollapse());
|
||||||
while(hcollapse());
|
while(hcollapse());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! \brief Returns an array of all valid positions
|
||||||
auto const & all_positions() const {
|
auto const & all_positions() const {
|
||||||
using Indices = std::make_index_sequence<W*H>;
|
using Indices = std::make_index_sequence<W*H>;
|
||||||
return all_positions_impl(Indices{});
|
return all_positions_impl(Indices{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! \brief Get (mutable) value at p
|
||||||
T& get(Position const & p){
|
T& get(Position const & p){
|
||||||
return grid[p.first + p.second*W];
|
assert(valid(p));
|
||||||
|
return grid[static_cast<size_t>(p.first + p.second*W)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! \brief Get value at p
|
||||||
T const& get(Position const & p) const {
|
T const& get(Position const & p) const {
|
||||||
return grid[p.first + p.second*W];
|
assert(valid(p));
|
||||||
|
return grid[static_cast<size_t>(p.first + p.second*W)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! \brief Pretty prints grid to out
|
||||||
void print(std::ostream& out) const {
|
void print(std::ostream& out) const {
|
||||||
for(auto y = H; y; --y){
|
for(auto y = H; y; --y){
|
||||||
for(auto x = 0; x < W; ++x){
|
for(auto x = 0; x < W; ++x){
|
||||||
|
@ -86,14 +99,16 @@ struct Field{
|
||||||
private:
|
private:
|
||||||
std::array<T, W*H> grid;
|
std::array<T, W*H> grid;
|
||||||
|
|
||||||
|
//! \brief Helper function for all_positions()
|
||||||
template<std::size_t... I>
|
template<std::size_t... I>
|
||||||
auto const & all_positions_impl(std::index_sequence<I...>) const {
|
auto const & all_positions_impl(std::index_sequence<I...>) const {
|
||||||
static const std::array<const Position, W*H> ret = {
|
static const std::array<const Position, W*H> ret = {{
|
||||||
Position{I % W, I / W}...
|
Position{I % W, I / W}...
|
||||||
};
|
}};
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! \brief Single vertical collapsing step
|
||||||
auto vcollapse(){
|
auto vcollapse(){
|
||||||
using namespace std;
|
using namespace std;
|
||||||
bool some_change = false;
|
bool some_change = false;
|
||||||
|
@ -112,6 +127,7 @@ private:
|
||||||
return some_change;
|
return some_change;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! \brief Single horizontal collapsing step
|
||||||
auto hcollapse(){
|
auto hcollapse(){
|
||||||
using namespace std;
|
using namespace std;
|
||||||
bool some_change = false;
|
bool some_change = false;
|
||||||
|
@ -132,7 +148,8 @@ private:
|
||||||
return some_change;
|
return some_change;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto empty_column(size_t x){
|
//! \brief Returns true if the whole column at x is empty
|
||||||
|
auto empty_column(int x){
|
||||||
for(auto y = 0; y < H; ++y){
|
for(auto y = 0; y < H; ++y){
|
||||||
if(!empty({x, y})){
|
if(!empty({x, y})){
|
||||||
return false;
|
return false;
|
||||||
|
@ -142,7 +159,8 @@ private:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <size_t W, size_t H, typename T>
|
//! \brief Helper function to create a field (T will be deducted)
|
||||||
|
template <int W, int H, typename T>
|
||||||
auto create_rectangular_field(std::initializer_list<T> grid){
|
auto create_rectangular_field(std::initializer_list<T> grid){
|
||||||
return Field<W, H, T>(grid);
|
return Field<W, H, T>(grid);
|
||||||
}
|
}
|
||||||
|
|
21
include/generator.hpp
Normal file
21
include/generator.hpp
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "field.hpp"
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
template <int W, int H, typename URNG, size_t... I>
|
||||||
|
auto random_field(URNG&& r, std::index_sequence<I...>){
|
||||||
|
std::uniform_int_distribution<int> dis(0, 4);
|
||||||
|
return create_rectangular_field<W, H>({
|
||||||
|
((void)I, dis(r))...
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int W, int H, typename URNG>
|
||||||
|
auto random_field(URNG&& r){
|
||||||
|
using Indices = std::make_index_sequence<W*H>;
|
||||||
|
return detail::random_field<W, H>(r, Indices{});
|
||||||
|
}
|
|
@ -2,16 +2,6 @@
|
||||||
|
|
||||||
#include "clusters.hpp"
|
#include "clusters.hpp"
|
||||||
|
|
||||||
template <typename Field, typename Container>
|
|
||||||
auto make_empty(Field field, Container const & c){
|
|
||||||
using namespace std;
|
|
||||||
for(auto&& p : c){
|
|
||||||
field.get(p) = 0;
|
|
||||||
}
|
|
||||||
field.collapse();
|
|
||||||
return field;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Field>
|
template <typename Field>
|
||||||
auto solve(Field const & field){
|
auto solve(Field const & field){
|
||||||
for(auto&& p : field.all_positions()){
|
for(auto&& p : field.all_positions()){
|
||||||
|
|
32
main.cpp
32
main.cpp
|
@ -2,8 +2,10 @@
|
||||||
#include "field.hpp"
|
#include "field.hpp"
|
||||||
#include "clusters.hpp"
|
#include "clusters.hpp"
|
||||||
#include "solver.hpp"
|
#include "solver.hpp"
|
||||||
|
#include "generator.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <random>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
@ -17,35 +19,11 @@ auto is_void(Field const & field){
|
||||||
|
|
||||||
int main(){
|
int main(){
|
||||||
using namespace std;
|
using namespace std;
|
||||||
// constexpr auto W = 10;
|
|
||||||
// constexpr auto H = 10;
|
|
||||||
|
|
||||||
// auto field = create_rectangular_field<W, H>({
|
std::random_device rd;
|
||||||
// 2, 1, 1, 1, 2, 1, 2, 4, 1, 2,
|
std::mt19937 gen(rd());
|
||||||
// 2, 2, 2, 1, 2, 2, 1, 1, 1, 2,
|
|
||||||
// 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
|
|
||||||
// 2, 1, 1, 4, 2, 4, 2, 1, 2, 1,
|
|
||||||
// 1, 1, 1, 3, 2, 2, 2, 3, 3, 4,
|
|
||||||
// 3, 2, 2, 1, 1, 1, 2, 2, 2, 2,
|
|
||||||
// 1, 1, 2, 1, 3, 1, 1, 4, 2, 3,
|
|
||||||
// 1, 1, 1, 1, 3, 1, 3, 2, 1, 2,
|
|
||||||
// 1, 1, 1, 1, 2, 4, 1, 3, 1, 2,
|
|
||||||
// 1, 1, 1, 1, 2, 2, 1, 1, 4, 9
|
|
||||||
// });
|
|
||||||
|
|
||||||
constexpr auto W = 9;
|
auto field = random_field<5, 5>(gen);
|
||||||
constexpr auto H = 9;
|
|
||||||
auto field = create_rectangular_field<W, H>({
|
|
||||||
2, 1, 1, 1, 2, 1, 2, 4, 1,
|
|
||||||
2, 2, 2, 1, 2, 2, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 2, 2,
|
|
||||||
2, 1, 1, 4, 2, 4, 2, 1, 2,
|
|
||||||
1, 1, 1, 3, 2, 2, 2, 3, 3,
|
|
||||||
3, 2, 2, 1, 1, 1, 2, 2, 2,
|
|
||||||
1, 1, 2, 1, 3, 1, 1, 4, 2,
|
|
||||||
1, 1, 1, 1, 3, 1, 3, 2, 1,
|
|
||||||
1, 1, 1, 1, 2, 4, 1, 3, 9
|
|
||||||
});
|
|
||||||
|
|
||||||
field.print(std::cout);
|
field.print(std::cout);
|
||||||
|
|
||||||
|
|
Reference in a new issue