from lib import get_data, str_to_ints, add2 def above(p): return add2(p, (0, -1)) def below(p): return add2(p, (0, 1)) def right(p): return add2(p, (1, 0)) def left(p): return add2(p, (-1, 0)) def print2d(xs, ys=[], zs=[], cs=".#~|"): xs, ys, zs = set(xs), set(ys), set(zs) all = xs | ys | zs x_min, x_max, y_min, y_max = 10**9, 0, 10**9, 0 for x, y in all: x_min = min(x_min, x) y_min = min(y_min, y) x_max = max(x_max, x) y_max = max(y_max, y) for y in range(y_min, y_max + 1): row = "" for x in range(x_min, x_max + 1): if (x, y) in xs: row += cs[1] elif (x, y) in ys: row += cs[2] elif (x, y) in zs: row += cs[3] else: row += cs[0] print(row) def part_1(data): sand = [] max_y = 0 min_y = 10**9 for line in data.splitlines(): line = line.strip() a, b, c = str_to_ints(line) if line.startswith("x"): x = a for y in range(b, c + 1): max_y = max(max_y, y) min_y = min(min_y, y) sand.append((x, y)) elif line.startswith("y"): y = a max_y = max(max_y, y) min_y = min(min_y, y) for x in range(b, c + 1): sand.append((x, y)) else: assert False # TODO: probably should use 2D array for better perf sources = [(500, 0)] water = set() sand = set(sand) water_rest = set() while sources: source = sources.pop() current = below(source) while current[1] <= max_y: if current[1] < min_y: current = below(current) elif current in water_rest: break elif below(current) in sand or below(current) in water_rest: water.add(current) c = current to_water_rest = [current] left_sand, right_sand = False, False while True: c = right(c) if c in sand: right_sand = True break elif below(c) in sand or below(c) in water_rest: water.add(c) to_water_rest.append(c) else: # it's empty underneath water.add(c) sources.append(c) break c = current while True: c = left(c) if c in sand: left_sand = True break elif below(c) in sand or below(c) in water_rest: water.add(c) to_water_rest.append(c) else: # it's empty underneath water.add(c) sources.append(c) break if left_sand and right_sand: sources.append(above(above(current))) for w in to_water_rest: water_rest.add(w) break else: water.add(current) current = below(current) # print2d(sand, water_rest, water) # print(sources) # input() current_water = len(water_rest | water) print(current_water) print(len(water_rest)) def main(): data = get_data(__file__) part_1(data) if __name__ == "__main__": main()