Mine Sweeper
#include <functional>
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
template <typename T>
class matrix
{
public:
matrix(size_t size, const T &value = T()) : m_buf(size*size, value), m_size(size)
{
}
size_t size() const
{
return m_size;
}
const T &at(size_t i, size_t j) const
{
return m_buf.at(i*m_size + j);
}
T &at(size_t i, size_t j)
{
const T &ref = static_cast<const matrix<T>*>(this)->at(i, j);
return const_cast<T&>(ref);
}
void for_each(function<void(const T &element, size_t i, size_t j)> func) const
{
for (size_t i = 0; i < m_size; i++)
{
for (size_t j = 0; j < m_size; j++)
{
func(at(i, j), i, j);
}
}
}
void for_each(function<void(const T &element)> func) const
{
for_each([&](const T &element, size_t i, size_t j)
{
func(element);
});
}
void for_each(function<void(T &element, size_t i, size_t j)> func)
{
static_cast<const matrix<T>*>(this)->for_each([&](const T &element, size_t i, size_t j)
{
func(const_cast<T&>(element), i, j);
});
}
void for_each(function<void(T &element)> func)
{
static_cast<const matrix<T>*>(this)->for_each([&](const T &element, size_t i, size_t j)
{
func(const_cast<T&>(element));
});
}
string to_string() const
{
ostringstream oss;
for (size_t i = 0; i < m_size; i++)
{
for (size_t j = 0; j < m_size; j++)
{
oss << at(i, j);
}
oss << endl;
}
return oss.str();
}
friend ostream &operator <<(ostream &os, const matrix<T> &m)
{
os << m.to_string();
return os;
}
private:
vector<T> m_buf;
size_t m_size;
};
template <typename T>
istream &read_matrix(istream &is, matrix<T> &m, const map<char, T> &mapping)
{
m.for_each([&](T &element)
{
while (is.peek() != EOF && isspace(is.peek())) is.get();
if (is.peek() == EOF) throw;
element = mapping.at(is.get());
});
return is;
}
typedef char BOOL; // To bypass the vector<bool> specialization.
matrix<size_t> gen_heat_map(const matrix<BOOL> &m, size_t radius)
{
matrix<size_t> temp(m.size() + radius, 0);
m.for_each([&](const BOOL &element, size_t i, size_t j)
{
temp.at(i, j) = element ? 1 : 0;
});
temp.for_each([&](size_t &element, size_t i, size_t j)
{
if (j > 0) element += temp.at(i, j - 1);
});
temp.for_each([&](size_t &element, size_t i, size_t j)
{
if (i > 0) element += temp.at(i - 1, j);
});
matrix<size_t> result(m.size());
const size_t diameter = 2 * radius + 1;
result.for_each([&](size_t &element, size_t i, size_t j)
{
i += radius, j += radius;
element = temp.at(i, j);
if (i >= diameter && j >= diameter) element += temp.at(i - diameter, j - diameter);
if (i >= diameter) element -= temp.at(i - diameter, j);
if (j >= diameter) element -= temp.at(i, j - diameter);
});
return result;
}
void test_case()
{
size_t n;
cin >> n;
matrix<BOOL> has_mine(n);
read_matrix(cin, has_mine,
{
{ '*', true },
{ '.', false },
});
matrix<BOOL> mask(n);
read_matrix(cin, mask,
{
{ 'x', true },
{ '.', false },
});
matrix<size_t> heat_map = gen_heat_map(has_mine, 1);
matrix<char> display(n, '.');
bool any_mine_touched = false;
mask.for_each([&](const BOOL &element, size_t i, size_t j)
{
if (element)
{
display.at(i, j) = '0' + heat_map.at(i, j);
if (has_mine.at(i, j)) any_mine_touched = true;
}
});
if (any_mine_touched)
{
has_mine.for_each([&](const BOOL &element, size_t i, size_t j)
{
if (element) display.at(i, j) = '*';
});
}
cout << display;
}
int main()
{
size_t n;
cin >> n;
while (n--)
{
test_case();
if (n > 0) cout << endl;
}
return 0;
}