#!/usr/bin/env perl
# https://www.youtube.com/watch?v=iSNsgj1OCLA
use v5.40;
use strict;
use warnings;
use diagnostics;
use Array::Contains;
my $PRISONERCOUNT = 100; # How many prisoners
my $OPENBOXES = $PRISONERCOUNT / 2; # Every prisoner can open half the boxes
my $LOOPCOUNT = 10_000;
my $DEBUG = 0;
STDOUT->autoflush(1);
my @results = (0, 0);
for(my $l = 0; $l < $LOOPCOUNT; $l++) {
if($DEBUG) {
print "== SIMULATION $l ==\n";
} elsif($l % 100 == 0) {
print "== SIMULATION $l of $LOOPCOUNT ==\r"; # non-debug: overwrite the line without scrolling
}
$results[simulate()]++;
}
print "\n";
print "Success: ", $results[1], "\n";
print "Fail: ", $results[0], "\n";
print "Fail rate: ", $results[0] / ($results[0] + $results[1]) * 100, "%\n";
sub simulate {
my $boxes = generateBoxes();
DumpBoxes($boxes) if($DEBUG);
print "Checking prisoner " if($DEBUG);
for(my $i = 0; $i < $PRISONERCOUNT; $i++) {
print $i, " " if($DEBUG);
if(!checkBoxes($boxes, $i, $OPENBOXES)) {
print "Failed!\n" if($DEBUG);
return 0;
}
}
print "OK\n" if($DEBUG);
return 1;
}
sub generateBoxes {
print "Generating boxes...\n" if($DEBUG);
my @boxes;
while(scalar @boxes < $PRISONERCOUNT) {
my $prisoner = int(rand($PRISONERCOUNT));
if(!contains($prisoner, \@boxes)) {
push @boxes, $prisoner;
}
}
return \@boxes;
}
sub checkBoxes($boxes, $prisoner, $count) {
my $currentbox = $prisoner;
while($count) {
my $val = $boxes->[$currentbox]; # Get content of current box
if($val == $prisoner) {
return 1;
}
$currentbox = $val;
$count--;
}
return 0;
}
sub DumpBoxes($boxes) {
print "---- BOXES -------------\n";
for(my $i = 0; $i < $PRISONERCOUNT; $i++) {
print $i, " => ", $boxes->[$i], "\n";
}
print "---- LOOPS -------------\n";
my @seen;
for(my $i = 0; $i < $PRISONERCOUNT; $i++) {
my $currentbox = $i;
my $count = 100;
my $ok = 1;
my @current;
while($count) {
if(contains($currentbox, \@seen)) {
$ok = 0; # Part of already known loop
last;
}
push @current, $currentbox;
my $val = $boxes->[$currentbox];
if($val == $i) {
last; # Loop done
}
$currentbox = $val;
}
if($ok) {
print join(' ', @current), "\n";
push @seen, @current;
}
}
print "------------------------\n";
return;
}
####
$ perl simulate.pl
== LOOP 99900 ==
Success: 31139
Fail: 68861
Fail rate: 68.861%
##
##
---- LOOPS -------------
0 72 86 73 80
1 96 19 83 91 47 75 18 53 3 50 24 81 59 38 23 44 67 39 55 65
2 20 45 98 84 89 63 93 46 58 68 28 56 64 78 6 87 52 8 82 97 34 31 85 79 12 41 48 70 66 37 5 49 33 51 15 57 54 69 90 26 43 14 94 76 9 88 40
4 42 25 99 27 77 16 10 74 36 22
7 13 71 61 62 11 95 21 17 30
29
32
35 60 92
------------------------