Scripting Games 2007 Advanced PowerShell Event 10
Event 10: Pick a Color, Any Color
PS Answer: Pick a Color, Any Color
For this event we had to make a Card game, Draw 20 Colored cards and asking the person being testing to predict the color of the card about to be drawn
As I did not like that for the VbScript division an GUI (HTA) was asked and PowerShell Division the answer only had to be colored text ( as we have it much easer already in the PowerShell division as the VbScript Guy's with our much more PowerFull environment ) , I decided to also make a GUI version in PowerShell using Windows Forms.
After making that alternate version, I got another idea ... I did not NEED to use Windows forms for a GUI version, I also could use the Console and RawUI to make a GUI version.. So I ended up with 3 versions of the Script.
- The Text Version I did send in as Answer to Event 10
- A GUI version using Windows Forms
- A GUI version using the RawUI support of the PowerShell Host
I will provide all 3 versions below, ( so this will be a Long Post ;-) )
Version 1 : Original Answer
$cards = @()
$cards += ,'Blue' * 5
$cards += ,'Red' * 5
$cards += ,'Yellow' * 5
$cards += ,'Green' * 5
$r = new-object random
$script:Deck = [System.Collections.Queue]($cards | % { $in = $_; 1 | select @{n='Card';e={$in}},@{n='val';e={$r.Next()}} } | sort val)
$count = 0
$correct = 0
while ($script:deck.count -gt 0) {
$count += 1
$color = Read-Host "Please, predict the next color"
$card = $script:Deck.Dequeue().card
write-host -fore $card $card
if ($card.StartsWith($color.Substring(0,1).toUpper())) {
$correct += 1
}
"$correct correct out of $count tries"
}
"ESP stest is over, results of the test :"
if ( $correct -gt 5 ) {"you have ESP"} Else {"you have no ESP"}
I think there are 3 interesting things to note here the way I create the list of cards, how I Randomize it and how I cast it into a Queue
As I did a post about Randomizing a list before on my old blog : PowerShell : How Do I randomize a list, and remove some elements ?, this part was very easy,
b.t.w I did not use the solution I made there but the one Lee Holmes did provide in the comments of that post
Here's one way to randomize a list -- favoured by Donald Knuth (the computer scientist famed for writing lots of hard-core books:)
1) Run through a list, assigning a random number to each element in the list.
2) Sort by that random number
3) The original numbers are now randomized.
PS >$r = new-object Random
PS >1..10 | % { $in = $_; 1 | select @{n='num';e={$in}},@{n='val';e={$r.Next()}} } | sort val
Version 2 : Alternate way using Windows Forms
I Used a Windows Form here to make a GUI :
It has 4 buttons to Choose a color,
* Note * I also added some Gimmics as 2 Processbars and a FileMenu to show some more possibilities of using Windows forms so the script might look a bit big, but as you go trough it you will see that it's actualy very simple
The Script looks like this :
# Name: test-EspForm
#
# Author: /\/\o\/\/ ( http:\\thePowerShellGuy.com )
# Created: 02/13/2007
#
# Description: A Color Guess Game using Windows Forms
# load Forms NameSpace
[void][System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms")
# Make the form
$form = new-object Windows.Forms.form
$form.Size = new-object System.Drawing.Size @(480,380)
$form.text = "/\/\o\/\/'s PowerShell EPS Tester"
$MainMenu = new-object System.Windows.Forms.MenuStrip
$FileMenu = new-object System.Windows.Forms.ToolStripMenuItem('&File')
$miNew = new-object System.Windows.Forms.ToolStripMenuItem('&New')
$miQuit = new-object System.Windows.Forms.ToolStripMenuItem('&quit')
[void]$MainMenu.Items.Add($FileMenu)
[void]$fileMenu.DropDownItems.Add($miNew)
[void]$fileMenu.DropDownItems.Add($miQuit)
$miQuit.add_Click({$form.close()})
$miNew.add_Click({StartGame})
$form.Controls.Add($MainMenu)
$EspMeter = new-Object System.Windows.Forms.ToolStripProgressBar
$EspMeter.Maximum = 20
$EspMeter.size = new-object System.Drawing.Size @(200,16)
$EspMeter.Alignment = 'Right'
$EspMeter.Padding = New-Object System.Windows.Forms.Padding(0,0,20,0)
$EspMeter.ForeColor = 'Red'
[void]$MainMenu.Items.Add($EspMeter)
$EspLabel = New-Object System.Windows.Forms.ToolSTripStatusLabel
$EspLabel.Alignment = 'Right'
$EspLabel.Text = "ESP Level : "
[void]$MainMenu.Items.Add($EspLabel)
$statusStrip = new-object System.Windows.Forms.StatusStrip
$CardMeter = new-Object System.Windows.Forms.ToolStripProgressBar
$CardMeter.Maximum = 20
$CardMeter.size = new-object System.Drawing.Size @(200,16)
$CardMeter.Padding = New-Object System.Windows.Forms.Padding(20,0,0,0)
[void]$statusStrip.Items.Add($CardMeter)
$label = New-Object System.Windows.Forms.ToolSTripStatusLabel
$label.Text = "New Game"
[void]$statusStrip.Items.Add($Label)
$form.Controls.Add($statusStrip)
$btnGuess = new-object System.Windows.Forms.Button
$btnGuess.Text = 'Your Guess'
$btnActual = new-object System.Windows.Forms.Button
$btnActual.Text = 'Actual'
$btnBlue = new-object System.Windows.Forms.Button
$btnGreen = new-object System.Windows.Forms.Button
$btnRed = new-object System.Windows.Forms.Button
$btnYellow = new-object System.Windows.Forms.Button
$btnGuess.Location = new-object System.Drawing.Size(10,30)
$btnGuess.size = new-object System.Drawing.Size(200,240)
$btnActual.Location = new-object System.Drawing.Size(220,30)
$btnActual.size = new-object System.Drawing.Size(200,240)
$btnBlue.Location = new-object System.Drawing.Size(10,290)
$btnBlue.BackColor = 'Blue'
$btnGreen.Location = new-object System.Drawing.Size(120,290)
$btnGreen.BackColor = 'Green'
$btnRed.Location = new-object System.Drawing.Size(235,290)
$btnRed.BackColor = 'Red'
$btnYellow.Location = new-object System.Drawing.Size(345,290)
$btnYellow.BackColor = 'Yellow'
$btnBlue.add_Click({ClearGuess;$btnGuess.BackColor = 'Blue';DoTurn})
$btnGreen.add_Click({ClearGuess;$btnGuess.BackColor = 'Green';DoTurn})
$btnRed.add_Click({ClearGuess;$btnGuess.BackColor = 'Red';DoTurn})
$btnYellow.add_Click({ClearGuess;$btnGuess.BackColor = 'Yellow';DoTurn})
$form.Controls.Add($btnGuess )
$form.Controls.Add($btnActual )
$form.Controls.Add($btnBlue )
$form.Controls.Add($btnGreen )
$form.Controls.Add($btnRed )
$form.Controls.Add($btnYellow )
Function ClearGuess {
$btnGuess.BackColor = 'Control';$btnGuess.Update()
Sleep -m 100
}
Function ClearActual {
$btnActual.BackColor = 'Control';$btnActual.Update()
Sleep -m 200
}
Function DoTurn {
If ($deck.count -gt 0 ) {
$btnGuess.Update()
ClearActual
$btnActual.BackColor = $Deck.Dequeue().card
$CardMeter.Value = $deck.count
if ( $btnActual.BackColor -eq $btnGuess.BackColor ) {
1..3 |% {
$form.backColor = $btnActual.BackColor
$form.Update();sleep -m 50
$form.backColor = 'Control'
$form.Update();sleep -m 30
}
$script:Correct += 1
$EspMeter.Value = $script:Correct
If ($script:Correct -gt 5) {$EspMeter.BackColor = 'Yellow'}
}
$label.Text = "$($deck.count) Cards Left , Guessed correct $script:Correct"
if ($deck.count -eq 0){DoTurn}
} else {
Write-Host "`a"
$label.Text = "Game Over !, Guessed correct $script:Correct of 20,"
If ($script:Correct -gt 5 ) {$label.Text += " You have ESP !"}
Else {$label.Text += " Sorry you have no ESP"}
}
}
Function GetNewDeck {
$cards = ,'Blue' * 5
$cards += ,'Red' * 5
$cards += ,'yellow' * 5
$cards += ,'Green' * 5
$r = new-object random
$Deck = [System.Collections.Queue]($cards | % { $in = $_; 1 | select @{n='Card';e={$in}},@{n='val';e={$r.Next()}} } | sort val)
,$deck
}
Function StartGame {
$Script:Correct = 0
$Script:deck = GetNewDeck
$label.Text = "New Game"
$EspMeter.Value = 0
$CardMeter.Value = 0
$EspMeter.BackColor = 'Control'
ClearGuess
ClearActual
}
StartGame
$Form.Add_Shown({$form.Activate()})
[void]$form.showdialog()
Version 3 : Alternate way using the PowerShell console RawUI to Paint the GUI
This version uses $host.UI.rawUI to draw the GUI on the PowerShell console
PowerShell ESP Tester
/\/\o\/\/ 2007
Wrong Guess | 4 correct out of 13 tries | 7 Cards left
http://thePowerShellGuy.com
Pick a Color : [B] Blue [R] Red [Y] Yellow [G] Green [Q] Quit
PoSH> .\RawEsp.ps1
PoSH>
And Cleaning up :
PoSH> .\RawEsp.ps1
ESP test is over.
results of the test :
5 correct out of 20 tries
you have no ESP
PoSH> .\RawEsp.ps1
ESP test is over.
results of the test :
6 correct out of 20 tries
you have ESP
PoSH>
Note that I save the current contents of the buffer, to not mess up the Console.
And this script looks like this :
# Name: test-EspRawUI
#
# Author: /\/\o\/\/ ( http:\\thePowerShellGuy.com )
# Created: 02/14/2007
#
# Description: A Color Guess Game using RawUI
# save old Buffer contents to restore Later
$raw = $host.ui.rawui
$pos = $raw.windowposition
$size = $raw.buffersize
$rect = "system.management.automation.host.rectangle"
$posOld = $pos
$re = new-object $rect $pos.x,$pos.y,$size.width,($pos.y + 25)
$buffer = $raw.getbuffercontents($re)
# Helper functions
Function ColorLine ($x,$y,$l,[system.consolecolor]$bgc) {
$pos = $host.ui.RawUI.WindowPosition
$pos.x += $x
$pos.y += $y
$row = $host.ui.rawui.NewBufferCellArray((' ' * $l),$bgc,$bgc)
$host.ui.rawui.SetBufferContents($pos,$row)
}
Function WriteLine ($x,$y,$Text,[system.consolecolor]$fgc,[system.consolecolor]$bgc) {
$pos = $host.ui.RawUI.WindowPosition
$pos.x += $x
$pos.y += $y
$row = $host.ui.rawui.NewBufferCellArray($text,$fgc,$bgc)
$host.ui.rawui.SetBufferContents($pos,$row)
}
# Make PlayField :
ColorLine 0 0 ( $host.ui.rawui.WindowSize.Width -1 ) 'Yellow'
WriteLine 2 0 'PowerShell ESP Tester' 'Black' 'Yellow'
ColorLine 0 1 ( $host.ui.rawui.WindowSize.Width -1 ) 'DarkBlue'
WriteLine ($host.ui.rawui.WindowSize.Width - 16 ) 1 '/\/\o\/\/ 2007' 'Yellow' 'darkBlue'
ColorLine 0 24 ( $host.ui.rawui.WindowSize.Width -1 ) 'DarkBlue'
WriteLine ($host.ui.rawui.WindowSize.Width - 29 ) 24 'http://thePowerShellGuy.com' 'Yellow' 'darkBlue'
2..23 |% {ColorLine 0 $_ ( $host.ui.rawui.WindowSize.Width -1 ) 'DarkGray'}
3..20 |% {ColorLine 1 $_ 20 'Gray'}
3..20 |% {ColorLine 25 $_ 20 'Gray'}
ColorLine 1 22 ( $host.ui.rawui.WindowSize.Width - 3 ) 'DarkRed'
WriteLine 3 22 "New Game !, $($deck.count) Cards left" 'White' 'DarkRed'
ColorLine 0 25 ( $host.ui.rawui.WindowSize.Width -1 ) 'Yellow'
WriteLine 2 25 'Pick a Color : [B] Blue [R] Red [Y] Yellow [G] Green [Q] Quit ' 'Black' 'Yellow'
# Create Deck
$cards = @()
$cards += ,'Blue' * 5
$cards += ,'Red' * 5
$cards += ,'Yellow' * 5
$cards += ,'Green' * 5
$r = new-object random
$script:Deck = [System.Collections.Queue]($cards | % { $in = $_; 1 | select @{n='Card';e={$in}},@{n='val';e={$r.Next()}} } | sort val)
# Start Game
$count = 0
$correct = 0
while ($script:deck.count -gt 0) {
$count += 1
$key = $host.ui.RawUI.ReadKey('NoEcho,IncludeKeyUp')
$Color = [string]$key.Character
$KeyValid = $true
Switch ($Color){
'b' {3..20 |% {ColorLine 1 $_ 20 'Blue'}}
'r' {3..20 |% {ColorLine 1 $_ 20 'Red'}}
'y' {3..20 |% {ColorLine 1 $_ 20 'Yellow'}}
'g' {3..20 |% {ColorLine 1 $_ 20 'Green'}}
'q' {
$host.ui.rawui.SetBufferContents($posOld,$buffer)
Write-Warning "Quit Choosen, no TestResults "
return
}
Default {write-host -no "`a";$KeyValid = $False}
}
if ($KeyValid) {
$card = $script:Deck.Dequeue().card
3..20 |% {ColorLine 25 $_ 20 $card}
ColorLine 1 22 ( $host.ui.rawui.WindowSize.Width -3 ) 'DarkRed'
if ($card.StartsWith($color.toUpper())) {
$correct += 1
WriteLine 3 22 "Right Guess" 'Green' 'DarkRed'
} Else {
WriteLine 3 22 "Wrong Guess" 'Red' 'DarkRed'
}
WriteLine 14 22 " | $correct correct out of $count tries | $($deck.count) Cards left" 'White' 'DarkRed'
}
}
# Clean up by restoring old Buffer Data and Guve Results
$host.ui.rawui.SetBufferContents($posOld,$buffer)
"ESP test is over."
"results of the test :"
"$correct correct out of $count tries"
if ( $correct -gt 5 ) {"you have ESP"} Else {"you have no ESP"}
And this ends the Scripting games hope you liked it, and till next Year !
Enjoy,
Greetings /\/\o\/\/