#pragma once #include "utilities.hpp" #include #include #include #include #include #include // Position {0,0} is bottom left. // Position {W-1, H-1} is top right. // template struct DynamicGrid{ using Position = std::pair; DynamicGrid(int width, int height, std::vector && data); //! \brief Returns an array of all valid positions (may be empty) auto const & all_positions() const{ return positions; } //! \brief Returns true if p represents a valid position auto valid(Position const & p) const { return p.first >= 0 && p.second >= 0 && p.first < W && p.second < H; } //! \brief Get (mutable) value at p auto & get(Position const & p){ assert(valid(p)); return grid[static_cast(p.first + p.second*W)]; } //! \brief Get value at p auto const& get(Position const & p) const { assert(valid(p)); return grid[static_cast(p.first + p.second*W)]; } //! \brief Returns true if p represents an empty cell auto empty(Position const & p) const { assert(valid(p)); return get(p) == 0; } //! \brief Return true if the whole grid is empty auto empty() const { for(auto&& p : all_positions()){ if(!empty(p)) return false; } return true; } //! \brief Returns all neighbors of p //! Only returns valid neighbors (and p does not need to be valid) small_vector neighbors(Position const & p) const; //! \brief Let the block fall (all the way) void collapse(); //! \brief Pretty prints grid to out void print(std::ostream& out) const; private: int W; int H; std::vector grid; std::vector positions; //! \brief Single vertical collapsing step auto vcollapse(); //! \brief Single horizontal collapsing step auto hcollapse(); //! \brief Returns true if the whole column at x is empty auto empty_column(int x); }; template auto random_dynamic_grid(int W, int H, int C, URNG&& r){ std::uniform_int_distribution dis(1, C); std::vector v(W*H); std::generate_n(std::begin(v), W*H, [&]{ return dis(r); }); return DynamicGrid(W, H, std::move(v)); }