I wanted to create a 9x9 matrix with 10 ones in it, which is filled randomly in C/C++.
For example, it should look like this:
array[[ 0, 1, 0, 0, 0, 1, 0, 0, 0, ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, ]
[ 0, 1, 0, 0, 0, 0, 0, 0, 0, ]
[ 0, 0, 0, 0, 0, 0, 0, 1, 0, ]
[ 0, 1, 0, 0, 0, 1, 0, 0, 0, ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, ]
[ 0, 0, 0, 0, 0, 0, 0, 0, 1, ]
[ 0, 0, 1, 0, 0, 0, 0, 0, 0, ]
[ 1, 0, 0, 0, 0, 1, 0, 0, 0, ]]
There are different ways. You could fill the 10 first positions in an array with 1
s and then call std::shuffle
to put those in random positons. You could also create a list of available positions and randomly pick 10 out of that list.
Commented example of the former:
#include <algorithm> // shuffle
#include <array> // array
#include <iostream> //
#include <random> // mt19937
int main() {
constexpr unsigned side_size = 9;
// a seeded pseudo number generator
std::mt19937 prng(std::random_device{}());
std::array<std::array<int, side_size>, side_size> arr_to_fill;
unsigned ones = 10; // the number of 1's we want
// create an array with all available positions number from 0-
std::array<unsigned, side_size * side_size> positions{};
// put 1's in the first `ones` positions:
std::fill_n(positions.begin(), ones, 1);
// shuffle the array so the 1's are put in random positions
std::shuffle(positions.begin(), positions.end(), prng);
// fill the array:
for (size_t idx = 0; idx < positions.size(); ++idx) {
arr_to_fill[idx / side_size][idx % side_size] = positions[idx];
}
// print result:
for (auto& inner : arr_to_fill) {
for (auto v : inner) std::cout << ' ' << v;
std::cout << '\n';
}
}
(Note that it's tempting to just cast the 2d array into a plain 1d array and fill that with 1's and shuffle it directly but then you are in undefined behavior territory)
Commented example of the latter:
#include <array> // array
#include <iostream> //
#include <numeric> // iota
#include <random> // mt19937, uniform_int_distribution
int main() {
constexpr unsigned side_size = 9;
// a seeded pseudo number generator
std::mt19937 prng(std::random_device{}());
// all zeroes:
std::array<std::array<int, side_size>, side_size> arr_to_fill{};
unsigned ones = 10; // the number of 1's we want
// create an array with all available positions number from 0-
std::array<unsigned, side_size * side_size> positions;
std::iota(positions.begin(), positions.end(), 0); // [0, side_size^2)
for (unsigned i = 0; i < ones; ++i) {
unsigned last = positions.size() - 1 - i; // last unpicked pos
// distribution of random numbers from 0 to last (inclusive)
std::uniform_int_distribution dist(0u, last);
unsigned idx = dist(prng); // get random index ...
unsigned pos = positions[idx]; // ... to pick a position
positions[idx] = positions[last]; // copy last unpicked position
// put a 1 in the chosen positions place:
arr_to_fill[pos / side_size][pos % side_size] = 1;
}
// print result:
for (auto& inner : arr_to_fill) {
for (auto v : inner) std::cout << ' ' << v;
std::cout << '\n';
}
}
If you can use external libraries, you could also simplify this by using boost::multi::array
.
Example provided by alfC:
#include <multi/array.hpp> // boost::multi::array
#include <algorithm> // shuffle
#include <iostream> //
#include <random> // mt19937
int main() {
std::mt19937 prng(std::random_device{}());
// create a 9x9 array, initialized with 0's:
boost::multi::array<int, 2> A({9, 9}, 0);
// fill the first 10 elements:
std::fill_n(A.elements().begin(), 10, 1);
// shuffle the array so the 1's end up in random positions:
std::shuffle(A.elements().begin(), A.elements().end(), prng);
// print result:
for (auto const& row : A) {
for (auto const& v : row) {
std::cout << ' ' << v;
}
std::cout << '\n';
}
}