Dyota's blog

PowerShell: 100 prisoners

A good friend of mine mentioned this this maths problem on the weekend while were on a hike.

The group of us found it simple enough yet fascinating enough that we said we would code it up and see if we could model the situation.

I took on the challenge of writing it in PowerShell (of course!)

Here it all is!

using namespace System.Collections

function makeCabinet {
    $hundred = @(1..100)
    [ArrayList] $cabinet = @()
    [ArrayList] $prisonerNumbers = $hundred
    
    # set up a cabinet of 100 boxes with random prisoner number assignments
    $hundred.ForEach({
            [int] $randomPrisoner = $prisonerNumbers[$(Get-Random $prisonerNumbers.Count)]
            $box = [PSCustomObject] @{
                number         = [int] $_;
                prisonerNumber = [int] $randomPrisoner
            }
            [void] $prisonerNumbers.Remove($randomPrisoner)
            [void] $cabinet.Add($box)
        })
    return $cabinet
}


# look into a box and see which prisoner number is in it
function checkBoxContents ([int] $boxNumber) {
    return [int] $cabinet[$boxNumber].prisonerNumber
}

# get one prisoner to search through their allowed 50 attempts
function searchThroughBoxes($prisonerNumber) {
    $found = $false
    $count = 0
    $startingNumber = $prisonerNumber

    while (
        !$found -and $count -lt 50
    ) {    
    
        [int] $nextnumber = if ($count -eq 0) {
            checkBoxContents $startingNumber
        }
        else {
            (checkBoxContents $nextNumber)
        }

        $count++

        if ($nextNumber -eq $prisonerNumber) {
            $found = $true
            $out = "Prisoner `#$prisonerNumber found in $count attempts!"
        }
    }

    if (!$found) {
        $out = "Prisoner `#$prisonerNumber search failed`, everybody dies."
    }

    # Write-Host $out
    return $found
}

function trialGroupOfPrisoners() {
    $alive = $true

    # start with prisoner #1
    $prisonerNumber = 1
    
    # get all the prisoners to go through and search
    while ($alive -and $prisonerNumber -le 100) {
        $found = searchThroughBoxes $prisonerNumber
        if (!$found) {
            $alive = $false
            Write-Host Search failed`, everybody dies
        }
        else {
            $prisonerNumber++
        }
    }
    
    return $alive
}

$lifetimes = 1000

$successes = 0

for ($i = 0; $i -lt $lifetimes; $i++) {
    $cabinet = makeCabinet
    if (trialGroupOfPrisoners) { 
        Write-Host Everybody lives and goes free!
        $successes++ 
    }
}


$successes / $lifetimes

#montecarlo #powershell