
Usando o pipeline no Powershell
O algoritmo é simples, o primeiro é o gerador de porta aleatória, depois o gerador de escolha do usuário, depois a lógica de abertura da porta do apresentador, outra ação do usuário e contagem de estatísticas.
E a ferramenta nos ajudará com isso
ValueFromPipeline
, o que nos permite especificar o cmdlet um a um, transformando o objeto passo a passo. É assim que nosso pipeline deve ser:
New-Doors | Select-Door | Open-Door | Invoke-UserAction
New-Doors
gera novas portas, na equipa o
Select-Door
jogador escolhe uma das portas, o
Open-Door
líder abre a porta em que definitivamente não há cabra e que não foi escolhida pelo jogador, e
Invoke-UserAction
aí simulamos diferentes comportamentos do utilizador.
O objeto que descreve a porta se move da esquerda para a direita, transformando-se gradualmente.
Esse método de escrever código ajuda a mantê-lo em pedaços com divisões claras de responsabilidade.
O Powershell tem suas próprias convenções. Incluindo as convenções sobre a nomenclatura correta das funções , elas também precisam ser observadas e quase as cumprimos.
Fazendo portas
Como vamos simular a situação, também descreveremos em detalhes as portas.
A porta contém uma cabra ou um carro. A porta pode ser escolhida pelo jogador ou aberta pelo anfitrião.
class Door {
<#
, .
.
#>
[string]$Contains = "Goat"
[bool]$Selected = $false
[bool]$Opened = $false
}
Colocaremos cada uma das portas em um campo separado em uma classe separada.
class Doors {
<#
, 3
#>
[Door]$DoorOne
[Door]$DoorTwo
[Door]$DoorThree
}
Foi possível colocar todas as portas em uma matriz, mas quanto mais detalhado tudo for descrito, melhor. A propósito, no Powershell 7, classes, seus construtores, métodos e tudo o mais é OOP, que funciona quase como deveria, mas mais nisso em outra ocasião.
O gerador de porta aleatória se parece com isso. Primeiro, para cada batente de porta, sua própria porta é gerada, e então o gerador escolhe em qual delas o carro ficará.
function New-Doors {
<#
.
#>
$i = [Doors]::new()
$i.DoorOne = [Door]::new()
$i.DoorTwo = [Door]::new()
$i.DoorThree = [Door]::new()
switch ( Get-Random -Maximum 3 -Minimum 0 ) {
0 {
$i.DoorOne.Contains = "Car"
}
1 {
$i.DoorTwo.Contains = "Car"
}
2 {
$i.DoorThree.Contains = "Car"
}
Default {
Write-Error "Something in door generator went wrong"
break
}
}
return $i
Nosso cachimbo se parece com isto:
New-Doors
O jogador escolhe a porta
Agora vamos descrever a escolha inicial. O jogador pode escolher uma das três portas. Com o propósito de simular mais situações, deixe o jogador escolher apenas a primeira, apenas a segunda, apenas a terceira e porta aleatória de cada vez.
[Parameter(Mandatory)]
[ValidateSet("First", "Second", "Third", "Random")]
$Principle
Para aceitar argumentos do pipeline, você precisa especificar uma variável no bloco de parâmetros que fará isso. Isso é feito assim:
[parameter(ValueFromPipeline)]
[Doors]$i
Você pode escrever
ValueFromPipeline
sem
True
.
Esta é a aparência do bloco de seleção de porta acabado:
function Select-Door {
<#
.
#>
Param (
[parameter(ValueFromPipeline)]
[Doors]$i,
[Parameter(Mandatory)]
[ValidateSet("First", "Second", "Third", "Random")]
$Principle
)
switch ($Principle) {
"First" {
$i.DoorOne.Selected = $true
}
"Second" {
$i.DoorTwo.Selected = $true
}
"Third" {
$i.DoorThree.Selected = $true
}
"Random" {
switch ( Get-Random -Maximum 3 -Minimum 0 ) {
0 {
$i.DoorOne.Selected = $true
}
1 {
$i.DoorTwo.Selected = $true
}
2 {
$i.DoorThree.Selected = $true
}
Default {
Write-Error "Something in door selector went wrong"
break
}
}
}
Default {
Write-Error "Something in door selector went wrong"
break
}
}
return $i
Nosso cachimbo se parece com isto:
New-Doors | Select-Door -Principle Random
Liderando abre a porta
Tudo é muito simples aqui. Se a porta não foi escolhida pelo jogador e se houver uma cabra atrás dela, altere o campo
Opened
para
True
. Especificamente, neste caso, não é
Open
correto nomear o comando com uma palavra , o recurso chamado não é lido, mas alterado. Nesses casos, use
Set
, mas
Open
deixe para maior clareza.
function Open-Door {
<#
, , .
#>
Param (
[parameter(ValueFromPipeline)]
[Doors]$i
)
switch ($false) {
$i.DoorOne.Selected {
if ($i.DoorOne.Contains -eq "Goat") {
$i.DoorOne.Opened = $true
continue
}
}
$i.DoorTwo.Selected {
if ($i.DoorTwo.Contains -eq "Goat") {
$i.DoorTwo.Opened = $true
continue
}
}
$i.DoorThree.Selected {
if ($i.DoorThree.Contains -eq "Goat") {
$i.DoorThree.Opened = $true
continue
}
}
}
return $i
Para tornar nossa simulação mais convincente, "abrimos" essa porta alterando o campo .opened para, em
$true
vez de remover o objeto da matriz da porta.
Não se esqueça dos
continue
interruptores, a comparação não termina após a primeira partida.
Coninue
sai do switch e continua a executar o script, e o operador
break
no switch encerra o script.
Adicione mais uma função ao tubo, agora se parece com isto:
New-Doors | Select-Door -Principle Random | Open-Door
O jogador muda sua escolha
O jogador muda a porta ou não a muda. No bloco de parâmetros, temos apenas uma variável do tubo e um argumento booleano.
Use a palavra
Invoke
nos nomes dessas funções, pois
Invoke
significa chamar uma operação síncrona, e
Start
assíncrona, siga as convenções e recomendações.
function Invoke-UserAction {
<#
, .
#>
Param (
[parameter(ValueFromPipeline)]
[Doors]$i,
[Parameter(Mandatory)]
[bool]$SwitchDoor
)
if ($true -eq $SwitchDoor) {
switch ($false) {
$i.DoorOne.Opened {
if ( $i.DoorOne.Selected ) {
$i.DoorOne.Selected = $false
}
else {
$i.DoorOne.Selected = $true
}
}
$i.DoorTwo.Opened {
if ( $i.DoorTwo.Selected ) {
$i.DoorTwo.Selected = $false
}
else {
$i.DoorTwo.Selected = $true
}
}
$i.DoorThree.Opened {
if ( $i.DoorThree.Selected ) {
$i.DoorThree.Selected = $false
}
else {
$i.DoorThree.Selected = $true
}
}
}
}
return $i
Nos operadores de ramificação e comparação, você deve primeiro especificar o sistema e as variáveis estáticas. Provavelmente, pode haver dificuldade em converter um objeto em outro, mas o autor não encontrou essas dificuldades quando escreveu de uma maneira diferente antes.
Outra função no pipeline.
New-Doors | Select-Door -Principle Random | Open-Door | Invoke-UserAction -SwitchDoor $True
A vantagem dessa abordagem de escrita é clara, porque nunca foi tão conveniente dividir o código em partes com uma separação clara de funções.
Comportamento do jogador
Quantas vezes o jogador muda a porta. Existem 5 linhas de comportamento:
Never
- o jogador nunca muda sua escolhaFifty-Fifty
- 50 a 50. O número de simulações é dividido em duas passagens. Na primeira passagem o jogador não muda a porta, na segunda passagem muda.Random
- em cada nova simulação, o jogador joga uma moedaAlways
- o jogador sempre muda sua escolha.Ration
- o jogador muda sua escolha em N% dos casos.
switch ($SwitchDoors) {
"Never" {
0..$Count | ForEach-Object {
$Win += Invoke-Simulation -Door $Door -SwitchDoors $false
}
continue
}
"FiftyFifty" {
$Fifty = [math]::Round($Count / 2)
0..$Fifty | ForEach-Object {
$Win += Invoke-Simulation -Door $Door -SwitchDoors $false
}
0..$Fifty | ForEach-Object {
$Win += Invoke-Simulation -Door $Door -SwitchDoors $true
}
continue
}
"Random" {
0..$Count | ForEach-Object {
[bool]$Random = Get-Random -Maximum 2 -Minimum 0
$Win += Invoke-Simulation -Door $Door -SwitchDoors $Random
}
continue
}
"Always" {
0..$Count | ForEach-Object {
$Win += Invoke-Simulation -Door $Door -SwitchDoors $true
}
continue
}
"Ratio" {
$TrueRatio = $Ratio / 100 * $Count
$FalseRatio = $Count - $TrueRatio
0..$TrueRatio | ForEach-Object {
$Win += Invoke-Simulation -Door $Door -SwitchDoors $true
}
0..$FalseRatio | ForEach-Object {
$Win += Invoke-Simulation -Door $Door -SwitchDoors $false
}
continue
}
}
ForEach-Object
no Powershell 7 ele funciona muito mais rápido do que um loop
for
, além de poder ser paralelizado, então é usado aqui ao invés de um loop
for
.
Estilizando o cmdlet
Agora você precisa corrigir o cmdlet. Primeiro de tudo, você precisa fazer a validação dos argumentos recebidos. O bônus não é apenas que uma pessoa não pode inserir um argumento inválido no campo, mas também uma lista de todos os argumentos disponíveis aparece nos prompts.
É assim que o código no bloco de parâmetros se parece:
param (
[Parameter(Mandatory = $false,
HelpMessage = "How often the player changes his choice.")]
[ValidateSet("Never", "FiftyFifty", "Random", "Always", "Ratio")]
$SwitchDoors = "Random"
)
Esta é a dica:

Antes que o bloco de parâmetros possa ser feito
comment based help
. Esta é a aparência do código antes do bloco de parâmetros:
<#
.SYNOPSIS
Performs monty hall paradox simulation.
.DESCRIPTION
The Invoke-MontyHallParadox.ps1 script invoke monty hall paradox simulation.
.PARAMETER Door
Specifies door the player will choose during the entire simulation
.PARAMETER SwitchDoors
Specifies principle how the player changes his choice.
.PARAMETER Count
Specifies how many times to run the simulation.
.PARAMETER Ratio
If -SwitchDoors Ratio, specifies how often the player changes his choice. As a percentage."
.INPUTS
None. You cannot pipe objects to Update-Month.ps1.
.OUTPUTS
None. Update-Month.ps1 does not generate any output.
.EXAMPLE
PS> Invoke-MontyHallParadox -SwitchDoors Always -Count 10000
#>
Esta é a aparência do prompt:

Executando a simulação
Resultados simulados:

Se uma pessoa nunca muda sua escolha, ela ganha 33,37% das vezes.
No caso de dois passes, em que na metade nos recusamos a mudar de escolha, as chances de vitória são de 49,9134%, o que é muito próximo de exatamente 50%.
No caso de sorteio, nada muda, a chance de vitória fica em torno de 50,131%.
Pois bem, se o jogador sempre muda sua escolha, a chance de ganhar sobe para 66,6184%, ou seja, chata e nada de novo.
Desempenho:
Em termos de desempenho. O script não parece ser o ideal.
String
em vez disso
Bool
, muitas funções diferentes com um switch dentro, passando um objeto para o outro, mas, no entanto, aqui estão os resultados
Measure-Command
para este script e um script de outro autor .
A comparação foi realizada em dois sistemas, o pwsh 7.1 estava em todos os lugares, 100.000 passes.
▍I5-5200u
Este algoritmo:
Days : 0 Hours : 0 Minutes : 0 Seconds : 4 Milliseconds : 581 Ticks : 45811819 TotalDays : 5,30229386574074E-05 TotalHours : 0,00127255052777778 TotalMinutes : 0,0763530316666667 TotalSeconds : 4,5811819 TotalMilliseconds : 4581,1819
Esse algoritmo:
Days : 0 Hours : 0 Minutes : 0 Seconds : 5 Milliseconds : 104 Ticks : 51048392 TotalDays : 5,9083787037037E-05 TotalHours : 0,00141801088888889 TotalMinutes : 0,0850806533333333 TotalSeconds : 5,1048392 TotalMilliseconds : 5104,8392
▍I9-9900K
Este algoritmo:
Days : 0 Hours : 0 Minutes : 0 Seconds : 1 Milliseconds : 891 Ticks : 18917629 TotalDays : 2,18954039351852E-05 TotalHours : 0,000525489694444444 TotalMinutes : 0,0315293816666667 TotalSeconds : 1,8917629 TotalMilliseconds : 1891,7629
Esse algoritmo:
Days : 0 Hours : 0 Minutes : 0 Seconds : 1 Milliseconds : 954 Ticks : 19543236 TotalDays : 2,26194861111111E-05 TotalHours : 0,000542867666666667 TotalMinutes : 0,03257206 TotalSeconds : 1,9543236 TotalMilliseconds : 1954,3236
Vantagem de 63 ms, mas os resultados ainda são muito estranhos considerando quantas vezes o script compara strings.
O autor espera que este artigo sirva como um exemplo convincente para aqueles que acreditam que as probabilidades são sempre de 50 a 50, mas você pode ler o código neste spoiler.
Todo o código
class Doors {
<#
, 3
#>
[Door]$DoorOne
[Door]$DoorTwo
[Door]$DoorThree
}
class Door {
<#
, .
.
#>
[string]$Contains = «Goat»
[bool]$Selected = $false
[bool]$Opened = $false
}
function New-Doors {
<#
.
#>
$i = [Doors]::new()
$i.DoorOne = [Door]::new()
$i.DoorTwo = [Door]::new()
$i.DoorThree = [Door]::new()
switch ( Get-Random -Maximum 3 -Minimum 0 ) {
0 {
$i.DoorOne.Contains = «Car»
}
1 {
$i.DoorTwo.Contains = «Car»
}
2 {
$i.DoorThree.Contains = «Car»
}
Default {
Write-Error «Something in door generator went wrong»
break
}
}
return $i
}
function Select-Door {
<#
.
#>
Param (
[parameter(ValueFromPipeline)]
[Doors]$i,
[Parameter(Mandatory)]
[ValidateSet(«First», «Second», «Third», «Random»)]
$Principle
)
switch ($Principle) {
«First» {
$i.DoorOne.Selected = $true
continue
}
«Second» {
$i.DoorTwo.Selected = $true
continue
}
«Third» {
$i.DoorThree.Selected = $true
continue
}
«Random» {
switch ( Get-Random -Maximum 3 -Minimum 0 ) {
0 {
$i.DoorOne.Selected = $true
continue
}
1 {
$i.DoorTwo.Selected = $true
continue
}
2 {
$i.DoorThree.Selected = $true
continue
}
Default {
Write-Error «Something in selector generator went wrong»
break
}
}
continue
}
Default {
Write-Error «Something in door selector went wrong»
break
}
}
return $i
}
function Open-Door {
<#
, , .
#>
Param (
[parameter(ValueFromPipeline)]
[Doors]$i
)
switch ($false) {
$i.DoorOne.Selected {
if ($i.DoorOne.Contains -eq «Goat») {
$i.DoorOne.Opened = $true
continue
}
}
$i.DoorTwo.Selected {
if ($i.DoorTwo.Contains -eq «Goat») {
$i.DoorTwo.Opened = $true
continue
}
}
$i.DoorThree.Selected {
if ($i.DoorThree.Contains -eq «Goat») {
$i.DoorThree.Opened = $true
continue
}
}
}
return $i
}
function Invoke-UserAction {
<#
, .
#>
Param (
[parameter(ValueFromPipeline)]
[Doors]$i,
[Parameter(Mandatory)]
[bool]$SwitchDoor
)
if ($true -eq $SwitchDoor) {
switch ($false) {
$i.DoorOne.Opened {
if ( $i.DoorOne.Selected ) {
$i.DoorOne.Selected = $false
}
else {
$i.DoorOne.Selected = $true
}
}
$i.DoorTwo.Opened {
if ( $i.DoorTwo.Selected ) {
$i.DoorTwo.Selected = $false
}
else {
$i.DoorTwo.Selected = $true
}
}
$i.DoorThree.Opened {
if ( $i.DoorThree.Selected ) {
$i.DoorThree.Selected = $false
}
else {
$i.DoorThree.Selected = $true
}
}
}
}
return $i
}
function Get-Win {
Param (
[parameter(ValueFromPipeline)]
[Doors]$i
)
switch ($true) {
($i.DoorOne.Selected -and $i.DoorOne.Contains -eq «Car») {
return $true
}
($i.DoorTwo.Selected -and $i.DoorTwo.Contains -eq «Car») {
return $true
}
($i.DoorThree.Selected -and $i.DoorThree.Contains -eq «Car») {
return $true
}
default {
return $false
}
}
}
function Invoke-Simulation {
param (
[Parameter(Mandatory = $false,
HelpMessage = «Which door the player will choose during the entire simulation.»)]
[ValidateSet(«First», «Second», «Third», «Random»)]
$Door = «Random»,
[bool]$SwitchDoors
)
return New-Doors | Select-Door -Principle $Door | Open-Door | Invoke-UserAction -SwitchDoor $SwitchDoors | Get-Win
}
function Invoke-MontyHallParadox {
<#
.SYNOPSIS
Performs monty hall paradox simulation.
.DESCRIPTION
The Invoke-MontyHallParadox.ps1 script invoke monty hall paradox simulation.
.PARAMETER Door
Specifies door the player will choose during the entire simulation
.PARAMETER SwitchDoors
Specifies principle how the player changes his choice.
.PARAMETER Count
Specifies how many times to run the simulation.
.PARAMETER Ratio
If -SwitchDoors Ratio, specifies how often the player changes his choice. As a percentage."
.INPUTS
None. You cannot pipe objects to Update-Month.ps1.
.OUTPUTS
None. Update-Month.ps1 does not generate any output.
.EXAMPLE
PS> Invoke-MontyHallParadox -SwitchDoors Always -Count 10000
#>
param (
[Parameter(Mandatory = $false,
HelpMessage = «Which door the player will choose during the entire simulation.»)]
[ValidateSet(«First», «Second», «Third», «Random»)]
$Door = «Random»,
[Parameter(Mandatory = $false,
HelpMessage = «How often the player changes his choice.»)]
[ValidateSet(«Never», «FiftyFifty», «Random», «Always», «Ratio»)]
$SwitchDoors = «Random»,
[Parameter(Mandatory = $false,
HelpMessage = «How many times to run the simulation.»)]
[uint32]$Count = 10000,
[Parameter(Mandatory = $false,
HelpMessage = «How often the player changes his choice. As a percentage.»)]
[uint32]$Ratio = 30
)
[uint32]$Win = 0
switch ($SwitchDoors) {
«Never» {
0..$Count | ForEach-Object {
$Win += Invoke-Simulation -Door $Door -SwitchDoors $false
}
continue
}
«FiftyFifty» {
$Fifty = [math]::Round($Count / 2)
0..$Fifty | ForEach-Object {
$Win += Invoke-Simulation -Door $Door -SwitchDoors $false
}
0..$Fifty | ForEach-Object {
$Win += Invoke-Simulation -Door $Door -SwitchDoors $true
}
continue
}
«Random» {
0..$Count | ForEach-Object {
[bool]$Random = Get-Random -Maximum 2 -Minimum 0
$Win += Invoke-Simulation -Door $Door -SwitchDoors $Random
}
continue
}
«Always» {
0..$Count | ForEach-Object {
$Win += Invoke-Simulation -Door $Door -SwitchDoors $true
}
continue
}
«Ratio» {
$TrueRatio = $Ratio / 100 * $Count
$FalseRatio = $Count — $TrueRatio
0..$TrueRatio | ForEach-Object {
$Win += Invoke-Simulation -Door $Door -SwitchDoors $true
}
0..$FalseRatio | ForEach-Object {
$Win += Invoke-Simulation -Door $Door -SwitchDoors $false
}
continue
}
}
Write-Output («Player won in » + $Win + " times out of " + $Count)
Write-Output («Whitch is » + ($Win / $Count * 100) + "%")
return $Win
}
#Invoke-MontyHallParadox -SwitchDoors Always -Count 500000
<#
, 3
#>
[Door]$DoorOne
[Door]$DoorTwo
[Door]$DoorThree
}
class Door {
<#
, .
.
#>
[string]$Contains = «Goat»
[bool]$Selected = $false
[bool]$Opened = $false
}
function New-Doors {
<#
.
#>
$i = [Doors]::new()
$i.DoorOne = [Door]::new()
$i.DoorTwo = [Door]::new()
$i.DoorThree = [Door]::new()
switch ( Get-Random -Maximum 3 -Minimum 0 ) {
0 {
$i.DoorOne.Contains = «Car»
}
1 {
$i.DoorTwo.Contains = «Car»
}
2 {
$i.DoorThree.Contains = «Car»
}
Default {
Write-Error «Something in door generator went wrong»
break
}
}
return $i
}
function Select-Door {
<#
.
#>
Param (
[parameter(ValueFromPipeline)]
[Doors]$i,
[Parameter(Mandatory)]
[ValidateSet(«First», «Second», «Third», «Random»)]
$Principle
)
switch ($Principle) {
«First» {
$i.DoorOne.Selected = $true
continue
}
«Second» {
$i.DoorTwo.Selected = $true
continue
}
«Third» {
$i.DoorThree.Selected = $true
continue
}
«Random» {
switch ( Get-Random -Maximum 3 -Minimum 0 ) {
0 {
$i.DoorOne.Selected = $true
continue
}
1 {
$i.DoorTwo.Selected = $true
continue
}
2 {
$i.DoorThree.Selected = $true
continue
}
Default {
Write-Error «Something in selector generator went wrong»
break
}
}
continue
}
Default {
Write-Error «Something in door selector went wrong»
break
}
}
return $i
}
function Open-Door {
<#
, , .
#>
Param (
[parameter(ValueFromPipeline)]
[Doors]$i
)
switch ($false) {
$i.DoorOne.Selected {
if ($i.DoorOne.Contains -eq «Goat») {
$i.DoorOne.Opened = $true
continue
}
}
$i.DoorTwo.Selected {
if ($i.DoorTwo.Contains -eq «Goat») {
$i.DoorTwo.Opened = $true
continue
}
}
$i.DoorThree.Selected {
if ($i.DoorThree.Contains -eq «Goat») {
$i.DoorThree.Opened = $true
continue
}
}
}
return $i
}
function Invoke-UserAction {
<#
, .
#>
Param (
[parameter(ValueFromPipeline)]
[Doors]$i,
[Parameter(Mandatory)]
[bool]$SwitchDoor
)
if ($true -eq $SwitchDoor) {
switch ($false) {
$i.DoorOne.Opened {
if ( $i.DoorOne.Selected ) {
$i.DoorOne.Selected = $false
}
else {
$i.DoorOne.Selected = $true
}
}
$i.DoorTwo.Opened {
if ( $i.DoorTwo.Selected ) {
$i.DoorTwo.Selected = $false
}
else {
$i.DoorTwo.Selected = $true
}
}
$i.DoorThree.Opened {
if ( $i.DoorThree.Selected ) {
$i.DoorThree.Selected = $false
}
else {
$i.DoorThree.Selected = $true
}
}
}
}
return $i
}
function Get-Win {
Param (
[parameter(ValueFromPipeline)]
[Doors]$i
)
switch ($true) {
($i.DoorOne.Selected -and $i.DoorOne.Contains -eq «Car») {
return $true
}
($i.DoorTwo.Selected -and $i.DoorTwo.Contains -eq «Car») {
return $true
}
($i.DoorThree.Selected -and $i.DoorThree.Contains -eq «Car») {
return $true
}
default {
return $false
}
}
}
function Invoke-Simulation {
param (
[Parameter(Mandatory = $false,
HelpMessage = «Which door the player will choose during the entire simulation.»)]
[ValidateSet(«First», «Second», «Third», «Random»)]
$Door = «Random»,
[bool]$SwitchDoors
)
return New-Doors | Select-Door -Principle $Door | Open-Door | Invoke-UserAction -SwitchDoor $SwitchDoors | Get-Win
}
function Invoke-MontyHallParadox {
<#
.SYNOPSIS
Performs monty hall paradox simulation.
.DESCRIPTION
The Invoke-MontyHallParadox.ps1 script invoke monty hall paradox simulation.
.PARAMETER Door
Specifies door the player will choose during the entire simulation
.PARAMETER SwitchDoors
Specifies principle how the player changes his choice.
.PARAMETER Count
Specifies how many times to run the simulation.
.PARAMETER Ratio
If -SwitchDoors Ratio, specifies how often the player changes his choice. As a percentage."
.INPUTS
None. You cannot pipe objects to Update-Month.ps1.
.OUTPUTS
None. Update-Month.ps1 does not generate any output.
.EXAMPLE
PS> Invoke-MontyHallParadox -SwitchDoors Always -Count 10000
#>
param (
[Parameter(Mandatory = $false,
HelpMessage = «Which door the player will choose during the entire simulation.»)]
[ValidateSet(«First», «Second», «Third», «Random»)]
$Door = «Random»,
[Parameter(Mandatory = $false,
HelpMessage = «How often the player changes his choice.»)]
[ValidateSet(«Never», «FiftyFifty», «Random», «Always», «Ratio»)]
$SwitchDoors = «Random»,
[Parameter(Mandatory = $false,
HelpMessage = «How many times to run the simulation.»)]
[uint32]$Count = 10000,
[Parameter(Mandatory = $false,
HelpMessage = «How often the player changes his choice. As a percentage.»)]
[uint32]$Ratio = 30
)
[uint32]$Win = 0
switch ($SwitchDoors) {
«Never» {
0..$Count | ForEach-Object {
$Win += Invoke-Simulation -Door $Door -SwitchDoors $false
}
continue
}
«FiftyFifty» {
$Fifty = [math]::Round($Count / 2)
0..$Fifty | ForEach-Object {
$Win += Invoke-Simulation -Door $Door -SwitchDoors $false
}
0..$Fifty | ForEach-Object {
$Win += Invoke-Simulation -Door $Door -SwitchDoors $true
}
continue
}
«Random» {
0..$Count | ForEach-Object {
[bool]$Random = Get-Random -Maximum 2 -Minimum 0
$Win += Invoke-Simulation -Door $Door -SwitchDoors $Random
}
continue
}
«Always» {
0..$Count | ForEach-Object {
$Win += Invoke-Simulation -Door $Door -SwitchDoors $true
}
continue
}
«Ratio» {
$TrueRatio = $Ratio / 100 * $Count
$FalseRatio = $Count — $TrueRatio
0..$TrueRatio | ForEach-Object {
$Win += Invoke-Simulation -Door $Door -SwitchDoors $true
}
0..$FalseRatio | ForEach-Object {
$Win += Invoke-Simulation -Door $Door -SwitchDoors $false
}
continue
}
}
Write-Output («Player won in » + $Win + " times out of " + $Count)
Write-Output («Whitch is » + ($Win / $Count * 100) + "%")
return $Win
}
#Invoke-MontyHallParadox -SwitchDoors Always -Count 500000

