Usando la canalización en Powershell
El algoritmo es simple, el primero es el generador de puerta aleatorio, luego el generador de elección del usuario, luego la lógica de apertura de la puerta del presentador, otra acción del usuario y el conteo de estadísticas.
Y ayúdanos con esto es la herramienta eléctrica
ValueFromPipeline
, que nos permite especificar el cmdlet uno a uno, transformando el objeto paso a paso. Así es como debería verse nuestra canalización:
New-Doors | Select-Door | Open-Door | Invoke-UserAction
New-Doors
genera nuevas puertas, en el equipo el
Select-Door
jugador elige una de las puertas, el
Open-Door
líder abre la puerta en la que definitivamente no hay cabra y que no fue elegida por el jugador, y en
Invoke-UserAction
nosotros simulamos diferentes comportamientos del usuario.
El objeto que describe la puerta se mueve de izquierda a derecha, transformándose gradualmente.
Este método de escribir código ayuda a mantenerlo en pedazos con claras divisiones de responsabilidad.
Powershell tiene sus propias convenciones. Incluidas las convenciones sobre la denominación correcta de funciones , también es necesario observarlas y casi las cumplimos.
Haciendo puertas
Como vamos a simular la situación, también describiremos en detalle las puertas.
La puerta contiene una cabra o un automóvil. La puerta puede ser elegida por el jugador o abierta por el anfitrión.
class Door {
<#
, .
.
#>
[string]$Contains = "Goat"
[bool]$Selected = $false
[bool]$Opened = $false
}
Colocaremos cada una de las puertas en un campo separado en una clase separada.
class Doors {
<#
, 3
#>
[Door]$DoorOne
[Door]$DoorTwo
[Door]$DoorThree
}
Fue posible poner todas las puertas en una matriz, pero cuanto más detallado se describa todo, mejor. Por cierto, en Powershell 7, las clases, sus constructores, métodos y todo lo demás es OOP, que funciona casi como debería, pero más sobre eso en otro momento.
El generador de puerta aleatorio se ve así. Primero, para cada jamba de puerta, se genera su propia puerta, y luego el generador elige en cuál de ellas se colocará el automóvil.
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
Nuestra pipa se ve así:
New-Doors
El jugador elige la puerta
Ahora describamos la elección inicial. El jugador puede elegir una de las tres puertas. Con el fin de simular más situaciones, deje que el jugador elija solo la primera, solo la segunda, solo la tercera y puerta aleatoria cada vez.
[Parameter(Mandatory)]
[ValidateSet("First", "Second", "Third", "Random")]
$Principle
Para aceptar argumentos de la canalización, debe especificar una variable en el bloque de parámetros que hará esto. Esto se hace así:
[parameter(ValueFromPipeline)]
[Doors]$i
Puedes escribir
ValueFromPipeline
sin
True
.
Así es como se ve el bloque de selección de puerta terminado:
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
Nuestra pipa se ve así:
New-Doors | Select-Door -Principle Random
Liderar abre la puerta
Aquí todo es muy sencillo. Si el jugador no eligió la puerta y si hay una cabra detrás de ella, cambie el campo
Opened
a
True
. Específicamente, en este caso, no es
Open
correcto nombrar el comando con una palabra , el recurso llamado no se lee, sino que se cambia. En tales casos, use
Set
, pero
Open
déjelo para mayor claridad.
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 hacer nuestra simulación más convincente, "abrimos" esta puerta cambiando el campo .opened a en
$true
lugar de eliminar el objeto de la matriz de puertas.
No te olvides de los
continue
interruptores, la comparación no se detiene después del primer partido.
Coninue
sale del conmutador y continúa ejecutando el script, y el operador
break
del conmutador termina el script.
Agregue una función más a la tubería, ahora se ve así:
New-Doors | Select-Door -Principle Random | Open-Door
El jugador cambia su elección
El jugador cambia la puerta o no la cambia. En el bloque de parámetros, solo tenemos una variable de la tubería y un argumento booleano.
Use la palabra
Invoke
en los nombres de dichas funciones, porque
Invoke
significa llamar a una operación sincrónica y
Start
asincrónica, siga las convenciones y recomendaciones.
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
En los operadores de ramificación y comparación, primero debe especificar el sistema y las variables estáticas. Probablemente, puede haber dificultades para convertir un objeto en otro, pero el autor no encontró tales dificultades cuando antes escribió de una manera diferente.
Otra función en la tubería.
New-Doors | Select-Door -Principle Random | Open-Door | Invoke-UserAction -SwitchDoor $True
La ventaja de este método de escritura es clara, porque nunca ha sido tan conveniente dividir el código en partes con una clara separación de funciones.
Comportamiento del jugador
Con qué frecuencia el jugador cambia de puerta. Hay 5 líneas de comportamiento:
Never
- el jugador nunca cambia su elecciónFifty-Fifty
- 50 a 50. El número de simulaciones se divide en dos pasadas. El primer pase el jugador no cambia la puerta, el segundo pase cambia.Random
- en cada nueva simulación, el jugador lanza una monedaAlways
- el jugador siempre cambia su elección.Ration
- el jugador cambia su elección en un N% de 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
en Powershell 7 funciona mucho más rápido que un bucle
for
, además de que se puede paralelizar, por lo que se usa aquí en lugar de un bucle
for
.
Aplicar estilo al cmdlet
Ahora necesita corregir el cmdlet. En primer lugar, debe realizar la validación de los argumentos entrantes. La ventaja no es solo que una persona no puede ingresar un argumento no válido en el campo, sino que aparece una lista de todos los argumentos disponibles en las solicitudes.
Así es como se ve el código en el bloque de parámetros:
param (
[Parameter(Mandatory = $false,
HelpMessage = "How often the player changes his choice.")]
[ValidateSet("Never", "FiftyFifty", "Random", "Always", "Ratio")]
$SwitchDoors = "Random"
)
Esta es la pista:
Antes de que se pueda realizar el bloque de parámetros
comment based help
. Así es como se ve el código antes del bloque 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
#>
Así es como se ve el mensaje:
Ejecutando la simulación
Resultados de la simulación:
Si una persona nunca cambia su elección, gana el 33,37% de las veces.
En el caso de dos pases, en la mitad de los cuales nos negamos a cambiar nuestra elección, las posibilidades de ganar son del 49,9134%, que está muy cerca de exactamente el 50%.
En el caso de un lanzamiento de moneda, nada cambia, la posibilidad de ganar se mantiene alrededor del 50,131%.
Pues si el jugador cambia siempre de elección, la posibilidad de ganar se eleva al 66,6184%, es decir, aburrido y nada nuevo.
Rendimiento:
en términos de rendimiento. El guión no parece ser el óptimo.
String
en cambio
Bool
, muchas funciones diferentes con un interruptor adentro, pasándose un objeto entre sí, pero sin embargo, aquí están los resultados
Measure-Command
para este guión y un guión de otro autor .
La comparación se llevó a cabo en dos sistemas, pwsh 7.1 estaba en todas partes, 100.000 pases.
▍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
Ese 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
Ese 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
63 ms de ventaja, pero los resultados siguen siendo muy extraños teniendo en cuenta la cantidad de veces que el script compara cadenas.
El autor espera que este artículo sirva como un ejemplo convincente para aquellos que creen que las probabilidades son siempre de 50 a 50, pero puede leer el código en este spoiler.
Todo el 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