#include <iostream>
#include <string>
#include <array>
#include <random>
#define onlyAtEnd(a) typename std::enable_if<sizeof...(a) == 0 > ::type
template<int a, int b>
class Entry
{
public:
static constexpr int VAL = a;
static constexpr int PROB = b;
};
template<typename... EntryTypes>
class NumChooser
{
private:
const int SUM;
static constexpr int NUM_VALS = sizeof...(EntryTypes);
std::mt19937 gen;
std::uniform_int_distribution<> dist;
public:
static constexpr int size()
{
return NUM_VALS;
}
template<typename T, typename... args>
constexpr int calcSum()
{
return T::PROB + calcSum < args...>();
}
template <typename... Ts, typename = onlyAtEnd(Ts) >
constexpr int calcSum()
{
return 0;
}
NumChooser() : SUM(calcSum < EntryTypes... >()), gen(std::random_device{}()), dist(1, SUM) { }
template<typename T, typename... args>
constexpr int find(int left, int previous = 0)
{
return left < 0 ? previous : find < args... >(left - T::PROB, T::VAL);
}
template <typename... Ts, typename = onlyAtEnd(Ts) >
constexpr int find(int left, int previous)
{
return previous;
}
int choose()
{
return find < EntryTypes... >(dist(gen));
}
};
NumChooser <
Entry<0, 10>,
Entry<1, 50>,
Entry<2, 80>,
Entry<3, 01>
> chooser;
int main()
{
std::array<int, chooser.size() > frequency{};
const int NUM_TRIALS = 10000;
for (int i = 0; i < NUM_TRIALS; ++i)
{
int val = chooser.choose();
frequency[val]++;
}
std::cout << "Frequency:" << std::endl;
for (int i : frequency)
std::cout << (float) i / NUM_TRIALS << " ";
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8c3RyaW5nPgojaW5jbHVkZSA8YXJyYXk+CiNpbmNsdWRlIDxyYW5kb20+CgojZGVmaW5lIG9ubHlBdEVuZChhKSB0eXBlbmFtZSBzdGQ6OmVuYWJsZV9pZjxzaXplb2YuLi4oYSkgPT0gMCA+IDo6dHlwZQoKdGVtcGxhdGU8aW50IGEsIGludCBiPgpjbGFzcyBFbnRyeQp7CnB1YmxpYzoKCXN0YXRpYyBjb25zdGV4cHIgaW50IFZBTCA9IGE7CglzdGF0aWMgY29uc3RleHByIGludCBQUk9CID0gYjsKfTsKCnRlbXBsYXRlPHR5cGVuYW1lLi4uIEVudHJ5VHlwZXM+CmNsYXNzIE51bUNob29zZXIKewpwcml2YXRlOgoJY29uc3QgaW50IFNVTTsKCXN0YXRpYyBjb25zdGV4cHIgaW50IE5VTV9WQUxTID0gc2l6ZW9mLi4uKEVudHJ5VHlwZXMpOwoJc3RkOjptdDE5OTM3IGdlbjsKCXN0ZDo6dW5pZm9ybV9pbnRfZGlzdHJpYnV0aW9uPD4gZGlzdDsKCnB1YmxpYzoKCglzdGF0aWMgY29uc3RleHByIGludCBzaXplKCkKCXsKCQlyZXR1cm4gTlVNX1ZBTFM7Cgl9CgoJdGVtcGxhdGU8dHlwZW5hbWUgVCwgdHlwZW5hbWUuLi4gYXJncz4KCWNvbnN0ZXhwciBpbnQgY2FsY1N1bSgpCgl7CgkJcmV0dXJuIFQ6OlBST0IgKyBjYWxjU3VtIDwgYXJncy4uLj4oKTsKCX0KCgl0ZW1wbGF0ZSA8dHlwZW5hbWUuLi4gVHMsIHR5cGVuYW1lID0gb25seUF0RW5kKFRzKSA+Cgljb25zdGV4cHIgaW50IGNhbGNTdW0oKQoJewoJCXJldHVybiAwOwoJfQoKCU51bUNob29zZXIoKSA6IFNVTShjYWxjU3VtIDwgRW50cnlUeXBlcy4uLiA+KCkpLCBnZW4oc3RkOjpyYW5kb21fZGV2aWNle30oKSksIGRpc3QoMSwgU1VNKSB7IH0KCgl0ZW1wbGF0ZTx0eXBlbmFtZSBULCB0eXBlbmFtZS4uLiBhcmdzPgoJY29uc3RleHByIGludCBmaW5kKGludCBsZWZ0LCBpbnQgcHJldmlvdXMgPSAwKQoJewoJCXJldHVybiBsZWZ0IDwgMCA/IHByZXZpb3VzIDogZmluZCA8IGFyZ3MuLi4gPihsZWZ0IC0gVDo6UFJPQiwgVDo6VkFMKTsKCX0KCgl0ZW1wbGF0ZSA8dHlwZW5hbWUuLi4gVHMsIHR5cGVuYW1lID0gb25seUF0RW5kKFRzKSA+Cgljb25zdGV4cHIgaW50IGZpbmQoaW50IGxlZnQsIGludCBwcmV2aW91cykKCXsKCQlyZXR1cm4gcHJldmlvdXM7Cgl9CgoJaW50IGNob29zZSgpCgl7CgkJcmV0dXJuIGZpbmQgPCBFbnRyeVR5cGVzLi4uID4oZGlzdChnZW4pKTsKCX0KfTsKCk51bUNob29zZXIgPApFbnRyeTwwLCAxMD4sCkVudHJ5PDEsIDUwPiwKRW50cnk8MiwgODA+LApFbnRyeTwzLCAwMT4KPiBjaG9vc2VyOwoKaW50IG1haW4oKQp7CglzdGQ6OmFycmF5PGludCwgY2hvb3Nlci5zaXplKCkgPiBmcmVxdWVuY3l7fTsKCWNvbnN0IGludCBOVU1fVFJJQUxTID0gMTAwMDA7Cglmb3IgKGludCBpID0gMDsgaSA8IE5VTV9UUklBTFM7ICsraSkKCXsKCQlpbnQgdmFsID0gY2hvb3Nlci5jaG9vc2UoKTsKCQlmcmVxdWVuY3lbdmFsXSsrOwoJfQoJc3RkOjpjb3V0IDw8ICJGcmVxdWVuY3k6IiA8PCBzdGQ6OmVuZGw7Cglmb3IgKGludCBpIDogZnJlcXVlbmN5KQoJCXN0ZDo6Y291dCA8PCAoZmxvYXQpIGkgLyBOVU1fVFJJQUxTIDw8ICIgIjsKfQ==