Skip to content

Instantly share code, notes, and snippets.

@ZerothAngel
Last active February 28, 2021 06:30
Show Gist options
  • Save ZerothAngel/57ac270056562da1e90029717ed81f2c to your computer and use it in GitHub Desktop.
Save ZerothAngel/57ac270056562da1e90029717ed81f2c to your computer and use it in GitHub Desktop.
A simple utility for Phantasy Star Online 2 (PSO2) to calculate the overall success rate of upslotting a weapon/unit to N slots from N-1.
#!/usr/bin/env python3
"""
A simple utility for Phantasy Star Online 2 to calculate the overall success
rate of upslotting a weapon/unit to N slots from N-1.
Can also take number of (filled) S-Grade Augment slots (aka SSA slots) which,
when present, always improve the overall chance (because they are 100% even
on upslot).
Specifying additional boosts (e.g. boost week) and/or manually specifying the
augmentation aid to use is also possible.
For example, to calculate the chance of upslotting a 7s trailblazer (aka
lightstream) weapon with 3 filled SGA slots during 10% boost week while
using a 45% augmentation aid:
# ./upslot.py -b .1 -a .45 8 3
Base success rate per slot: 40.0%
Using 45.00% aid
Success rate per slot: 85.00%
Success probabilities:
8 : 44.371%
7 : 39.150%
6 : 13.818%
5 : 2.4384%
4 : 0.21516%
3 : 0.0075938%
That is, a 44% chance to end up with an 8 slots (i.e. total success), a 39%
chance to end up with 7 slots (1 failure), etc. etc.
"""
from decimal import *
import math
TARGET_SUCCESS = [
Decimal("1.0"),
Decimal("0.9"),
Decimal("0.85"),
Decimal("0.7"),
Decimal("0.6"),
Decimal("0.55"),
Decimal("0.4"),
Decimal("0.3")
]
def clamp(rate):
if rate > Decimal("1.0"):
return Decimal("1.0")
return rate
def choose_aid(success_rate):
gap = Decimal("1.0") - success_rate
if gap == Decimal("0.0"):
return Decimal("0.0")
elif gap <= Decimal("0.1"):
return Decimal("0.1")
elif gap <= Decimal("0.3"):
return Decimal("0.3")
else:
return Decimal("0.4")
def main(target_slots, sga_slots=0, boost='0', aid=None):
if target_slots < 0 or target_slots > 8:
raise ValueError('target_slots must be in range [0,8]')
if sga_slots < 0 or sga_slots >= target_slots:
raise ValueError('sga_slots must be in range [0,target_slots)')
boost_week = Decimal(boost)
base_success = clamp(TARGET_SUCCESS[target_slots - 1] + boost_week)
if aid is None:
aid = choose_aid(base_success)
else:
aid = Decimal(aid)
success_rate = clamp(base_success + aid)
failure_rate = Decimal("1.0") - success_rate
print(f'Base success rate per slot: {base_success * Decimal("100")}%')
print(f'Using {aid * Decimal("100")}% aid')
print(f'Success rate per slot: {success_rate * Decimal("100")}%')
num_slots = target_slots - sga_slots
print('Success probabilities:')
for successes in range(num_slots, -1, -1):
failures = num_slots - successes
prob = success_rate ** successes
if failures > 0:
prob *= failure_rate ** failures
prob *= math.comb(num_slots, successes)
with localcontext() as ctxt:
ctxt.prec = 5
print(f' {successes + sga_slots} : {prob * Decimal("100")}%')
if success_rate == Decimal("1"):
break
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser(description='calculate upslot probabilities')
parser.add_argument('target-slots', type=int,
help='target slots')
parser.add_argument('sga-slots', type=int, nargs='?',
default=0,
help='number of SGA slots')
parser.add_argument('--boost', '-b', type=str,
default='0',
help='additional boosts (e.g. boost week)')
parser.add_argument('--aid', '-a', type=str,
default=None,
help='manual augmentation aid specification')
args = vars(parser.parse_args())
main(args['target-slots'], sga_slots=args['sga-slots'], boost=args['boost'],
aid=args['aid'])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment