Hydreigon_Lord

The Amazing Race Leg Win / Last Place Simulator

Oct 31st, 2020
2,084
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //Hydreigon_Lord
  2. //The Amazing Race Leg Win / Last Place Simulation
  3.  
  4. #include <iostream>
  5. #include <string>
  6. #include <vector>
  7. #include <random>
  8. #include <cmath>
  9. #include <iomanip>
  10. using namespace std;
  11.  
  12. //Global constants
  13. const long SIMULATIONS = 1000000;
  14. const vector<string> TEAM_NAMES = {
  15.     "Dave & Connor",
  16.     "Pam & Winnie",
  17.     "Max & Katie",
  18.     "Caroline & Jennifer",
  19.     "Joey & Meghan",
  20.     "Mona & Beth",
  21.     "Bates & Anthony",
  22.     "Chuck & Wynona"
  23. };
  24. const vector<vector<int>> LEG_RANKS = {
  25.     {3,2,1,1},
  26.     {4,9,4,2},
  27.     {9,8,8,3},
  28.     {10,7,6,4},
  29.     {6,4,5,5},
  30.     {5,6,7,6},
  31.     {2,1,3,7},
  32.     {7,5,9,8}
  33. };
  34.  
  35. //Class to represent teams
  36. class Team
  37. {
  38. public:
  39.     //Creates a team with a blank name
  40.     Team()
  41.     {
  42.         name = "";
  43.     }
  44.    
  45.     //Sets the team's name to the given name
  46.     void setName(string n)
  47.     {
  48.         name = n;
  49.     }
  50.    
  51.     //Adds a leg rank to this team's rank progression
  52.     void addRank(int r)
  53.     {
  54.         ranks.push_back(r);
  55.     }
  56.    
  57.     //Returns this team's name
  58.     string getName() const
  59.     {
  60.         return name;
  61.     }
  62.    
  63.     //Returns the number of legs this team has competed in
  64.     int numLegs() const
  65.     {
  66.         return (int)ranks.size();
  67.     }
  68.    
  69.     //Returns this team's last leg rank
  70.     int lastRank() const
  71.     {
  72.         return ranks[ranks.size() - 1];
  73.     }
  74.    
  75.     //Returns this team's racing average (average leg rank)
  76.     //Returns -1 if this team has no leg ranks
  77.     double racingAverage() const
  78.     {
  79.         if (ranks.size() == 0)
  80.             return -1;
  81.         double sum = 0;
  82.         for (int r: ranks) {
  83.             sum += r;
  84.         }
  85.         return sum / ranks.size();
  86.     }
  87.    
  88.     //Returns this team's standard deviation of leg ranks
  89.     //Returns -1 if this team has fewer than 2 leg ranks
  90.     double sdLegRanks() const
  91.     {
  92.         if (ranks.size() < 2)
  93.             return -1;
  94.         double mean = racingAverage();
  95.         double var = 0;
  96.         for (int r: ranks) {
  97.             var += pow(r - mean, 2);
  98.         }
  99.         return sqrt(var / (ranks.size() - 1));
  100.     }
  101.    
  102.     //Returns this team's volatility (average leg rank change)
  103.     //Returns -1 if this team has fewer than 2 leg ranks
  104.     double volatility() const
  105.     {
  106.         if (ranks.size() < 2)
  107.             return -1;
  108.         double sum = 0;
  109.         int lastRank = ranks[0];
  110.         for (int i = 1; i < ranks.size(); i++) {
  111.             sum += abs(ranks[i] - lastRank);
  112.             lastRank = ranks[i];
  113.         }
  114.         return sum / (ranks.size() - 1);
  115.     }
  116.    
  117.     //Returns this team's standard deviation of leg rank changes
  118.     //Returns -1 if this team has fewer than 3 leg ranks
  119.     double sdLegRankChanges() const
  120.     {
  121.         if (ranks.size() < 3)
  122.             return -1;
  123.         double mean = volatility();
  124.         double var = 0;
  125.         int lastRank = ranks[0];
  126.         for (int i = 1; i < ranks.size(); i++) {
  127.             var += pow(abs(ranks[i] - lastRank) - mean, 2);
  128.             lastRank = ranks[i];
  129.         }
  130.         return sqrt(var / (ranks.size() - 2));
  131.     }
  132.    
  133.     //Converts this team to a string (equivalent to getName())
  134.     operator string() const
  135.     {
  136.         return name;
  137.     }
  138.    
  139. private:
  140.     string name;
  141.     vector<int> ranks;
  142.    
  143. };
  144.  
  145. int main()
  146. {
  147.     if (TEAM_NAMES.size() != LEG_RANKS.size()) {
  148.         cout << "The list of team names is length " << TEAM_NAMES.size();
  149.         cout << ", but the list of leg ranks includes leg rank lists for " << LEG_RANKS.size() << " teams.\n";
  150.         exit(1);
  151.     }
  152.    
  153.     //Seed the random engine
  154.     random_device rd;
  155.     seed_seq seq{rd(), rd(), rd(), rd(), rd(), rd(), rd(), rd()};
  156.     mt19937_64 en(seq);
  157.    
  158.     //Initialize the list of teams
  159.     int n = (int)TEAM_NAMES.size();  //This will hold the number of teams in the simulation
  160.     Team* teams = new Team[n];  //This is the master copy of the team list
  161.     for (int i = 0; i < n; i++) {
  162.         teams[i].setName(TEAM_NAMES[i]);
  163.         for (int r: LEG_RANKS[i]) {
  164.             teams[i].addRank(r);
  165.         }
  166.     }
  167.    
  168.     //Prepare for the simulations
  169.     Team* tempTeams;  //This is a pointer to a team list for a particular simulation only
  170.     vector<long> numWins, numLasts;
  171.     vector<int> currRanks;
  172.     for (int i = 0; i < n; i++) {
  173.         numWins.push_back(0);
  174.         numLasts.push_back(0);
  175.         currRanks.push_back(teams[i].lastRank());
  176.     }
  177.     vector<double> results;
  178.     uniform_int_distribution<int> randLegRanks(1, n);
  179.     normal_distribution<double> randGaussian(0, 1);
  180.    
  181.     //Perform the simulations
  182.     long print_interval = 10000 / n;  //After every print_interval sims, print the current progress
  183.     for (long s = 1; s <= SIMULATIONS; s++) {
  184.         //Initialize the temporary teams list
  185.         tempTeams = new Team[n];
  186.         for (int i = 0; i < n; i++) {
  187.             tempTeams[i] = teams[i];
  188.             //Assign the team 3 additional random leg ranks
  189.             for (int j = 0; j < 3; j++) {
  190.                 tempTeams[i].addRank(randLegRanks(en));
  191.             }
  192.         }
  193.        
  194.         //Generate the simulation results using one of two methods
  195.         if (s % 2 == 0) {  //Simulate based on racing average and SD of leg ranks
  196.             for (int i = 0; i < n; i++) {
  197.                 results.push_back(tempTeams[i].racingAverage() + tempTeams[i].sdLegRanks() * randGaussian(en));
  198.             }
  199.         } else {  //Simulate based on current rank, volatility, and SD of leg rank changes
  200.             for (int i = 0; i < n; i++) {
  201.                 results.push_back(currRanks[i] + (generate_canonical<float, 32>(en) < 0.5 ? -1 : 1) * tempTeams[i].volatility() + tempTeams[i].sdLegRankChanges() * randGaussian(en));
  202.             }
  203.         }
  204.        
  205.         //Determine who wins and who gets last place
  206.         int winInd = 0, lastInd = 0;
  207.         for (int i = 1; i < n; i++) {
  208.             if (results[i] < results[winInd]) {
  209.                 winInd = i;
  210.             } else if (results[i] > results[lastInd]) {
  211.                 lastInd = i;
  212.             }
  213.         }
  214.         numWins[winInd]++;
  215.         numLasts[lastInd]++;
  216.        
  217.         //Cleanup
  218.         delete[] tempTeams;
  219.         results.clear();
  220.         if (s % print_interval == 0) {
  221.             cout << "Completed " << s << " out of " << SIMULATIONS << " simulations (";
  222.             cout << (100 * s / SIMULATIONS) << "% done)\n";
  223.         }
  224.     }
  225.    
  226.     //Report the results
  227.     cout << left << setprecision(4) << fixed << showpoint;
  228.     cout << setw(8) << "Rank";
  229.     cout << setw(24) << "Team Name";
  230.     cout << setw(8) << "Win %";
  231.     cout << setw(8) << "Last %";
  232.     cout << setw(8) << "R.Avg.";
  233.     cout << setw(8) << "(SD)";
  234.     cout << setw(8) << "Vol.";
  235.     cout << setw(8) << "(SD)";
  236.     cout << endl << string(80, '-') << endl;
  237.     for (int i = 0; i < n; i++) {
  238.         cout << setw(8) << currRanks[i];
  239.         cout << setw(24) << teams[i].getName();
  240.         cout << setw(8) << 100.0 * numWins[i] / SIMULATIONS;
  241.         cout << setw(8) << 100.0 * numLasts[i] / SIMULATIONS;
  242.         cout << setw(8) << teams[i].racingAverage();
  243.         int numLegs = teams[i].numLegs();
  244.         if (numLegs >= 2) {
  245.             cout << setw(8) << teams[i].sdLegRanks();
  246.             cout << setw(8) << teams[i].volatility();
  247.             if (numLegs >= 3) {
  248.                 cout << setw(8) << teams[i].sdLegRankChanges();
  249.             }
  250.         }
  251.         cout << endl;
  252.     }
  253.    
  254.     delete[] teams;
  255.     return 0;
  256. }
RAW Paste Data