Chances para dados com dados explodindo

7

Estou criando um jogo de mesa com um mecanismo de pool de dados para resolução de combate. Você rola alguns d6 e cada dado que rolou pelo menos 3 contagens como um SUCESSO:

  • Se você rolar mais 1s do que 6s, é um fumble
  • Um ou dois SUCESSOS é uma ferida leve
  • Três SUCESSOS em um rolo é uma ferida grave
  • Seis SUCESSOS é uma ferida crítica
  • Por cada 6 que você rola, você obtém um SUCESSO. Além disso, adicione outro d6 ao pool para cada 6 que você rolou. Conte cada um deles como um SUCESSO independentemente do número jogado . Cada um deles também pode explodir em 6.

Eu tenho tudo menos o último ponto coberto na função abaixo ( link direto para a função AnyDice ). Mas estou lutando com a última parte, o mecânico de dados explodindo.

Isso é crítico para avaliar o sistema, pois sem explodir os dados, as chances aumentam, e são quase 1/3, o que é muito alto. Dados explosivos limitarão a probabilidade de fumble. [editar: não, não vai]

Alguma ideia de como escrever esta função?

FUMBLE: -1
MISS: 0
WOUND: 1
SEVERE: 2
CRITICAL: 3

function: evaluate ROLL:s {
 SUCCESSES: ROLL >= 3
 if [count 1 in ROLL] > [count 6 in ROLL] { result: FUMBLE }
 if SUCCESSES = 0 { result: MISS }
 if SUCCESSES = {1..2} { result: WOUND }
 if SUCCESSES = {3..5} { result: SEVERE }
 if SUCCESSES >= 6 { result: CRITICAL }
}

loop DICE over {1..6} {
 output [evaluate DICE d6] named "[DICE]d6"
}
    
por bramford 29.07.2016 / 23:34

3 respostas

Existe uma função explode incorporada, mas você precisa usá-la antes de realizar o outro processamento. Especificamente, use FOOdBAR para ter BAR avaliado como uma sequência e usado para gerar FOO "dados" com contagens e valores laterais arbitrários. Aqui, DICEd([explode d6]) faz o trabalho, transformando um d6 explodido na base do rolo real. ( explode não separa os dados que você dá - você tem que fazer isso, ou você receberá um 5d6 roll que só explode, uma vez, em 30.)

Não é possível comparar sequências com um limite para obter uma lista ou soma de valores em relação a esse limite - basta ver a sequência somada e verificada em relação ao limite. Em vez disso, use [count VALUES in SEQUENCE] para cada um dos valores válidos (3-6). E como se vê, uma vez que a cada 6 dispara um novo dado e todos os dados contam, você pode apenas contar duas vezes seis vezes depois de explodir. Então realmente deveria ser [count {3..6, 6} in ROLL] .

Os resultados, da melhor maneira possível, não são bonitos. Cada explosão vai se atrapalhar mais (1), fazer nenhum progresso contra atrapalhar (2-5), ou empatar e ter uma nova chance de fazer a mesma coisa (6), e quanto mais dados você começar, maiores as chances de explosões. Não há previsão de que os fumbles se esgotem em explosões, como se esperaria de um grande sucesso; a única questão é se a cadeia termina com um 1 ou não.

    
30.07.2016 / 01:20

Eu dei uma olhada nisso em Python (eu sei que não é qualquer coisa. Tanto faz.) Acontece que, mesmo se excluirmos os explodidos da contagem em direção ao fumble, os fumble ainda são muito comuns em qualquer pool de dados de tamanho razoável (meu pool de testes de 8d6 ainda apareceu em torno de metade do tempo). Aqui está o meu script Python que exclui os explodidos:

# This is exploding D6s.
# Basically, you start with a single roll with x dice.
# A result of 4 or higher is a success.
# A result of 3 or lesser is a failure.
# If a 6 is rolled, you roll another die. It will always be a success.
# If that die is a 6, you roll yet another, and so on. This is the "exploding" part.
# However, if more 1's are rolled than 6's, there's a FUMBLE.
# Exploded dice don't count towards 1's when rolled, but do count toward 6's.
# Let's... rationalize that.

import random

def explodeD6(x, xcount=0, explodes=0, explodecount=0, successes=0, ones=0): #x is the number of dice initially rolled.
  if xcount < x: #This means not all the dice in the initial pool have been rolled yet.
    roll = random.randint(1,6)
    if roll == 1:
      ones = ones + 1
    elif roll == 2 or roll == 3:
      successes = successes #Just demonstrating that nothing happens.
    elif roll == 4 or roll == 5:
      successes = successes + 1
    elif roll == 6:
      successes = successes + 1
      explodes = explodes + 1
    else: #Whoops! The randint wasn't between one and six. That's not right.
      print("Oops. Wrong die.")
    print(str(roll)) #Report.
    xcount = xcount + 1 #Indicate one more die has been rolled.
    explodeD6(x,xcount,explodes,explodecount,successes,ones) #And again.
  elif xcount == x: #This means all the initial dice have been rolled, but not necessarily the explosions.
    if explodecount < explodes: #This is an explosion roll. There are no failures, but it can explode again!.
      roll = random.randint(1,6)
      if roll == 1 or roll == 2 or roll == 3 or roll == 4 or roll == 5:
        explodes = explodes #Again, demonstrating nothing happens.
      elif roll == 6:
        explodes = explodes + 1
      else: #D'oh. randint still not working.
        print("Oops. Wrong die.")
      successes = successes + 1
      explodecount = explodecount + 1
      print(str(roll) + "(Explosion)") #Report.
      explodeD6(x,xcount,explodes,explodecount,successes,ones)
    elif explodecount == explodes: #All dice have been rolled and all manner of bonus dice shall have been rolled.
      totalRolls = x + explodes
      if ones > explodes: #Fumble.
        print("With %s ones, but only %s sixes, the result is a fumble, despite %s successes.") % (ones,explodes,successes)
        print("%s rolls total, from a starting pool of %sd6, due to %s explosions.") % (totalRolls,x,explodes)
      elif ones <= explodes:
        if successes > 0: #Success!
          print("There were %s ones, but %s sixes, allowing the %s successes to shine through.") % (ones,explodes,successes)
          print("%s rolls total, from a starting pool of %sd6, due to %s explosions.") % (totalRolls,x,explodes)
        elif successes == 0: #Miss.
          print("There were %s ones, but %s sixes, yet there were %s successes, resulting in a miss.") % (ones,explodes,successes)
          print("%s rolls total, from a starting pool of %sd6, due to %s explosions.") % (totalRolls,x,explodes)
        else: #Oops. Successes are negative.
          print("Something's wrong.")
    else:
      print("Something's wrong.")
  else:
    print("Something's wrong.")

#Holy shit. That's really long. Let's test it.

explodeD6(8)

Copie e cole-o aqui para vê-lo em ação.

    
24.11.2016 / 17:35

Parece que eu estava errado e aprendi alguma coisa. Você pode fazer isso no AnyDice. :-) Eu ajustei o código no primeiro link nos comentários para adicionar na lógica para diminuir os sucessos quando 1s ocorrer. Parece que, com um lançamento de 3d6, você obteria uma pontuação -1 ou menor, 8,5% do tempo. 0 ~ 12%, 1 ~ 22% 2 ~ 22% e 3 ou mais ~ 35% do tempo com base nos resultados.

Para esclarecer o que isso está fazendo: As funções na parte inferior usam 1s para indicar que devem permitir essa coisa (explodir dados, rerola, falha na sub-rotina) e 0s para indicar que não devem. Limiar é o teste de dados (ou superior) que conta como um sucesso. Então, se é 3, então 3-6 são sucessos. Eu só adicionei a função bef embora você possa facilmente ajustar as funções para alterar o limite, se elas explodirem ou não, etc. A maior parte do crédito vai para @Magician que respondeu esta questão . Então, para a sua pergunta, você pode apenas editar a última linha antes da terceira parte para ser [# d6 para rolar inicialmente].

function: roll ROLL:n threshold T {
  if ROLL >=T {result: 1}
  result: 0
}

function: rollexploding ROLL:n threshold T{
  if ROLL =6 {result: 1+[rollexploding 1d6 threshold T]}
  result: [roll ROLL threshold T]
}

function: rerollfailures ROLL:n threshold T{
  if ROLL < T {result: [roll 1d6 threshold T]}
  result: [roll ROLL threshold T]
}

function: subtractfailureexplode ROLL:n threshold T{
  if ROLL =6 {result: 1+[subtractfailureexplode 1d6 threshold T]}
  if ROLL =1 {result: -1+[roll ROLL threshold T]}
  result: [roll ROLL threshold T]
}

function: rerollthenexplode ROLL: n threshold T {
  if ROLL < T {result: [rollexploding 1d6 threshold T]}
  result: [rollexploding ROLL threshold T]
}

function: wrapper DICE:n threshold T explode E reroll R fail F{
  RES:0
  loop N over {1..DICE} {
    if E & F {RES:RES+[subtractfailureexplode 1d6 threshold T]}
      else {if E & R {RES:RES+[rerollthenexplode 1d6 threshold T]}
        else {if E {RES:RES+[rollexploding 1d6 threshold T]}
          else {if R {RES:RES+[rerollfailures 1d6 threshold T]}
            else {RES:RES+[roll 1d6 threshold T]}
        }
      }
    }
  }
  result:RES
}

function: b DICE:n{
  result:[wrapper DICE threshold 4 explode 0 reroll 0 fail 0]
}

function: be DICE:n{
  result:[wrapper DICE threshold 4 explode 1 reroll 0 fail 0]
}

function: gr DICE:n{
  result:[wrapper DICE threshold 3 explode 0 reroll 1 fail 0]
}

function: bef DICE:n{
  result:[wrapper DICE threshold 3 explode 1 reroll 0 fail 1]
}

output [bef 3]
    
30.07.2016 / 00:04

Tags