// clang++ -std=c++23 -Wall -Wextra -pedantic -D_CRT_SECURE_NO_WARNINGS elimination_simulation.cpp -g -o elimination_simulation.exe // .\elimination_simulation.exe 7 1000000 #include #include #include #include #include int simulateRps(int n, std::mt19937 &gen) { std::uniform_int_distribution<> rps(0, 2); int rounds = 0; while (n > 1) { int cnts[3] = {}; for (int i = 0; i < n; ++i) { ++cnts[rps(gen)]; } // Some players are eliminated iff // there are exactly 2 different choices present. if ((cnts[0] > 0) + (cnts[1] > 0) + (cnts[2] > 0) == 2) { if (cnts[0] == 0) { // no rocks => scissors stay n = cnts[2]; } else if (cnts[1] == 0) { // no papers => rocks stay n = cnts[0]; } else { // no scissors => papers stay n = cnts[1]; } } ++rounds; } return rounds; } int simulateZzz(int n, std::mt19937 &gen) { std::uniform_int_distribution<> rps(0, 1); int rounds = 0; while (n > 2) { int cnts[2] = {}; for (int i = 0; i < n; ++i) { ++cnts[rps(gen)]; } // Some players will be eliminated, // unless everyone chose the same or it's a tie. if (cnts[0] > 0 && cnts[1] > 0 && cnts[0] != cnts[1]) { // The minority stays. n = std::min(cnts[0], cnts[1]); } ++rounds; } // If 2 players remain, they play rock paper scissors. if (n == 2) { rounds += simulateRps(2, gen); } return rounds; } std::vector runSimulationsRps(int n, int s, std::mt19937 &gen) { std::vector rounds(s); for (int i = 0; i < s; ++i) { rounds[i] = simulateRps(n, gen); } std::sort(rounds.begin(), rounds.end()); return rounds; } std::vector runSimulationsZzz(int n, int s, std::mt19937 &gen) { std::vector rounds(s); for (int i = 0; i < s; ++i) { rounds[i] = simulateZzz(n, gen); } std::sort(rounds.begin(), rounds.end()); return rounds; } double getPercentile(const std::vector &v, int p) { double r = p / 100.0; return std::lerp( v[std::floor(r * v.size())], v[std::ceil(r * v.size())], r * v.size() - std::floor(r * v.size()) ); } void printResults(const std::vector &rounds) { int s = rounds.size(); double avg = (double)std::reduce(rounds.begin(), rounds.end()) / s; int min = *std::min_element(rounds.begin(), rounds.end()); int max = *std::max_element(rounds.begin(), rounds.end()); double p50 = getPercentile(rounds, 50); double p90 = getPercentile(rounds, 90); double p95 = getPercentile(rounds, 95); double p99 = getPercentile(rounds, 99); std::cout << "avg=" << avg << std::endl; std::cout << "min=" << min << std::endl; std::cout << "p50=" << p50 << std::endl; std::cout << "p90=" << p90 << std::endl; std::cout << "p95=" << p95 << std::endl; std::cout << "p99=" << p99 << std::endl; std::cout << "max=" << max << std::endl; } int main(int argc, char *argv[]) { if (argc != 3) return 1; int n; if (std::sscanf(argv[1], "%d", &n) != 1) return 1; if (n < 1) return 1; int s; if (std::sscanf(argv[2], "%d", &s) != 1) return 1; if (s < 1) return 1; std::random_device rd; std::mt19937 gen(rd()); std::cout << "ROCK PAPER SCISSORS" << std::endl; std::cout << "===================" << std::endl; printResults(runSimulationsRps(n, s, gen)); std::cout << std::endl; std::cout << "ZIMI ZAMI ZUM" << std::endl; std::cout << "=============" << std::endl; printResults(runSimulationsZzz(n, s, gen)); return 0; }