# Pocket Camp Complete - Fortune Cookie Simulator

import random

NUM_OF_SIMULATIONS = 20
NUM_OF_COOKIE_TYPES = 182

# These are the rates pulled directly from the app.
# Each row must have all 10 item rates in ascending order.
LIST_OF_ALL_COOKIE_ODDS = [
    [2.53, 7.06, 7.06, 7.06, 7.06, 13.85, 13.85, 13.85, 13.85, 13.85],
    [3.41, 9.47, 9.47, 9.47, 9.47, 11.74, 11.74, 11.74, 11.74, 11.74],
    [3.01, 7.33, 7.33, 7.33, 7.33, 13.53, 13.53, 13.53, 13.53, 13.53],
    [3.11, 6.97, 6.97, 6.97, 6.97, 13.80, 13.80, 13.80, 13.80, 13.80],
    [3.39, 9.83, 9.83, 9.83, 11.19, 11.19, 11.19, 11.19, 11.19, 11.19],
    [3.01, 9.22, 9.22, 9.22, 9.22, 12.02, 12.02, 12.02, 12.02, 12.02],
    [2.72, 7.26, 7.26, 7.26, 7.26, 13.65, 13.65, 13.65, 13.65, 13.65],
    [2.83, 7.14, 7.14, 7.14, 7.14, 13.73, 13.73, 13.73, 13.73, 13.73],
    [2.32, 6.75, 6.75, 6.75, 6.75, 14.14, 14.14, 14.14, 14.14, 14.14],
    [2.61, 9.32, 9.32, 9.32, 9.32, 12.02, 12.02, 12.02, 12.02, 12.02],
    [2.65, 6.82, 6.82, 6.82, 6.82, 14.01, 14.01, 14.01, 14.01, 14.01],
    [3.03, 7.62, 7.62, 7.62, 7.62, 13.29, 13.29, 13.29, 13.29, 13.29],
    [3.09, 7.82, 7.82, 7.82, 7.82, 13.13, 13.13, 13.13, 13.13, 13.13],
    [2.93, 6.66, 6.66, 6.66, 6.66, 14.08, 14.08, 14.08, 14.08, 14.08],
    [3.13, 9.03, 9.03, 9.03, 9.03, 12.15, 12.15, 12.15, 12.15, 12.15],
    [2.75, 6.26, 6.26, 6.26, 6.26, 14.44, 14.44, 14.44, 14.44, 14.44]
]

# This is the number of times each cookie rate was seen in February and March
OCCURANCE_OF_COOKIE_ODDS = [3, 3, 2, 2, 7, 1, 1, 3, 2, 1, 1, 1, 1, 2, 1, 1]

def cookie_simulation_all_items_with_stamps(balk_num):
    item_indexes = [i for i in range(10)]
    pull_stats = [0] * NUM_OF_COOKIE_TYPES
    stamp_count = 0

    for c in range(NUM_OF_COOKIE_TYPES):
        pull_count = 0
        owned_items = [False] * 10

        # Get a random set of cookie odds
        cookie_odds = random.choices(population=LIST_OF_ALL_COOKIE_ODDS, weights=OCCURANCE_OF_COOKIE_ODDS, k=1)[0]

        while not all(owned_items):
            # Pull five cookies at a time
            pulled_cookies = random.choices(population=item_indexes, weights=cookie_odds, k=5)
            pull_count += 5
            stamp_count += 6

            # Mark which items were given
            for p in pulled_cookies:
                owned_items[p] = True
            
            # If we've eaten a lot of cookies and still haven't gotten the item,
            # try to buy it with stamps.
            if not all(owned_items) and pull_count >= balk_num:
                # Because this walks the array from forward to back, it tries to buy the 5-star 
                # item first.  This is intentional.  If you run out of stamps and still need
                # to buy cookies, then you'll have better odds pulling the 3 or 4-star items.
                for i in range(10):
                    if not owned_items[i]:
                        # 5-star item
                        if cookie_odds[i] < 4.0:
                            if stamp_count >= 100:
                                owned_items[i] = True
                                stamp_count -= 100
                        # 4-star item
                        elif cookie_odds[i] < 10.0:
                            if stamp_count >= 50:
                                owned_items[i] = True
                                stamp_count -= 50
                        # 3-star item
                        else:
                            if stamp_count >= 10:
                                owned_items[i] = True
                                stamp_count -= 10
            
        pull_stats[c] = pull_count

    return sum(pull_stats)


max_box_pull_balk_point = 12
results = [[0] * NUM_OF_SIMULATIONS for _ in range(max_box_pull_balk_point)]

for i in range(NUM_OF_SIMULATIONS):
    for b in range(max_box_pull_balk_point):
        results[b][i] = cookie_simulation_all_items_with_stamps(balk_num=(b+1)*5)

for b in range(max_box_pull_balk_point):
    results[b] = sorted(results[b])
bottom_five_index = max(1, int(NUM_OF_SIMULATIONS * 0.05))
top_five_index = NUM_OF_SIMULATIONS - bottom_five_index - 1
median_index = int(NUM_OF_SIMULATIONS / 2)

print(f'Cumulative cookies purchased to complete {NUM_OF_COOKIE_TYPES} collections. Simulated {NUM_OF_SIMULATIONS} times.')
print('| Use stamps after X pulls |  Best  |   5%   | Median |   95%  |  Worst | Average |')
for b in range(max_box_pull_balk_point):
    print(f'|            {(b+1)*5:02d}            |  {results[b][0]}  |  {results[b][bottom_five_index]}  |  {results[b][median_index]}  |  {results[b][top_five_index]}  |  {results[b][-1]}  |  {round(sum(results[b]) / NUM_OF_SIMULATIONS)}   |')
