Start-1to100Game3.0.ps1

<#PSScriptInfo
.DESCRIPTION
    This game is between a user and the computer, where the user tries to determine the number the computer has randomly chosen by using clues.
 
.VERSION
    3.0
 
.GUID
    1d4c86bf-1dab-44e8-afc4-4a4e28577e20
 
.AUTHOR
    Tommy Maynard @thetommymaynard
 
.COMPANYNAME
 
.COPYRIGHT
 
.TAGS
 
.LICENSEURI
 
.PROJECTURI
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
#>


Function Start-1to100Game {
<#
.SYNOPSIS
    This game is between a user and the computer, where the user tries to determine the number the computer has randomly chosen by using clues.
 
.DESCRIPTION
    The computer chooses a random number between 1 and 100, by default, and the user has to attempt to guess the number. After each guess, the computer will indicate whether the user should choose a higher lower number on their next guess.
 
.NOTES
    Name: Start-1to100Game
    Author: Tommy Maynard
    Comments:
    Last Edit: 07/03/2014 [1.1], 08/01/2014 [2.0], 12/15/2016 [3.0]
    Version 1.1
        - Added replay option (Version 1.1 is first version uploaded to TechNet Gallery)
    Version 2.0
        - Made script an advanced function
        - Removed clearing of variables (unneeded since it's a function)
        - Changed how to quit: Yes and No vs. Replay and Quit (Y and N vs. R and Q)
        - Added 3rd nested Do-While so that only R and Q can be entered (in the past, if something else was entered the game would start again)
        - Added average number of attempts per game (uses formatting to only return 2 decimal places)
    Version 3.0
        - Added the ability to choose minimum and maximum numbers: The number no longer *has* to be 1 and 100.
        - Results are outputted to a formatted table; it's rebuilt after each attempt to solve.
        - All game stats are not included unless the ShowTotals switch parameter is included.
        - Game title, that shows on first game, includes dynamic number of asterisks, and includes the minimum and maximum numbers: 1 and 100, 1 and 10, 20 and 40, etc.
        - Added OutVariable parameter to Read-Host to collect the value of a "bad entry," such as a letter, special character, etc. Read-Host is cast as [int].
#>

    [CmdletBinding()]
    Param (
        [Parameter(Position=0)]
        [int]$Minimum = 1,

        [Parameter(Position=1)]
        [int]$Maximum = 100,

        [Parameter()]
        [switch]$ShowTotals
    )

    Begin {
        $Continue = $true
        If (($Minimum -gt $Maximum) -or ($Minimum -eq $Maximum)) {
            Write-Error -Exception "The Minimum value ($Minimum) cannot be greater than, or equal to, the Maximum value ($Maximum)."
            $Continue = $false
        }
    } # End Begin

    Process {
        If ($Continue) {
            # Display game title.
            $Title = "The $Minimum to $Maximum Game"
            "$('*' * $Title.Length)`r`n$Title`r`n$('*' * $Title.Length)"
  
            $Plays = 0
            If ($ShowTotals) {$ObjectTotal = @()}

            Do { # Get computer's number and set attempts.
                $CompNumber = Get-Random -Minimum $Minimum -Maximum ($Maximum + 1)
                $Attempts = 0

                $Object = @()
                $InGameAttempt = 1
                Do { # Begin game.
                    try {
                        Remove-Variable -Name FailedUserNumber -ErrorAction SilentlyContinue
                        [int]$UserNumber = Read-Host -Prompt "Enter a number from $Minimum to $Maximum" -OutVariable FailedUserNumber
                        If ($UserNumber -gt ($Minimum - 1) -and $UserNumber -lt ($Maximum + 1)) {

                            # Lower.
                            If ($UserNumber -gt $CompNumber) {
                                $Object += [PSCustomObject]@{
                                    Attempt = $InGameAttempt ++
                                    UserNumber = $UserNumber
                                    Message = 'Lower'
                                }
                                $Object | Format-Table -AutoSize

                            # Higher.
                            } ElseIf ($UserNumber -lt $CompNumber) {
                                $Object += [PSCustomObject]@{
                                    Attempt = $InGameAttempt ++
                                    UserNumber = $UserNumber
                                    Message = 'Higher'
                                }
                                $Object | Format-Table -AutoSize

                            # Winner.
                            } Else {
                                $Object += [PSCustomObject]@{
                                    Attempt = $InGameAttempt ++
                                    UserNumber = $UserNumber
                                    Message = 'Winner'
                                }
                                $Object | Format-Table -AutoSize
                                $Winner = $true
                            }

                        # Too High.
                        } ElseIf ($UserNumber -gt $Maximum) {
                            $Object += [PSCustomObject]@{
                                Attempt = $InGameAttempt ++
                                UserNumber = $UserNumber
                                Message = 'Too High'
                            }
                            $Object  | Format-Table -AutoSize

                        # Too Low.
                        } ElseIf ($UserNumber -lt $Minimum) {
                            $Object += [PSCustomObject]@{
                                Attempt = $InGameAttempt ++
                                UserNumber = $UserNumber
                                Message = 'Too Low'
                            }
                            $Object | Format-Table -AutoSize
                        }
                    }
                    catch {
                        # Not an integer.
                        $Object += [PSCustomObject]@{
                            Attempt = $InGameAttempt ++
                            UserNumber = [string]$FailedUserNumber
                            Message = 'Bad entry'
                        }
                        $Object | Format-Table -AutoSize
                    }

                    $Attempts += 1
                }
                Until ($UserNumber -eq $CompNumber)

                ##### Display Winning Results
                If ($Winner) {
                    
                    If ($ShowTotals) {
                        # Complete total calculations.
                        $Plays += 1
                        $TotalAttempts += $Attempts
                        If ($TotalAttempts % $Plays -eq 0) {
                            $AveragePerAttempt = $TotalAttempts / $Plays

                        } Else {
                            $AveragePerAttempt = '{0:N2}' -f ($TotalAttempts / $Plays)
                        }
                    
                        # Create total calculations object.
                        $ObjectTotal += [PSCustomObject]@{
                            Game = $Plays
                            MatchNumber = "$CompNumber <--> $UserNumber"
                            CompNumber = $CompNumber
                            UserFinalNumber = $UserNumber
                            Attempts = $Attempts
                            TotalAttempts = $TotalAttempts
                            AverageAttempts = $AveragePerAttempt
                        }
                        $ObjectTotal | Format-Table -AutoSize -Property Game,MatchNumber,Attempts,TotalAttempts,AverageAttempts
                    }

                    # Prompt to play again.
                    Do {
                        $Replay = Read-Host -Prompt '(R)eplay or (Q)uit'
                    }
                    Until ($Replay -eq 'R' -or $Replay -eq 'Q')

                } # End If ($Winner).
            } Until ($Replay -eq 'Q')
        } # End If ($Continue).
    } # End Process

    End {
    } # End End.
} # End Function: Start-to1to100Game.