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 10: Blackjack!

Here we are asked to simulate a text-based Blackjack game. Mine works, I'm certainly not proud of the graphics, not proud of the colors, not even necessarily proud of the structure of my solution.

Please do not look at any of the following code and think "that's how I'm supposed to use objects in PowerShell!" Please don't. It's NOT ideal, I made several design mistakes; I don't even think most of my objects are necessary. Or, thinking from the other side--maybe I didn't go far enough.

Source

#PROBLEM #10
$cardValues = @{
    "Ace" = 11;
    "King" = 10;
    "Queen" = 10;
    "Jack" = 10;
    "Ten" = 10;
    "Nine" = 9;
    "Eight" = 8;
    "Seven" = 7;
    "Six" = 6;
    "Five" = 5;
    "Four" = 4;
    "Three" = 3;
    "Two" = 2;
}


$suits = @("Spades", "Hearts", "Diamonds", "Clubs")


#bad random number generator
$rnd = new-object Random




function Create-DeckObject
{
    $o = new-object PSObject
    $cards = @()
    foreach ($suit in $suits)
    {
        foreach ($cardValue in $cardValues.Keys)
        {
            $cards += Create-CardObject -value $cardValue -suit $suit
        }
    }
   
    $sortedDeck = $cards | sort PositionInDeck
   
    Add-Member -inputObject $o -memberType NoteProperty -name "Cards" -value $sortedDeck
    Add-Member -inputObject $o -memberType ScriptProperty -name "Deal" -value { $nextCard = $this.Cards | select -first 1; $this.Cards = $this.Cards | select -last ($this.Cards.Count - 1); $nextCard }
   
    $o
}


function Create-CardObject ($value, $suit)
{
    $o = new-object PSObject


    Add-Member -inputObject $o -memberType NoteProperty -name "Card" -value ("$value of $suit")
    Add-Member -inputObject $o -memberType NoteProperty -name "BlackjackValue" -value $cardValues[$value]
    Add-Member -inputObject $o -memberType NoteProperty -name "PositionInDeck" -value $rnd.NextDouble()
   
    $o
}


function Create-HandObject ([switch]$isdealer)
{
    $o = new-object PSObject


    $emptyHand = @()
    Add-Member -inputObject $o -memberType NoteProperty -name "Cards" -value $emptyHand
    Add-Member -inputObject $o -memberType NoteProperty -name "IsDealerHand" -value $isdealer


    #this value will change for the dealer hand as the game progresses.
    Add-Member -inputObject $o -memberType NoteProperty -name "AreAllCardsRevealed" -value (-not $isdealer)
    Add-Member -inputObject $o -memberType ScriptProperty -name "BlackjackValue" -value { $total = 0; $this.Cards | % {$total += $_.BlackjackValue}; $total }
   
    $o
}


function Print-VisibleCards ($cards,$allcardsvisible,[switch]$isdealer)
{
    $output = @()
    if ($allcardsvisible -eq $TRUE)
    {
        foreach ($card in $cards)
        {
            $output += $card.Card
        }


        #POSTSCRIPT-OOPS! Looks like I'm calculating the "total value of hand", when
        #I expose that value as a script property! This function would have been
        #IDEAL as a ScriptMethod attached to the Hand object.
        $total = 0; $cards | % { $total += $_.BlackjackValue }
        if (-not $isdealer)
        {
            $output += "You have $($total).`n"
        }
        else
        {
            $output += "Dealer has $($total).`n"
        }
    }
    else
    {
        #if the dealer's hand is invisible, we don't know their total, so
        #don't display it; also we can only see the second card.
        $output += $cards[1].Card
    }
   
    $output | out-string
}


function Show-Status ($my, $dealer)
{
    Write-Host "Your cards:"
    Write-Host (Print-VisibleCards -cards $my.Cards -allcardsvisible $TRUE) -foregroundColor Green
   
    Write-Host "Dealer's cards:"
    Write-Host (Print-VisibleCards -cards $dealer.Cards -isdealer -allcardsvisible $dealer.AreAllCardsRevealed ) -foregroundColor Red
}


function Show-Action ($text)
{
    Write-Host $text -foregroundColor Yellow
    Start-Sleep -seconds 1
}


function Solve-Problem10
{
    $deck = Create-DeckObject
   
    $myHand = Create-HandObject
    $dealerHand = Create-HandObject -isdealer
   
    Show-Action "Dealing starting hands..."
    $myHand.Cards += $deck.Deal
    $dealerHand.Cards += $deck.Deal
    $myHand.Cards += $deck.Deal
    $dealerHand.Cards += $deck.Deal


    #show starting hands
    Show-Status -my $myHand -dealer $dealerHand
   
   
    #give the player the option to hit
    while ($myHand.BlackjackValue -lt 21)
    {
        Write-Host -noNewLine "Stay (s) or Hit (h) ? "
        if ((Read-Host) -match "h")
        {
            Show-Action "You have chosen to Hit."
            $myHand.Cards += $deck.Deal
            Show-Status -my $myHand -dealer $dealerHand
        }
        else
        {
            Show-Action "You have chosen to Stay."
            break
        }
    }
   
    #did we bust? If so, quit.
    if ($myHand.BlackjackValue -gt 21)
    {
        Show-Action "YOU LOSE! You busted!"
        return
    }


    #dealer reveals their cards
    $dealerHand.AreAllCardsRevealed = $TRUE
    Show-Action "Dealer has revealed their cards."


    Show-Status -my $myHand -dealer $dealerHand
    #extra delay so that we can process what is in the dealer's hand.
    Start-Sleep -seconds 3
   
   
    #give the dealer the option to hit
    while ($dealerHand.BlackjackValue -lt $myHand.BlackjackValue)
    {
        Show-Action "Dealer takes a card."
        $dealerHand.Cards += $deck.Deal
        Show-Status -my $myHand -dealer $dealerHand
    }
   
    #did dealer bust? If so, VICTORY!
    if ($dealerHand.BlackjackValue -gt 21)
    {
        Show-Action "YOU WIN! VICTORY! Dealer busts!"
    }
    else
    {
        Show-Action "YOU LOSE! Dealer has $($dealerHand.BlackjackValue), you have $($myHand.BlackjackValue)."
    }
}


Solve-Problem10

2008 Winter Scripting Game Events: Index