#!/usr/bin/perl # # Syntax: get_cards [-s] [-v] -i <repeat_time> # -s = Switch: Your policy is to switch after Montys disclosure # -v = Verbose. Print 1 line for each iteration # -i = Number of iterations # # Program to demonstrate the 'Monty Hall' brainteaser. # See http://www.deanesmay.com/archives/000601.html & # http://www.deanesmay.com/archives/000656.html#000656 for more info. # C 2003 David Yule <david@yule.org> ######################################################################## use strict; use Getopt::Std; my %opts; getopts('svi:', \%opts); # options as above. Values in %opts my ($iterations, $switchpolicy, $verbose) = ($opts{i}, $opts{s}, $opts{v}); die "Syntax: $0 -i <iterations> [-s] [-v]\n" unless ($iterations > 0); my $wins = 0; foreach my $count (1 .. $iterations) { my ($win_door, $sel_door, $monty_door, $open_door); $win_door = &pick_door; # Randomly select the winning door $sel_door = &pick_door; # Randomly select your initial choice # Monty selects his door: He can't select $windoor or $seldoor # But we must check that these doors aren't the same if ($sel_door == $win_door) { $monty_door = &pick_door($win_door); } else { $monty_door = &pick_door($win_door, $sel_door); } # Now select your final door to be opened. Depends on your policy if ($switchpolicy) # Switch (pick the other door) { $open_door = &pick_door($sel_door, $monty_door); } else { $open_door = $sel_door} # Add to win count if the open door is the winning door. $wins += 1 if ($open_door == $win_door); print "Prize door: $win_door, Picked door: $sel_door, Opened door: $monty_door, Final door: $open_door: " . ($open_door == $win_door ? "WIN" : "LOSE") . "\n" if ($verbose); } printf "TOTAL WINS: $wins/$iterations (%.2f%%)\n", 100*$wins/$iterations; # Subroutine which randomly picks a door. It is passed a list of doors which # can't be picked. # The concept is simple but the code looks a bit weird ... # If any door can be selected: it's a simple random number. # If 1 door can't be selected: then add a random number (1 or 2) to the # unselectable door number (modulo 3) # If 2 doors can't be selected: Use the fact that adding the numbers of all # the doors comes to 6 (1+2+3) to select the unselected one. sub pick_door { my @doors = @_; my $selected; my $options = 2-$#doors; # Number of doors to choose from (1,2 or 3) if ($options == 3) # Pick a random number 1,2,3 { $selected = int(rand(3)) + 1; } elsif ($options == 2) # Pick a random number 1,2 then add that to invalid { $selected = (int(rand(2)) + $doors[0]) % 3 + 1; } elsif ($options == 1) # No choice: pick unselected door { $selected = 6 - $doors[0] - $doors[1];} else { die "Illegal list of doors sent to pick_door: @doors"; } $selected; }