1
Fork 0

Adds a random generator. Fixes some warnings. Adds some comments

This commit is contained in:
Joshua Moerman 2014-02-05 14:33:55 +01:00
parent 083141d346
commit a137e31ba0
5 changed files with 60 additions and 45 deletions

View file

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

View file

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

View file

@ -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()){

View file

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