#include "dynamic_grid.hpp" #include "colored_output.hpp" #include #include //! \brief Helper function for all_positions() static auto all_positions_impl(int W, int H) { std::vector r; for(int y = 0; y < H; ++y) for(int x = 0; x < W; ++x) r.emplace_back(x, y); return r; } DynamicGrid::DynamicGrid(int width, int height, std::vector && data) : W(width), H(height), grid(std::move(data)) { assert(grid.size() == W*H); positions = all_positions_impl(W, H); } small_vector DynamicGrid::neighbors(Position const & p) const { small_vector ret; static Position nbs[] = { {-1, 0}, {1, 0}, {0, 1}, {0, -1} }; for(auto&& n : nbs){ auto q = Position{p.first + n.first, p.second + n.second}; if(valid(q)){ ret.push_back(q); } } return ret; } auto DynamicGrid::empty_column(int x){ for(auto y = 0; y < H; ++y){ if(!empty({x, y})){ return false; } } return true; } auto DynamicGrid::vcollapse(){ using namespace std; bool some_change = false; for(auto&& p : all_positions()){ if(empty(p)) continue; auto q = p; q.second--; if(!valid(q)) continue; if(!empty(q)) continue; swap(get(p), get(q)); some_change = true; } return some_change; } auto DynamicGrid::hcollapse(){ using namespace std; bool some_change = false; for(auto x = 0; x < W-1; ++x){ if(!empty_column(x)) continue; auto x2 = x+1; for(; x2 < W; ++x2){ if(!empty_column(x2)) break; } if(x2 == W) return some_change; for(auto y = 0; y < H; ++y){ swap(get({x, y}), get({x2, y})); } some_change = true; } return some_change; } void DynamicGrid::collapse(){ while(vcollapse()); while(hcollapse()); } void DynamicGrid::print(std::ostream& out) const { for(auto y = H; y; --y){ for(auto x = 0; x < W; ++x){ out << colored_block(get({x, y-1})) << (x == W-1 ? "\n" : ""); } } } size_t DynamicGrid::hash() const { std::string hs(W*H, '\0'); auto it = hs.begin(); for(auto&&p : all_positions()){ *it++ = static_cast(get(p)); } return std::hash()(hs); }