108 lines
2.1 KiB
C++
108 lines
2.1 KiB
C++
#include "dynamic_grid.hpp"
|
|
#include "colored_output.hpp"
|
|
|
|
#include <functional>
|
|
#include <iostream>
|
|
|
|
//! \brief Helper function for all_positions()
|
|
static auto all_positions_impl(int W, int H) {
|
|
std::vector<DynamicGrid::Position> 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<int> && data)
|
|
: W(width), H(height), grid(std::move(data)) {
|
|
assert(grid.size() == W*H);
|
|
positions = all_positions_impl(W, H);
|
|
}
|
|
|
|
small_vector<DynamicGrid::Position, 4>
|
|
DynamicGrid::neighbors(Position const & p) const {
|
|
small_vector<Position, 4> 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<char>(get(p));
|
|
}
|
|
|
|
return std::hash<std::string>()(hs);
|
|
}
|