<jupyter_start><jupyter_text>Let's model a simple system.Just have fish reproduce every 7 days, ignore the 2-day new-fish lag for now.They all start at a 0-counter for now.They'll double every 7 days starting on day 0, easy peasy.<jupyter_code># initially we have one fish
# fish = [0]
# after day 0 we have 2 fish:
# fish = 6, 6
# after day 7 we have 4 fish, etc.
# after day 14 we have 8 fish, etc.
# So it's 2^(days//7) fish.

print("days \tfish")
for days in range(22):
    print(days, '\t', pow(2, days // 7 + 1))
# or more generally
def fish_at_day(day):
    return pow(2, day // 7 + 1)


print(fish_at_day(20))
print(fish_at_day(21))<jupyter_output>8
16<jupyter_text>Now we can easily extend that to fish with different clocks. Just need to incorporate 'clock' into the formula.<jupyter_code>def fish_at_day(day, clock):
    return pow(2, (day-clock) // 7 + 1)

print(fish_at_day(21, 0))  # A single '0' fish will become 16 fish by day 21
print(fish_at_day(21, 1))  # A single '1' fish will only become 8 fish by then
print(fish_at_day(22, 1))  # The '1' fish becomes 16 fish on day 22.
# How do we model multiple fish? Let's use a counter dict.
fish = {i:0 for i in range(7)}
fish[0] = 2  # we start with two "0" fish
fish[4] = 3  # and three "4" fish
# Update the formula so it takes the starting number of fish into account
def fish_at_day(day, clock, starting):
    return pow(2, (day-clock) // 7 + 1) * starting
# OK, so how many fish do we get by day 11?
# We should have eight "0" fish and twelve "4" fish.
day = 11
print("clock \t count")
for clock, count in fish.items():
    if not count:
        continue
    print(clock, '\t', fish_at_day(day, clock, count))

# Cleaning it up

def fish_after_time(days, fish):
    fish_after = {i:0 for i in range(7)}
    for clock, count in fish.items():
        fish_after[clock] =  fish_at_day(days, clock, count)
    return fish_after


def print_fish(fish):
    print("clock \t count")
    for f in fish:
        if fish[f] != 0:
            print(f, '\t', fish[f])

fish = {0: 2, 5: 1}

print("initially")
print_fish(fish)

days = 0
print("\nafter", days, 'days')
print_fish(fish_after_time(days, fish))

days = 7
print("\nafter", days, 'days')
print_fish(fish_after_time(days, fish))<jupyter_output>initially
clock 	 count
0 	 2
5 	 1

after 0 days
clock 	 count
0 	 4
5 	 1

after 7 days
clock 	 count
0 	 8
5 	 2<jupyter_text>Last challenge. How do we model the fact that "new" fish take longer before their first spawn?Well, I dunno. Got partway there but didn't solve it. Work after this point is rough draft stuff.<jupyter_code>"""
Idea: Let's compute at day 0, 7, 14...
and just bump all the clocks by 2 for only the NEW fish.
"""

# Which ones are the new fish? Let's separate them out by subtracting the old fish.
def new_fish(fish_after, fish_before):
    new_fish = {i:0 for i in range(9)}
    for f in new_fish.keys():
        new_fish[f] = fish_after.get(f,0) - fish_before.get(f,0)
    return new_fish

fish = {0: 2, 5: 1}

print("initially")
print_fish(fish)

days = 0
print("\nafter", days, 'days')
fish_after = fish_after_time(days, fish)
print_fish(fish_after)

print("\nNew fish")
print_fish(new_fish(fish_after, fish))
# So now we have the new fish isolated, we can bump their clocks up.
nf = new_fish(fish_after, fish)

def set_clocks(new_fish):
    fish = {i:0 for i in range(9)}
    for f in new_fish:
        fish[8] = new_fish[f]
    return fish

print_fish(nf)
print_fish(bump_clocks(nf))
# putting it all together

# test input
fish_before = {1: 1, 2: 1, 3: 2, 4: 1}
days = 80

for d in range(days):
    fish_after = {}
    for f in sorted(fish_before.keys()):
        if f == 0:
            fish_after[6] = fish_after.get(6, 0) + fish_before[f]
            fish_after[8] = fish_after.get(8, 0) + fish_before[f]
        else:
            fish_after[f-1] = fish_after.get(f-1, 0) + fish_before[f] 
    fish_before = fish_after
    
print_fish(fish_before)
print("total", sum(fish_after.values()))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1219147344801795, 'fraction_numerical': 0.03315881326352531, 'mean_word_length': 3.528216704288939, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '435323', 'license': 'MIT', 'n_tokens_mistral': 1557, 'n_tokens_neox': 1446, 'n_words': 525, 'path': 'aoc2021/day06/fishy.ipynb', 'repo_name': 'shoreofwonder/adventofcode', 'size': '4011'}