//+------------------------------------------------------------------+
//| 96_Glico_Monte_Carlo_v1_00.mq5                                   |
//| Simulate the score difference of two Glico hand strategies.      |
//+------------------------------------------------------------------+
#property script_show_inputs
#property version   "1.00"
#property description "Monte Carlo simulation of Glico score differences"

input int InpRoundsPerMatch = 500;       // Hands in one match
input int InpMatches        = 10000;     // Number of simulated matches
input int InpSeed           = 20260929;  // Fixed seed for reproducibility

struct SimulationResult
  {
   int uniform_wins;
   int weighted_wins;
   int draws;
   double score_difference_sum;
   double score_difference_square_sum;
  };

int DrawBelow(const int limit)
  {
   if(limit<1 || limit>32768)
      return(-1);

   const int accepted=32768-(32768%limit);
   int value=0;
   do
     {
      value=MathRand();
     }
   while(value>=accepted);
   return(value%limit);
  }

int DrawUniformHand()
  {
   return(DrawBelow(3));
  }

int DrawWeightedHand()
  {
   const int bucket=DrawBelow(5);
   if(bucket<2)
      return(0); // Rock: 2/5
   if(bucket<4)
      return(1); // Scissors: 2/5
   return(2);    // Paper: 1/5
  }

int RoundScoreDifference(const int first_hand,const int second_hand)
  {
   if(first_hand==second_hand)
      return(0);

   // 0=rock, 1=scissors, 2=paper. Winning scores are 3, 6, and 6.
   const bool first_wins=((first_hand==0 && second_hand==1) ||
                          (first_hand==1 && second_hand==2) ||
                          (first_hand==2 && second_hand==0));
   if(first_wins)
     {
      if(first_hand==0)
         return(3);
      return(6);
     }

   if(second_hand==0)
      return(-3);
   return(-6);
  }

bool RunSimulation(const int rounds,const int matches,const int seed,
                   SimulationResult &result)
  {
   if(rounds<1 || matches<1)
      return(false);

   result.uniform_wins=0;
   result.weighted_wins=0;
   result.draws=0;
   result.score_difference_sum=0.0;
   result.score_difference_square_sum=0.0;
   MathSrand(seed);

   for(int match=0;match<matches;match++)
     {
      int total_difference=0;
      for(int round=0;round<rounds;round++)
        {
         const int first=DrawUniformHand();
         const int second=DrawWeightedHand();
         if(first<0 || second<0)
            return(false);
         total_difference+=RoundScoreDifference(first,second);
        }

      result.score_difference_sum+=(double)total_difference;
      result.score_difference_square_sum+=(double)total_difference*(double)total_difference;
      if(total_difference>0)
         result.uniform_wins++;
      else if(total_difference<0)
         result.weighted_wins++;
      else
         result.draws++;
     }
   return(true);
  }

void OnStart()
  {
   SimulationResult result;
   if(!RunSimulation(InpRoundsPerMatch,InpMatches,InpSeed,result))
     {
      Print("O96 status=FAILED reason=invalid_input");
      return;
     }

   const double average=(result.score_difference_sum/(double)InpMatches);
   const double second_moment=(result.score_difference_square_sum/(double)InpMatches);
   Comment("Glico Monte Carlo\n",
           "Uniform (1:1:1): ",result.uniform_wins," wins\n",
           "Weighted (2:2:1): ",result.weighted_wins," wins\n",
           "Draws: ",result.draws," / ",InpMatches," matches\n",
           "Mean score difference: ",DoubleToString(average,3)," steps\n",
           "Seed: ",InpSeed,"  |  ",InpRoundsPerMatch," hands per match");
   ChartRedraw(0);
   PrintFormat("O96 status=PASS uniform_wins=%d weighted_wins=%d draws=%d rounds=%d matches=%d seed=%d mean_score_diff=%.6f second_moment=%.6f",
               result.uniform_wins,result.weighted_wins,result.draws,
               InpRoundsPerMatch,InpMatches,InpSeed,average,second_moment);
  }
