#!/usr/bin/perl -w
# DiceRoll
#    VERSION: 2 (14 September 2003)
#    PURPOSE: 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
#           This program serves to introduce simulations
#    INPUT FILES:  None
#    OUTPUT FILES: None. Output to monitor.

############## LIBRARIES AND PRAGMAS ################
  use strict;

#################### CONSTANTS ######################

   my $true = 1;                  # Defines the word "true"
   my $false = 0;                 # Defines the word "false"
   my $number_of_trials = 10000;  # Number of times dice are thrown
   my $number_of_dice = 5;        # Number of dice thrown
   my $matches_wanted = 2;        # Defines success: if any number occurs this many times
   my $LF = "\n";                 # Line feed

#################### VARIABLES ######################

   my $successes = 0;        # Accumulates number of times conditions are met
   my $trial;                # Goes from 1 to number of trials specified
   my $number_of_ones;       # Accumulates numbers of ones seen in a throw of the dice
   my $number_of_twos;       # Accumulates numbers of twos seen in a throw of the dice
   my $number_of_threes;     # Accumulates numbers of threes seen in a throw of the dice
   my $number_of_fours;      # Accumulates numbers of fours seen in a throw of the dice
   my $number_of_fives;      # Accumulates numbers of fives seen in a throw of the dice
   my $number_of_sixes;      # Accumulates numbers of sixes seen in a throw of the dice

################### MAIN PROGRAM ####################

   foreach $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 ####################

#### ROLL_DICE
#    Simulates roll of N dice (where N is $number_of_dice)
#      Counts ones, twos, etc, as it goes along
#    Counts must be initialized to zero before each roll
sub Roll_dice {

   my $die;               # A counter, going from die #1 to the last die
   my $die_value;         # Number of spots shown, i.e. a number between 1 and 6

   $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 $die (1..$number_of_dice) {
      $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 }
   }
}

#### ANY_MATCHES
#    Checks to see if the roll satisfies criteria for success
#    Returns true if criteria met, returns false otherwise
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 random integer within a given range of $low to $high, inclusive
#    Used by roll_dice to get value for a single die
#    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);
}
