#include <iostream>

#include <random>

#include <vector>


class RandomCount

{

public:


    using rand_type = unsigned long long;


    RandomCount( rand_type lvalue, rand_type rvalue, rand_type count )

    {

        unsigned long long size = rvalue - lvalue + 1;

        std::random_device rd;

        std::mt19937_64 rnd(rd());

        std::vector<bool> _overlap_check(size);


        for (rand_type i = 0; i < count && i < size; i++)

        {

            do {

                rand_type real = rnd() % size + lvalue;

                if (!_overlap_check[real - lvalue])

                {

                    m_vec.push_back(real);

                    _overlap_check[real - lvalue] = true;

                    break;

                }

            } while (true);

        }


    }


    inline rand_type operator[](rand_type index) const

    {

        return m_vec[index];

    }


private:


    std::vector<rand_type> m_vec;


};


typedef enum MineSweeperType

{

    Number=0, /* 0 ~ 9 */

    Mine=10,

} MineSweeperType;


typedef enum MineSweeperHide

{

    Hide=0,

    Shown=1,

} MineSweeperHide;


class MineSweeperBase

{

    MineSweeperType* pannel;

    MineSweeperHide* hides;

    size_t row, column, mines;


public:


    MineSweeperBase(size_t row, size_t column, size_t mines)

        : row(row), column(column), mines(mines)

    {

        pannel = new MineSweeperType[row*column];

        hides = new MineSweeperHide[row*column];

        memset(pannel, 0, sizeof(MineSweeperType)*row*column);

        memset(hides, 0, sizeof(MineSweeperHide)*row*column);

        RandomCount rc(0, row*column-1, mines);

        for ( int i = 0; i < mines; i++ )

            pannel[rc[i]] = MineSweeperType::Mine;


        for ( int i = 0; i < row; i++ )

            for ( int j = 0; j < column; j++ )

                if ( pannel[i*column+j] == MineSweeperType::Mine )

                    for ( int k = i-1; k <= i+1; k++ )

                        for ( int l = j-1; l <= j+1; l++ )

                            if ( k >= 0 && k < row && l >= 0 && l < column )

                                if ( pannel[k*column+l] != MineSweeperType::Mine )

                                    pannel[k*column+l] = (MineSweeperType)(1 + pannel[k*column+l]);

    }


    bool expand(size_t r, size_t c)

    {

        if ( pannel[r*row+c] == MineSweeperType::Mine ) return false;

        expand_recur(r,c);

        return true;

    }


    void print_pannel(bool force = false)

    {

        for ( int i = 0; i < row; i++ )

        {

            for ( int j = 0; j < column; j++ )

            {

                if ( hides[i*column+j] == MineSweeperHide::Hide && !force ) 

                {std::cout << '@'; continue;}

                int p = pannel[(i*column)+j];

                if ( p == 0 ) std::cout << '.';

                else if ( p == 10 ) std::cout << '*';

                else std::cout << p;

            }

            std::cout << ' ';

        }

        std::cout << ' ';

    }


private:


    void expand_recur(size_t r, size_t c)

    {

        if ( hides[r*column+c] == MineSweeperHide::Shown ) return;

        if ( pannel[r*column+c] == MineSweeperType::Mine ) return;

        hides[r*column+c] = MineSweeperHide::Shown;

        if ( pannel[r*column+c] > 0 )

        {

            if ( r > 0 && pannel[(r-1)*column+c] == 0 && hides[(r-1)*column+c] == MineSweeperHide::Hide ) expand_recur(r-1,c);

            if ( r < row-1 && pannel[(r+1)*column+c] == 0 && hides[(r+1)*column+c] == MineSweeperHide::Hide ) expand_recur(r+1,c);

            if ( c > 0 && pannel[r*column+c-1] == 0 && hides[r*column+c-1] == MineSweeperHide::Hide ) expand_recur(r,c-1);

            if ( c < column-1 && pannel[r*column+c+1] == 0 && hides[r*column+c+1] == MineSweeperHide::Hide ) expand_recur(r,c+1);

            return;

        }

        if ( r > 0 ) expand_recur(r-1,c);

        if ( r < row-1 ) expand_recur(r+1, c);

        if ( c > 0 ) expand_recur(r,c-1);

        if ( c < column-1 ) expand_recur(r, c+1);

    }


};


int main()

{

    MineSweeperBase msb(20,60,150);

    msb.print_pannel(true);

    msb.expand(2,3);

    msb.print_pannel();

    return 0;

}