#include <iostream>
#include <vector>
#include <algorithm>
#include <random>
#include <numeric>
using namespace std;
void generateBingoCard(int rows = 3) {
const int cols = 9;
const int numsPerRow = 5;
mt19937 engine(random_device{}()); // Shared random engine
// 1. Initialize Column Pools
vector<vector<int>> colPool(cols);
for (int j = 0; j < cols; j++) {
int start = (j * 10) + 1;
int end = (j == 8) ? 90 : (j + 1) * 10;
for (int v = start; v <= end; v++) colPool[j].push_back(v);
shuffle(colPool[j].begin(), colPool[j].end(), engine);
}
vector<vector<int>> card(rows, vector<int>(cols, 0));
vector<int> colCount(cols, 0);
vector<int> rowCount(rows, 0);
// 2. Pass 1: Every column must have at least one number
for (int j = 0; j < cols; j++) {
int r = j % rows;
card[r][j] = colPool[j].back();
colPool[j].pop_back();
colCount[j]++;
rowCount[r]++;
}
// 3. Pass 2: Fill remaining slots row-by-row (Unbiased)
for (int i = 0; i < rows; i++) {
// Create a list of column indices [0, 1, ..., 8] using a for loop
vector<int> colOrder(cols);
for (int k = 0; k < cols; k++) {
colOrder[k] = k;
}
// Shuffle the order we look at columns for THIS specific row
shuffle(colOrder.begin(), colOrder.end(), engine);
for (int j : colOrder) {
// Stop if the row already has 5 numbers
if (rowCount[i] >= numsPerRow) break;
// Only fill if cell is empty
if (card[i][j] == 0) {
card[i][j] = colPool[j].back();
colPool[j].pop_back();
colCount[j]++;
rowCount[i]++;
}
}
}
// 4. In-place Vertical Sort (preserves 0/nil positions)
for (int j = 0; j < cols; j++) {
for (int pass = 0; pass < rows - 1; pass++) {
for (int i = 0; i < rows - 1; i++) {
if (card[i][j] > 0 && card[i+1][j] > 0 && card[i][j] > card[i+1][j]) {
swap(card[i][j], card[i+1][j]);
}
}
}
}
// Output formatted like the sample
for (int i = 0; i < rows; i++) {
cout << "[";
for (int j = 0; j < cols; j++) {
printf("%2d%s", card[i][j], (j == cols - 1 ? "" : ", "));
}
cout << "]" << (i == rows - 1 ? "," : "") << endl;
}
}
int main() {
generateBingoCard(3);
return 0;
}