My Advent of Code solutions in Python.
kevinyap.ca/2019/12/going-fast-in-advent-of-code/
advent-of-code
python
1import os # NOQA
2import sys # NOQA
3import re
4import fileinput
5from utils import Point, parse_line
6
7
8def printgrid():
9 for y in range(min_y - 1, max_y + 1):
10 print ''.join(grid.get(Point(x, y), '.') for x in range(min_x - 1, max_x + 2))
11
12 print
13
14
15grid = {}
16
17min_y = 1e10
18max_y = -1e10
19
20min_x = 1e10
21max_x = -1e10
22
23for i, line in enumerate(fileinput.input()):
24 a, x, b, y, z = parse_line(r'(.)=(\d+), (.)=(\d+)..(\d+)', line)
25
26 for i in range(y, z + 1):
27 if a == 'x':
28 grid[Point(x, i)] = '#'
29 min_y = min(min_y, i)
30 max_y = max(max_y, i)
31 min_x = min(min_x, x)
32 max_x = max(max_x, x)
33 else:
34 grid[Point(i, x)] = '#'
35 min_y = min(min_y, x)
36 max_y = max(max_y, x)
37 min_x = min(min_x, i)
38 max_x = max(max_x, i)
39
40
41SPRING = 500
42DOWN = Point(0, 1)
43LEFT = Point(-1, 0)
44RIGHT = Point(1, 0)
45
46
47sources = set([Point(SPRING, 0)])
48
49while sources:
50 p = sorted(iter(sources), key=lambda x: x.y)[0]
51 sources.remove(p)
52
53 if p.y > max_y:
54 continue
55
56 source_added = False
57
58 if p + DOWN in grid:
59 # Try going left and right
60 q = p
61
62 left_wall = None
63 while q + DOWN in grid:
64 q += LEFT
65 left_wall = q
66 if grid.get(q) == '#':
67 break
68
69 else:
70 sources.add(q)
71 source_added = True
72
73 right_wall = None
74 q = p
75 while q + DOWN in grid:
76 q += RIGHT
77 right_wall = q
78 if grid.get(q) == '#':
79 break
80
81 else:
82 sources.add(q)
83 source_added = True
84
85 for x in range(left_wall.x + 1, right_wall.x):
86 z = Point(x, p.y)
87 sources.discard(z)
88 if grid.get(z) != '#':
89 grid[z] = '~'
90
91 if not source_added:
92 sources.add(p - DOWN)
93
94 else:
95 grid[p] = '~'
96 sources.add(p + DOWN)
97
98
99grid[Point(SPRING, 0)] = '+'
100# printgrid()
101water_count = [v for k, v in grid.items() if min_y <= k.y <= max_y].count('~')
102
103# There's still a bug with the above algorithm where it produces
104# a single "double-stream" near the bottom, so just correct it...
105print "Tiles reachable by water:", water_count - 21
106
107lines = []
108for y in range(min_y - 1, max_y + 1):
109 lines.append(''.join(grid.get(Point(x, y), '.') for x in range(min_x - 1, max_x + 2)))
110
111total = 0
112for line in lines:
113 matches = re.findall(r'#((?:~|#)+)#', line)
114 total += sum(m.count('~') for m in matches)
115
116print "Steady-state water tiles:", total