#include <iostream>
#include <iomanip>
#include <vector>
#include <random>
#include <functional>


using row_type = std::vector<unsigned>;
using grid_type = std::vector<row_type>;

std::function<unsigned()> get_rng(unsigned min, unsigned max)
{
    std::mt19937 generator((std::random_device())());
    return [=] () mutable 
    { 
    	return std::uniform_int_distribution<unsigned>(min, max)(generator); 
	};
}


// note that max_value is treated as a bit of a suggestion.
// modify rnd_non_multiple if that isn't satisfactory.
grid_type generate_grid(unsigned target, unsigned n_target_values, 
						unsigned width, unsigned height, unsigned max_value)
{
    grid_type grid(height, row_type(width));

    // convenience functions:
    auto rnd_width = get_rng(0, width - 1);
    auto rnd_height = get_rng(0, height - 1);
    
    auto factor = get_rng(1, max_value / target);
    auto rnd_multiple = [target, &factor] { return factor() * target; };

    auto lt_target = get_rng(1, target - 1);    // less than target
    auto rnd_non_multiple = [&rnd_multiple, &lt_target] 
    	{ return rnd_multiple() + lt_target(); };

    {
        // place multiples randomly
        unsigned targets_assigned = 0;
        while (targets_assigned < n_target_values)
        {
            unsigned y = rnd_height();
            unsigned x = rnd_width();

            if (!grid[y][x])
            {
                grid[y][x] = rnd_multiple();
                ++targets_assigned;
            }
        }
    }

    // fill the rest of the grid with non-multiples:
    for (auto& row : grid)
        for (auto & cell : row)
            if (!cell) cell = rnd_non_multiple();

    return grid;
}

void display(const grid_type& grid)
{
    for (auto& row : grid)
    {
        for (auto& cell : row)
            std::cout << std::setw(3) << cell;

        std::cout << '\n';
    }
}

void display(const std::vector<unsigned>& v)
{
    for (auto& e : v)
        std::cout << e << ' ';
    std::cout << '\n';
}

std::vector<unsigned> extract_multiples(const grid_type& grid, unsigned val)
{
    std::vector<unsigned> mults;

    for (auto& row : grid)
        for (auto& cell : row)
            if (cell % val == 0) mults.push_back(cell);

    return mults;
}

int main()
{
	unsigned target = 7 ;
    auto grid = generate_grid(target, 10, 5, 5, target*9);
    display(grid);
    std::cout << "\nMultiples are:\n\t";
    display(extract_multiples(grid, target));
}