yipo
8/20/2017 - 5:24 PM

Mine Sweeper

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