ObzLib container
obz::weighted_set
A collection of unique values where every value has a positive integer weight for random selection.
Random, But Designed
A match-3 board does not have to be random in a flat, uniform way. When matched pieces disappear, new pieces fall in from invisible slots above each column. Those slots can use weights to shape what the player is likely to see next.
For example, one column might be tuned to produce more red pieces. Red is not guaranteed; it is simply more likely. Over many drops, that column starts to feel different from the others.
enum class gem_colour {
red,
blue,
green
};
obz::weighted_set<gem_colour> left_column;
left_column.insert(gem_colour::red, 3);
left_column.insert(gem_colour::blue, 1);
left_column.insert(gem_colour::green, 1);
std::mt19937 generator(level_seed);
const auto next_gem = left_column.random(generator);
A Level Design Tool
Different columns can have different weighted sets. A designer can quietly make one side of the board favour red pieces, another favour blue pieces, and a later level make rare pieces appear less often. The board still feels alive because the sequence is not scripted.
obz::weighted_set<gem_colour> middle_column;
middle_column.insert(gem_colour::red, 1);
middle_column.insert(gem_colour::blue, 3);
middle_column.insert(gem_colour::green, 1);
obz::weighted_set<gem_colour> right_column;
right_column.insert(gem_colour::red, 1);
right_column.insert(gem_colour::blue, 1);
right_column.insert(gem_colour::green, 3);
That is the interesting space for this class: halfway between pure randomness and hard-coded behaviour. The game code can talk in design language: red should be more common here.
The Small Rule It Owns
The container keeps the bookkeeping out of the game logic. Values are unique, weights must be positive, and the total weight stays correct as entries are inserted, removed, or changed.
bool insert(T value, weight_type weight);
bool set_weight(const T& value, weight_type weight);
template <typename UniformRandomBitGenerator>
const T& random(UniformRandomBitGenerator& generator) const;
Randomness is supplied by the caller, which also makes the behaviour easy to test. Use the same seeded generator and the same weighted sets, and a level can be reproduced exactly when you need it.