Last week I showed you my PowerShell Bingo game. While the game itself might be a fun way to pass the time, the real goal was to teach you some PowerShell techniques and concepts without you realizing it. This week, I thought I'd keep with the gaming theme and take up chance. Specifically let's roll some dice and flip some coins. These aren't especially complicated tasks in PowerShell, and it is hard to say what problem they might solve, but let's have some fun anyway.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
First up, flipping coins.
Flipping a coin is essentially a True/False game. Or another way to look at is Even/Odd. My favorite way is to use the modulo operator.
PS C:\> 5%2 1 PS C:\> 6%2 0
Those values can be represented as Booleans.
PS C:\> 5%2 -as [boolean] True PS C:\> 6%2 -as [boolean] False
So all I need is a random number and perform a modulo operation. Here's the function I created.
Function Invoke-CoinToss { [cmdletbinding(DefaultParameterSetName="_AllParameterSets")] Param( [Parameter(ParameterSetName="Boolean")] [switch]$AsBoolean, [Parameter(ParameterSetName="EvenOdd")] [switch]$EvenOdd ) Write-Verbose "Using parameter set $($PSCmdlet.ParameterSetName)" #get a random number between 1 and 100 to test $i = Get-Random -Minimum 1 -Maximum 100 Write-Verbose "Random result = $i" #use the modulo operator if ($i%2) { Write-Verbose "Odd/Heads/True" Switch ($PSCmdlet.ParameterSetName) { "Boolean" { $True} "EvenOdd" {"Odd" } Default {"Heads"} } #switch } #if else { Write-Verbose "Even/Tails/False" Switch ($PSCmdlet.ParameterSetName) { "Boolean" { $False} "EvenOdd" {"Even" } Default {"Tails"} } #switch } #else } #end Invoke-CoinToss
I used a valid verb but will also define a more user-friendly alias.
Set-Alias -Name Flip-Coin -Value Invoke-CoinToss
Because you may want several different types of output, not necessarily the best idea for a function but this might be an exception. And remember this is supposed to be educational not necessarily practical. My function uses parameter sets and depending on the set, decides what type of result to write to the pipeline.
And it seems to work pretty well.
Next, let's roll some dice. Again I'll use Get-Random . A single dice roll is as simple as this:
get-random -Minimum 1 -Maximum 7
To roll multiple dice, you could do this:
$Dice = 4 1..$Dice | foreach { Get-Random -Minimum 1 -Maximum 7 }
Naturally I wrote a function with a few more bells and whistles because I like shiny toys.
Function Invoke-Dice { [cmdletbinding()] Param( [ValidateRange(1,10)] [int]$Dice = 2, [ValidateRange(6,12)] [int]$Sides = 6, [Alias("Total")] [switch]$Sum ) Write-Verbose "Rolling $dice $sides-sided dice" #generate a list of all possible numbers then select all random numbers at once $result = (1..$Sides)*$Dice | Get-Random -Count $Dice if ($sum) { write-Verbose "Totaling the result" Write-Verbose $($result -join ",") ($result | Measure-Object -sum).Sum } else { $result } } #end roll-dice Set-Alias -name Roll-Dice -value Invoke-Dice
This function lets you choose the number of dice to roll. Notice I use a ValidateRange attribute to limit the number of dice. And in case you are rolling for a game of Dungeons and Dragons which has some extra-sided dice, I gave you that option as well.
In some games, you need the total so I added that as well. One thing that I changed was my rolling technique. In this version I am pre-generating an array of all possible values and then get the specified number of random values.
$result = (1..$Sides)*$Dice | Get-Random -Count $Dice
Not that it is super critical, but this technique is faster.
$dice = 8 $sides = 7 Measure-Command { 1..$Dice | foreach { Get-Random -Minimum 1 -Maximum ($sides+1) } } Measure-Command { (1..$Sides)*$Dice | Get-Random -Count $Dice }
Here's the result
If you are debating between different techniques in a script or function, use Measure-Command to see how they perform.
Now you have some tools to build your own PowerShell games and maybe learn something new in the process. If you do, I hope you'll share. Enjoy!
I like it. If we’re looking for performance, though, removing the pipeline helps:
get-Random -Count $Dice -InputObject ( (1..$Sides)*$Dice )
Yes indeed. Thanks.
You made a common mistake with the get-random function for the dice roll. You need to change the Maximum to 7; otherwise, 6 will NEVER occur.
get-random -Minimum 1 -Maximum (6+1)
You are indeed correct. Thanks for pointing that out. I updated the relevant code samples in the post, although my function to roll dice should be ok as is.