If you aren't already in the know, these ten problems are from the 2008 Winter Scripting games.

For each problem, I'm going to quickly sum up the interesting (interesting TO ME) bits of each problem, then I'm going to post the full source.

Event 3: Instant (Runoff) Winner

 

This is not as straightforward as it looks. We are presented with a list of votes, each person voting for their preferred candidates, in order of preference. For each vote, you need to first count them as if there are 4 candidates, then count as if there are 3, then 2, until a candidate gets the majority vote. I'm actually proud of my solution. Some of the awesomeness is embodied in the following representative line:

$runoffCandidates = $results | Sort Percent -desc | select -first ($results.Count - 1) | % { $_.Name }

This is the magic that removes the candidate who just got booted off the island by reconstructing the list of the surviving candidates.

Source

#PROBLEM #3

#global, will change as the runoff eliminates candidates.
$runoffCandidates = @("Ken Myer","Jonathan Haas","Pilar Ackerman","Syed Abbas")

#POSTSCRIPT - this is one of the few times I think I'm justified in making a scriptmethod,
#because I think this is a nice solution to the problem.
function Create-VoteObject ($rawData)
{
    $o = new-object PSObject
    Add-Member -inputObject $o -memberType NoteProperty -name "Votes" -value $rawData.Split(",")
    Add-Member -inputObject $o -memberType ScriptMethod -name "GetValidVote" -value { Get-FirstValidCandidate $this.Votes }


    $o
}


function Get-FirstValidCandidate ($votes)
{
    foreach ($candidate in $votes)
    {
        if ($runoffCandidates -contains $candidate)
        {
            return $candidate
        }
    }
   
    #impossible to get here, throw error
    Throw "ERROR: Get-FirstValidCandidate should have already returned a value before reaching this point."
}

function Read-Votes ($filename)
{
    $rawVotes = cat $filename

    $rawVotes | % { Create-VoteObject -rawData $_ }
}

function Solve-Problem3
{
    $votes = Read-Votes "C:\Scripts\votes.txt"
   
    while ($runoffCandidates.Count -ge 2) {
        #POSTSCRIPT: to be honest, I think I originally wrote the following line as a function, then "shrunk
        #it down" to the following line. I'll break it up into each element in the pipeline:
        #    $results = $votes |
        #        Select @{ Name="Candidate"; Expression={ $_.GetValidVote() } } |
        #        group Candidate |
        #        select Name,
        #            @{ Name="Percent"; Expression={($_.Count/$votes.Count) * 100 } },
        #            @{ Name="Victory"; Expression={($_.Count/$votes.Count) -ge .5 } }
        $results = $votes | Select @{ Name="Candidate"; Expression={ $_.GetValidVote() } } | group Candidate | select Name, @{ Name="Percent"; Expression={($_.Count/$votes.Count) * 100 } }, @{ Name="Victory"; Expression={($_.Count/$votes.Count) -ge .5 } }
        $victoriousCandidate = $results | ? { $_.Victory }
        if ($victoriousCandidate)
        {
            write-host "The winner is $($victoriousCandidate.Name) with $($victoriousCandidate.Percent)% of the vote."
            break
        } else
        {
            $runoffCandidates = $results | Sort Percent -desc | select -first ($results.Count - 1) | % { $_.Name }
        }
    }
}


Solve-Problem3

2008 Winter Scripting Game Events: Index