My Advent of Code solutions in Python. kevinyap.ca/2019/12/going-fast-in-advent-of-code/
advent-of-code python
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add 2022/17

+97
+1
.gitignore
··· 1 1 *.pyc 2 2 inputs/ 3 3 outputs/ 4 + wip/ 4 5 vm.py 5 6 search.py 6 7 advent.py
+96
2022/day17.py
··· 1 + import fileinput 2 + from utils import Point, N, S, E, W 3 + 4 + 5 + ROCKS = [ 6 + [Point(0, 0), Point(1, 0), Point(2, 0), Point(3, 0)], 7 + [Point(1, 0), Point(0, 1), Point(1, 1), Point(2, 1), Point(1, 2)], 8 + [Point(0, 0), Point(1, 0), Point(2, 0), Point(2, 1), Point(2, 2)], 9 + [Point(0, 0), Point(0, 1), Point(0, 2), Point(0, 3)], 10 + [Point(0, 0), Point(1, 0), Point(0, 1), Point(1, 1)], 11 + ] 12 + 13 + 14 + pattern = fileinput.input()[0].strip() 15 + lcm = len(pattern) * len(ROCKS) 16 + 17 + def simulate(target_rocks, key_height=10): 18 + tower_hats = {} 19 + curr_rock = None 20 + 21 + move_num = 0 22 + rocks = 0 23 + height = 0 24 + bonus_height = 0 25 + 26 + chamber = {Point(x, 0): "#" for x in range(7)} 27 + 28 + while rocks < target_rocks: 29 + if curr_rock is None: 30 + # Check for a cycle. 31 + if rocks % lcm == 0 and bonus_height == 0: 32 + key = '' 33 + for y in range(key_height): 34 + key += ''.join(chamber.get(Point(x, height - y), ".") for x in range(7)) 35 + key += '\n' 36 + 37 + # Jump forward because we found a cycle, then finish up the simulation. 38 + if key in tower_hats: 39 + last_height, last_rocks = tower_hats[key] 40 + 41 + # Deltas from the last time we saw the hat. 42 + cycle_height = height - last_height 43 + cycle_rocks = rocks - last_rocks 44 + 45 + # Safe to jump forward this many cycles. 46 + n_cycles = (target_rocks - rocks) // cycle_rocks 47 + 48 + # Store how much extra height we gained implicitly, 49 + # otherwise future pieces will spawn way too high 50 + # compared to the state of the chamber. 51 + bonus_height += n_cycles * cycle_height 52 + rocks += n_cycles * cycle_rocks 53 + 54 + else: 55 + tower_hats[key] = (height, rocks) 56 + 57 + # Spawn new rock. 58 + curr_rock = [p + N * (height + 4) + (E * 2) for p in ROCKS[rocks % len(ROCKS)]] 59 + 60 + 61 + # Try to move the falling rock based on the jet of gas. 62 + if pattern[move_num % len(pattern)] == '>': 63 + # Does the right wall block us? 64 + if any(p.x >= 6 for p in curr_rock): 65 + pass 66 + # Does another rock at rest block us? 67 + elif any(p + E in chamber for p in curr_rock): 68 + pass 69 + else: 70 + curr_rock = [p + E for p in curr_rock] 71 + else: 72 + if any(p.x <= 0 for p in curr_rock): 73 + pass 74 + elif any(p + W in chamber for p in curr_rock): 75 + pass 76 + else: 77 + curr_rock = [p + W for p in curr_rock] 78 + 79 + # Do we come to rest? 80 + if any(chamber.get(p + S) == '#' for p in curr_rock): 81 + for r in curr_rock: 82 + chamber[r] = "#" 83 + height = max(height, r.y) 84 + 85 + curr_rock = None 86 + rocks += 1 87 + 88 + else: 89 + curr_rock = [r + S for r in curr_rock] 90 + 91 + move_num += 1 92 + 93 + return height + bonus_height 94 + 95 + print("Part 1:", simulate(2022)) 96 + print("Part 2:", simulate(1_000_000_000_000, key_height=16)) # 18 good