C. Lente

Rolando dados com {droll}

droll [ˈdrōl] (adj.). 1. (Ing.) Divertido, especialmente de forma incomum.

droll é um pacote R para parsear a notação usada para descrever dados, analisar rolagens, calcular probabilidades de sucesso e gerar gráficos das distribuições dos resultados. Ele pode ajudar DMs detalhistas a preparar encontros (in)justos com antecedência ou decidir a DC apropriada para um teste na hora. Jogadores também podem usar o droll para determinar a melhor estratégia quando em uma situação difícil.

Ele foi feito para ser uma alternativa muito leve (só uma dependência obrigatória), muito rápida (menos de 0,4s para calcular a distribuição completa de 40d6) e muito precisa (representação interna simbólica cortesia do Ryacas) para o anydice no R.

Instalação

Instale a versão estável do CRAN com:

install.packages("droll")

Ou instale a versão em desenvolvimento do GitHub com:

# install.packages("remotes")
remotes::install_github("curso-r/droll")

Uso

O que você procura no droll? Você é um usuário nível 1, um programador experiente nível 10, ou um estatístico divino nível 20? Escolha sua classe:

🖍️ Usuário

O uso mais básico do droll envolve simplesmente rolar dados. Você pode criar qualquer dado que quiser com a função d() e escrever qualquer expressão que envolva aquele dado. Note que, se você quiser rolar NdX, você deveria escrever N * dX.

# Criar alguns dados
d20 <- d(20)
d6  <- d(6)
d4  <- d(4)

# Rolar um teste enquanto abençoado
(d20 + 8) + d4
#> [1] 22

# Rolar o dano!!
8 * d6
#> [1] 22

# Rolar um teste de resistência de destreza com desvantagem
if (min(d20, d20) + 4 < 18) {
  print("Dano completo!")
} else {
  print("Metade do dano.")
}
#> [1] "Dano completo!"

Simples e fácil, certo? Se você é um DM, você também pode querer usar duas funções: check_prob() e check_dc(). Elas permitem que você, respectivamente, calcule a probabilidade de passar (ou falhar) em um teste e encontrar a DC necessária para que um teste tenha uma certa probabilidade de sucesso (ou erro). Você não precisa nem criar os dados que você vai usar dentro delas!

# Qual é a probabilidade que esse jogador passe em um teste de DC 15?
check_prob(d20 + 8, 15)
#> [1] 0.7

# Qual deveria ser a DC para que esse jogador tenha 50% de chance de sucesso?
check_dc(d20 + 8, 0.5)
#> [1] 19

# Qual é a probabilidade desse jogador falhar em um teste de DC 10?
check_prob(d20 + 8, 10, success = FALSE)
#> [1] 0.05

# Qual deveria ser a DC para que esse jogador tenha 90% de chance de falha?
check_dc(d20 + 8, 0.9, success = FALSE)
#> [1] 27

Não há funções do tipo attack_*() porque as mecânicas de ataques e testes são as mesmas, ou seja, sucesso equivale a rolar um valor maior ou igual a um certo patamar. Essas funções podem, portanto, ser usadas para ataques também!

🗡️ Programador

Se você já está acostumado com a notação d/p/q/r do R, pode ser que você queira mais detalhes sobre a distribuição de uma rolagem. É para isso que as funções droll(), proll(), qroll(), e rroll() existem! Elas são, respectivamente, a densidade, a função de distribuição, a função de quantil, e a geração aleatória da distribuição definida por uma expressão de rolagem.

# P[d20 + 8 = 12]
droll(12, d20 + 8)
#> [1] 0.05

# P[d20 + 8 <= 12]
proll(12, d20 + 8)
#> [1] 0.2

# inf{x: P[d20 + 8 <= x] >= 0.5}
qroll(0.5, d20 + 8)
#> [1] 18

# Amostrar 3 vezes de d20 + 8 
rroll(3, d20 + 8)
#> [1] 16 26  9

Quando você aprender a usar essas quatro funções, você pode olhar as suas variações plot_*() delas. Elas geram gráficos (usando o ggplot2 se ele estiver disponível) correspondendo às distribuições completas de d/p/q e um histograma simples no caso da plot_rroll().

# Densidade de 8d6
droll_plot(8 * d6)

# Função de distribuição de 8d6
proll_plot(8 * d6)

# Função de quantil de 8d6
qroll_plot(8 * d6)

# Histograma de 1000 rolagens de 8d6
rroll_plot(1000, 8 * d6)

Toda função p/q também tem um conveniente argumento lower.tail que pode ser igual a FALSE para que os cálculos sejam feitos a partir da cauda superior da distribuição.

🪄 Estatístico

Já que você é um veterano do R, você precisa ser capaz de dobrar o droll à sua vontade. Se você gostaria de ver o tecido da realidade do droll, você pode usar a função r() para obter uma distribuição de rolagem completa. Se você quiser precisão máxima, você também pode impedir o droll de converter a sua representação interna (operada pelo Ryacas) para doubles com precise = TRUE.

# Obter a distribuição completa de 8d6
r(8 * d6)
#> # A tibble: 41 × 4
#>    outcome     n           d           p
#>      <dbl> <dbl>       <dbl>       <dbl>
#>  1       8     1 0.000000595 0.000000595
#>  2       9     8 0.00000476  0.00000536 
#>  3      10    36 0.0000214   0.0000268  
#>  4      11   120 0.0000714   0.0000982  
#>  5      12   330 0.000196    0.000295   
#>  6      13   792 0.000472    0.000766   
#>  7      14  1708 0.00102     0.00178    
#>  8      15  3368 0.00201     0.00379    
#>  9      16  6147 0.00366     0.00745    
#> 10      17 10480 0.00624     0.0137     
#> # … with 31 more rows

# Poder ilimitado
r(8 * d6, precise = TRUE)
#> # A tibble: 41 × 4
#>    outcome n     d          p           
#>      <dbl> <chr> <chr>      <chr>       
#>  1       8 1     1/1679616  1/1679616   
#>  2       9 8     1/209952   1/186624    
#>  3      10 36    1/46656    5/186624    
#>  4      11 120   5/69984    55/559872   
#>  5      12 330   55/279936  55/186624   
#>  6      13 792   11/23328   143/186624  
#>  7      14 1708  427/419904 2995/1679616
#>  8      15 3368  421/209952 707/186624  
#>  9      16 6147  683/186624 695/93312   
#> 10      17 10480 655/104976 11495/839808
#> # … with 31 more rows

A tabela retornada por r() pode ser usada no lugar do argumento roll de todas as funções discutidas acima. Isso pula os cálculos internos, um atalho valioso se você quiser rodar múltiplos diagnósticos para a mesma expressão de rolagem.

Como um estatístico nível 20, você também não está limitado pelos dados internos do droll. Você pode criar dados personalizados usando a mesma função d() descrita anteriormente.

# Criar um dado "fudge"
dF <- d(-1:1)
rroll(5, dF)
#> [1] -1  1  1 -1 -1

# Criar um 2d20kh, um "dado de vantagem"
df <- r(max(d20, d20))
kh <- d(rep(df$outcome, df$n))
rroll(5, kh)
#> [1] 12  5  9  5 18