This question is easiest illustrated with a non-standard card deck, since cards can have more than one occurence.
Let $T=\{A, B, C, ...\}$ be the finite set of card types, and $n : T \mapsto \mathbb{N}$ be the function that gives the number of occurences $n(x)$ for any $x \in T$. It should be obvious that the total number of cards in the deck is then $\sum_{x\in T} n(x)$.
You are given finitely many multisets (meaning repetitions matter but order doesn't). They will be referred to as your goals, e.g.: $\{A, A, B\}$, $\{B, C, E\}$ and $\{B, B, C, D\}$.
Starting with no cards and with a complete deck, what is the expected number of times that you need to draw a card until your hand allows you to complete at least one of the goals?
In other words, what is the expected card number that you need to draw until at least one of the goals is a multi-subset of your hand?
I explained the problem again in this four minute video for those to whom it is still unclear.
I want to solve this problem because of my involvement in a project of creating a card game as an internship. Any help is appreciated.
My Icepool Python package can compute exact solutions to problems of this type with runtime jointly polynomial in the number of unique cards, hand size, and deck size, though exponential in the number of combos. Here's an example script to compute the number of cards needed to get any combo from a hypothetical deck:
(API subject to change. This script is based on Icepool v0.25.6.)
Brief explanation:
deckrepresents, well, the deck. The keys are the unique cards and the values are how many copies of each card are in the deck.multiset_functionallows us to define a function using some simple multiset operations. In this case, the>=operator represents the superset comparison, and the tuple produces a joint evaluation. So this will jointly evaluate whether each of the combos have been met.find_combos(deck.deal(hand_size))jointly evaluates the combos over hand sizes. The result is a distribution over tuples of booleans, each element indicating whether the corresponding combo was met..map(any)then collapses the outcomes to just whether any of the combos have been met. (Unfortunately I have not come up with a good way to allow this to be expressed inside themultiset_functionitself.) This gives the CDF over the number of draws, i.e. the chance that it will take at mosthand_sizecards to get any combo.from_cumulativethen takes successive differences to find the PMF, i.e. the chance it will take exactlyhand_sizecards to get any combo..trim()prunes all zero-probability outcomes.You can try the script out in your browser here.
The algorithm uses dynamic programming and the decomposition of the hypergeometric distribution into binomials to find the distribution efficiently. If you are curious to learn more, you can read my paper here.