#!/usr/local/bin/perl -w
use strict;

# DiceRoll: Simulation to determine probability that at least
#              M matches will occur in a roll of N dice 
#           Program currently set to look for at least 2 matches
#              with 5 dice
#           Simulation goes for specified number of trials,
#              currently set at 10000

#******************** CONSTANTS ********************************

my $true = 1;
my $false = ! $true;
my $number_of_trials = 10000;
my $number_of_dice = 5;
my $matches_wanted = 2;

#******************* MAIN PROGRAM ******************************

my $successes = 0;
foreach my $trial (1..$number_of_trials) {
  roll_dice();
  if (any_matches()) { $successes = $successes + 1 }
}

print "Number of successes: ", $successes, "\n";
print "Number of trials:    ", $number_of_trials, "\n";
print "Fraction successful: ", $successes/$number_of_trials, "\n";

#******************* SUBROUTINES *******************************
my ($number_of_ones, $number_of_twos, $number_of_threes, $number_of_fours,
    $number_of_fives, $number_of_sixes);

sub roll_dice {
   $number_of_ones = 0;
   $number_of_twos = 0;
   $number_of_threes = 0;
   $number_of_fours = 0;
   $number_of_fives = 0;
   $number_of_sixes = 0;

   foreach my $roll (1..$number_of_dice) {
      my $die_value = random_integer(1,6);

      if ($die_value == 1) { $number_of_ones = $number_of_ones + 1 }
      if ($die_value == 2) { $number_of_twos = $number_of_twos + 1 }
      if ($die_value == 3) { $number_of_threes = $number_of_threes + 1 }
      if ($die_value == 4) { $number_of_fours = $number_of_fours + 1 }
      if ($die_value == 5) { $number_of_fives = $number_of_fives + 1 }
      if ($die_value == 6) { $number_of_sixes = $number_of_sixes + 1 }
   }
}

sub any_matches {
  if ($number_of_ones >= $matches_wanted) { return $true }
  if ($number_of_twos >= $matches_wanted) { return $true }
  if ($number_of_threes >= $matches_wanted) { return $true }
  if ($number_of_fours >= $matches_wanted) { return $true }
  if ($number_of_fives >= $matches_wanted) { return $true }
  if ($number_of_sixes >= $matches_wanted) { return $true }
  return $false;
}

# random_integer($low, $high) returns a random integer between $low and $high
#    inclusive.
# Assumption: $low < $high, and both are integers.
#
sub random_integer {
  my ($low, $high) = @_;
  my $range = $high - $low + 1;
  my $random_fraction_of_range = rand($range);
  return $low + int($random_fraction_of_range);
}
