PowerShell: deck of cards
I started modelling a deck of normal Western, French-suit playing cards as a way to learn the basics of object-oriented programming.
I did it in PowerShell, just to see how far I can push it.
There are no games that you can actually play with this code - you can only set up a new, shuffled deck of 52 cards, deal cards from the deck, draw cards into your hand, and deal cards from your hand.
Things I learned in this exercise:
- Inheritance (through Deck : Stack and Hand : Stack)
- Class methods
- Enums, as "custom types"
- Using enum values as numbers to access array elements
- Presenting preset choices to the user through the console
Here it is:
using namespace System.Collections.Generic; # for List
using namespace System.Management.Automation.Host; # for ChoiceDescription
Function Get-EnumValues{
# get-enumValues -enum "System.Diagnostics.Eventing.Reader.StandardEventLevel"
Param([string]$enum)
$enumValues = @{}
[enum]::getvalues([type]$enum) |
ForEach-Object {
$enumValues.add($_, $_.value__)
}
$enumValues
}
enum Suit {
spades = 0
hearts = 1
clubs = 2
diamonds = 3
}
enum CardValue {
ace = 1
two = 2
three = 3
four = 4
five = 5
six = 6
seven = 7
eight = 8
nine = 9
ten = 10
jack = 11
queen = 12
king = 13
}
class Card {
[Suit] $suit
[CardValue] $value
[string] $symbol
hidden [string[]] $symbols = @("♠","♥","♣","♦")
hidden [string[]] $indeces = @('0','A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K')
Card([Suit] $suit, [CardValue] $value) {
$this.suit = $suit
$this.value = $value
$this.symbol = "$($this.indeces[$value])$($this.symbols[$suit])"
}
[string] Elaborate() {
return "$($this.value) of $($this.suit)"
}
}
# a hand and a deck are all "stacks"
class Stack {
[List[Card]] $cardList
Stack() {
[List[Card]] $this.cardList = @()
}
[int] Count() { return $this.cardList.Count }
[Card] Deal($i) {
$dealtCard = $this.cardList[$i]
$this.cardList.RemoveAt($i)
return $dealtCard
}
[void] Add([Card]$card) {
$this.cardList.Add($card)
}
}
class Deck : Stack {
Deck() {
[Suit].GetEnumNames().ForEach({
$_suit = $_
[CardValue].GetEnumNames().ForEach({
$_value = $_
$this.Add(
[Card]::new($_suit, $_value)
)
})
})
}
[Card] Deal() {
$deckCount = $this.Count()
$randomNumber = if ($deckCount -gt 1) {
Get-Random ($deckCount - 1)
} else {
0
}
$dealCard = $this.Deal($randomNumber)
# Write-Host Deal $dealCard.Elaborate() "," $this.Count() cards remaining
return $dealCard
}
}
class Hand : Stack {
[List[Card]] Draw(
[Deck] $pile,
[int] $numberOfCards
){
[List[Card]] $drawnCards = @()
for ($i = 0; $i -lt $numberOfCards; $i++) {
$drawnCard = $pile.Deal()
[void] $this.Add($drawnCard)
[void] $drawnCards.Add($drawnCard)
}
return $drawnCards
}
[Card] Discard() {
[ChoiceDescription[]] $options = @()
$options = $this.cardList |
%{
return [ChoiceDescription]::new($_.symbol, $_.symbol)
}
[int] $discardIndex = (Get-Host).ui.PromptForChoice("Pick a card", "Choose a card to play/discard", $options, 0)
$discardedCard = $this.cardList[$discardIndex]
[void] $this.cardList.RemoveAt($discardIndex)
return $discardedCard
}
}
$hand = [Hand]::new()
$deck = [Deck]::new()
$discard = [Stack]::new()
[void] $hand.Draw($deck, 5)
[void] $hand.Discard()
[void] $hand.Discard()