from fractions import Fraction from itertools import combinations def mul(xs): r = 1 for x in xs: r *= x return r def mul_inv(xs): r = 1 for x in xs: r *= (1 - x) return r def sub_odds(n_blue, n_total): """ Computes the odds for getting exactly n_blue out of n_total blue discs. """ total_odds = 0 odds = [Fraction(1, n) for n in range(2, 2 + n_total)] odds_set = set(odds) for odd in combinations(odds, n_blue): odd_inv = tuple(odds_set.difference(set(odd))) total_odds += mul(odd) * mul_inv(odd_inv) return total_odds def euler_121(): n_turns = 15 n_to_win = n_turns // 2 + 1 odds = 0 for n_blue in range(n_to_win, n_turns + 1): odds += sub_odds(n_blue, n_turns) price = int(1 / odds) return price if __name__ == "__main__": solution = euler_121() print("e121.py: " + str(solution)) assert(solution == 2269)