Skip to content

Instantly share code, notes, and snippets.

@kageru
Last active February 3, 2026 16:51
Show Gist options
  • Select an option

  • Save kageru/97799b6464503e1db0a0dbcca5649729 to your computer and use it in GitHub Desktop.

Select an option

Save kageru/97799b6464503e1db0a0dbcca5649729 to your computer and use it in GitHub Desktop.
deck probability
from itertools import chain
from random import sample
from collections import Counter
num_hands = 100_000
class MultipleOf:
def __init__(self, count, *cards):
self.count = count
self.cards = list(cards)
def All(*cards):
return MultipleOf(len(cards), *cards)
def Any(*cards):
return MultipleOf(1, *cards)
def times(count, *names):
return map(lambda n: (count, n), names)
decklist = [
*times(3,
'faimena',
'lukias',
'urgula',
'rahu',
'ecclesia',
),
*times(2,
'brafu',
'lorealbaz',
'pan',
),
*times(1,
'albaz',
'phryxul',
'mululu',
'ketu',
'cartesia',
),
(5, 'backrow'),
(13, 'handtrap'),
]
dt_except_faimena = Any('lukias', 'urgula', 'pan', 'phryxul', 'mululu')
dt = Any(*(['faimena'] + dt_except_faimena.cards))
ketu_or_name = Any(*(['ketu'] + dt.cards))
two_names = MultipleOf(2, *dt.cards)
fuser = Any('faimena', 'lukias', 'cartesia', 'lorealbaz', 'ketu', 'ecclesia', 'mululu')
monster = Any('handtrap', 'dt', 'ecclesia', 'cartesia', 'lorealbaz', 'albaz')
combos = [
('both', All(Any('lorealbaz', 'ecclesia'), dt)),
('brafu', 'brafu'),
("fuser + name", Any(
All(fuser, Any(All(ketu_or_name, 'handtrap'), two_names)),
All('mululu', monster),
)),
('rahu + name', All('rahu', ketu_or_name)),
('rahu', All('rahu', monster)),
('sanct', All('cartesia', 'albaz')),
('white ecclesia', Any('lorealbaz', 'ecclesia')),
]
def parse_decklist(cards):
return list(chain(*[n * [card] for (n, card) in cards]))
def draw_hand(decklist, handsize = 5):
return sample(decklist, k = handsize)
def contains(needle, haystack):
if isinstance(needle, list):
raise Exception(f'Forgot to wrap argument list {needle} in quantifier')
if isinstance(needle, MultipleOf):
return len(list(filter(lambda n: contains(n, haystack), needle.cards))) >= needle.count
return needle in haystack
def percent(n):
return f'{n / num_hands * 100:.1f}%'
deck = parse_decklist(decklist)
print(f"Deck has {len(deck)} cards")
hands = [draw_hand(deck) for _ in range(num_hands)]
combos_by_hand = [
[combo_name for (combo_name, combo) in combos if contains(combo, hand)] for hand in hands
]
for combo_name in set(map(lambda c: c[0], combos)):
count = sum(map(lambda ns: combo_name in ns, combos_by_hand))
print(f'Drew {combo_name} {percent(count)} of the time')
highest_combo = Counter(map(lambda xs: xs[0], filter(lambda xs: len(xs) > 0, combos_by_hand)))
for (name, count) in highest_combo.most_common():
print(f'Highest combo was {name} {percent(count)} of the time.')
bricks = sum(map(lambda cs: len(cs) == 0, combos_by_hand))
'''
for (hand, combos) in zip(hands, combos_by_hand):
if len(combos) == 0:
print(f'Bricked on {hand}')
'''
print(f'Bricked {percent(bricks)} of the time.')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment