Skip to content

Instantly share code, notes, and snippets.

@taikedz
Last active January 17, 2024 09:39
Show Gist options
  • Save taikedz/3a895286f1ccae67f0cc3c06e57ef484 to your computer and use it in GitHub Desktop.
Save taikedz/3a895286f1ccae67f0cc3c06e57ef484 to your computer and use it in GitHub Desktop.
Fate chances

Roll Fate

This is a quick script to see the chances of outcome of rolling Fudge/FATE dice against opposition.

Mainly, I am interested in rolling at Good skill against Good opposition , and seeing what happens.

Adding a +1 skill modifier is akin to being +1 shift above the Good opposition (skill Great).

  • -2 and below is abject failure
  • -1 is failure
  • 0 is a tie . For an "easy mode" on an alt game, this could be deemed a "success" for player, and "failure" for oposition.
  • 1 is a success
  • 2 and above is astounding success / superb

This seems to scale well - with no modifier, distribution is fairly even, with chances of abject failure and astounding success equal and rare enough.

With a +1 modifier (advantage to roller) and 2 dice, abject failure is impossible, and suberb is vastly enhanced. With 3 dice, abject failure becomes possible, but very rare, and superb becomes even more likely. The direct contrary is observed with a -1 modifier.

By displacing by 1 , very different chances are achieved. Conclusion for me is that going against equivalent opposition is somewhat balanced, but as soon as it shifts by 1, the balance is tipped vastly in favour of the higher value holder.

In the FATE rulebook, "advantage aspects" are possible granting a free invocation, and FATE points thereafter, with "boosts" as single-use free-invocation aspects, for some additional balance and nuance. FATE does this by setting an advantage aspect for an encounter; another game trying to use fudge/FATE dice might want to similarly include a way of closing the gap on a skill difference before rolling: systematic situational modifiers, equipment modifiers, buffs from spells/ally action, etc.

Roll results against equivalent opposition.
Simulations per combo: 1000000
| Fail bad Fail Tie Success Superb
2 dice, mod -2 | 66.7% 22.2% 11.0% 0.0% 0.0%
3 dice, mod -2 | 62.8% 22.3% 11.1% 3.7% 0.0%
4 dice, mod -2 | 61.8% 19.7% 12.3% 4.9% 1.2%
2 dice, mod -1 | 33.3% 33.3% 22.3% 11.1% 0.0%
3 dice, mod -1 | 37.1% 25.9% 22.2% 11.1% 3.7%
4 dice, mod -1 | 38.3% 23.5% 19.8% 12.3% 6.2%
2 dice, mod +0 | 11.1% 22.2% 33.4% 22.3% 11.1%
3 dice, mod +0 | 14.8% 22.3% 26.0% 22.2% 14.8%
4 dice, mod +0 | 18.5% 19.8% 23.4% 19.8% 18.5%
2 dice, mod +1 | 0.0% 11.1% 22.2% 33.3% 33.3%
3 dice, mod +1 | 3.7% 11.1% 22.2% 25.9% 37.0%
4 dice, mod +1 | 6.2% 12.3% 19.8% 23.6% 38.2%
2 dice, mod +2 | 0.0% 0.0% 11.1% 22.3% 66.6%
3 dice, mod +2 | 0.0% 3.7% 11.1% 22.1% 63.0%
4 dice, mod +2 | 1.2% 4.9% 12.3% 19.8% 61.7%
import random
import json
import time
def roll_fate(dice_count:int = 1) -> int:
return sum([random.choice([-1, 0, 1]) for _ in range(dice_count)])
def get_frequencies(dice_count:int, rolls:int, modifier:int) -> list[tuple[int,int]]:
cumulations = {}
outcomes = [roll_fate(dice_count) for x in range(rolls)]
for dice_outcome in outcomes:
final_outcome = str(dice_outcome + modifier)
if final_outcome not in cumulations:
cumulations[final_outcome] = 0
cumulations[final_outcome] += 1
return [(result_count,int(result)) for result,result_count in cumulations.items()]
def show(dice_count:int, rolls:int, modifier:int):
magnitude = rolls/100.0
sym = '' if modifier < 0 else '+'
ordered = get_frequencies(dice_count, rolls, modifier)
ordered.sort(key=lambda entry: entry[0])
#print("Stats:")
#print([f"{round(float(t[0])/magnitude)} % -> {t[1]}" for t in ordered])
_prob = lambda op: sum([result_count for result_count,result in ordered if op(result)]) / float(magnitude)
fail_2 = _prob(lambda x: x <= -2)
fail_1 = _prob(lambda x: x == -1)
tie_0 = _prob(lambda x: x == 0)
pass_1 = _prob(lambda x: x == 1)
pass_2 = _prob(lambda x: x >= 2)
print(f"{dice_count} dice, mod {sym}{modifier} | ", end='')
print(''.join([f"{chance:.1f}%".ljust(10) for chance in [fail_2, fail_1, tie_0, pass_1, pass_2] ]))
ROLLS = 1_000_000
random.seed(round(time.time()*1_000))
print("Roll results against equivalent opposition.")
print(f"Simulations per combo: {ROLLS}")
print("")
print((' '*15) + '| ' + ''.join([name.ljust(10) for name in ["Fail bad", "Fail", "Tie", "Success", "Superb"]]))
for modifier in [-2, -1, 0, 1, 2]:
for dice in [2,3,4]:
show(dice, ROLLS, modifier)
print("")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment