【问题标题】:D&D Dice simulatorDnD骰子模拟器
【发布时间】:2020-11-10 18:11:35
【问题描述】:

我想出了一个滚动策略,您可以滚动 4d6 并重新滚动任何重复项。这导致数字介于 10 和 18 之间,这导致 14 是最常见的,而 10 和 18 是最不常见的。要指定,您保留 1 个重复项并重新滚动其他项。而且我在任何骰子滚动应用程序/在线上都找不到这种方法。我正在尝试在 PowerShell 中运行:

$A = Get-Random -Maximum 6 -Minimum 1
$B = Get-Random -Maximum 6 -Minimum 1
$C = Get-Random -Maximum 6 -Minimum 1
$D = Get-Random -Maximum 6 -Minimum 1

While ($A = $B) {
$B = Get-Random -Maximum 6 -Minimum 1
}
... 
...

$Stat = $A+$B+$C+$D

但是 $A 和 $B 总是相同的,而 $C 和 $D 总是相同的。任何人都可以解释 Get-Random 的工作原理并为我的循环变为无限的原因提出解决方案吗?

【问题讨论】:

    标签: powershell random


    【解决方案1】:

    如果您将其视为一系列单独的掷骰子,重复进行直到您看到 4 个不同的值(这正是它的本质),您可以将其建模为:

    function Roll-4d6 {
        # Use hashtable to keep track of face values
        $uniqueRolls = @{}
    
        # Keep rolling until we've seen 4 distinct faces
        while($uniqueRolls.Count -lt 4){
            # Roll the dice, make note of unique face value
            $roll = 1..6 |Get-Random
            $uniqueRolls[$roll] = $roll
        }
    
        # Calculate and return sum
        return $uniqueRolls.Values |Measure-Object -Sum |Select-Object -ExpandProperty Sum
    }
    

    执行 10K 次将揭示重复 4d6 重新滚动的真实分布(与您似乎期望的不太一样):

    1..10000 |ForEach-Object {
      Roll-4d6
    } |Group-Object -NoElement |Sort Name
    
    # outputs something along the lines of
    Count Name
    ----- ----
      686 10
      650 11
     1334 12
     1323 13
     2044 14
     1314 15
     1348 16
      664 17
      637 18
    

    简单的解释是只有 一个 的组合可以产生 10 个 (1,2,3,4)、11 个 (1,2,3,5)、17 个 (2,4,5,6) 和 18 个 (@987654326) @)。

    要通过单次采样模拟相同的分布,您可以:

    $roll = 10, 11, 12, 12, 13, 13, 14, 14, 14, 15, 15, 16, 16, 17, 18 |Get-Random
    

    注意-Maximum

    请注意,Get-Random-Maximum 参数是排除性的,因此对于 6 面骰子,您需要 Get-Random -Minimum 1 -Maximum 7

    【讨论】:

    • 所以,10, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 17, 17, 18 | Get-Random 会更准确地表达我想做的事情,如果不是本着它的精神...
    • 不,那不准确,我在答案的单个语句中添加了一个如何做到这一点的示例
    【解决方案2】:

    这是一个任意数量的骰子的解决方案,重新滚动直到唯一并返回一个数组。

    function RollDice {
        param (
            [ValidateRange(1,[int]::MaxValue)][parameter(Position = 0, Mandatory = $true)][int]$Amount,
            [ValidateRange(1,[int]::MaxValue)][Alias('d')][int]$Sides
        )
        if ($Amount -gt $Sides) {
            throw "Invalid parameter - The number of sides ($Sides) must be greater than the number of dice thrown ($Amount)"
        }
    
        [System.Collections.Generic.List[int]]$Results = @()
    
        for ($DiceNum = 1; $DiceNum -le $Amount; $DiceNum++) {
            while (!([int]$Roll) -or $Roll -in $Results) {
                $Roll = Get-Random -Minimum 1 -Maximum ($Sides + 1)  #Maximum pulls a number less than, not equal. See https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/get-random
            }
            $Results += $Roll
        }
        
        Return $Results
    }
    
    RollDice 4 -d 6
    

    【讨论】:

      【解决方案3】:

      这是另一种使用列表且不需要重新滚动重复项的方式:

      Function Roll {
      
          # Die face values
          $roll = [System.Collections.Generic.List[int]]@(1..6)
          # Perform the required number of rolls
          $values = 1..4 | Foreach-Object { 
              # Random roll
              $r = Get-Random -InputObject $roll
              # Remove rolled value from list to prevent duplicates
              [void]$roll.Remove($r)
              # return roll
              $r
          }
          # Sum rolls
          ($values | Measure-Object -Sum).Sum
      }
      
      # Execute the rolls
      Roll
      
      # Output
      16
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-01-03
        • 1970-01-01
        • 2017-02-23
        • 2016-04-18
        • 2013-12-18
        • 1970-01-01
        • 2015-09-27
        • 1970-01-01
        相关资源
        最近更新 更多