64 lines
2.3 KiB
Python
64 lines
2.3 KiB
Python
# SPDX-License-Identifier: MIT
|
|
# Copyright (c) 2021 Akumatic
|
|
#
|
|
# https://adventofcode.com/2021/day/22
|
|
|
|
from collections import defaultdict
|
|
|
|
def parse_line(line: str) -> str:
|
|
state = True if line.startswith("on") else False
|
|
coords = line[3 if state else 4:].split(",")
|
|
return [state] + [(int(p[0]), int(p[1])) for p in (pos[2:].split("..") for pos in coords)]
|
|
|
|
def read_file(filename: str = "input.txt") -> defaultdict:
|
|
with open(f"{__file__.rstrip('code.py')}{filename}", "r") as f:
|
|
return [parse_line(line) for line in f.read().strip().split("\n")]
|
|
|
|
def areas_overlapping(a: tuple, b: tuple) -> bool:
|
|
return a[0][0] <= b[0][1] and a[0][1] >= b[0][0] \
|
|
and a[1][0] <= b[1][1] and a[1][1] >= b[1][0] \
|
|
and a[2][0] <= b[2][1] and a[2][1] >= b[2][0]
|
|
|
|
def calculate_overlap(a: tuple, b: tuple) -> tuple:
|
|
return ((max(a[0][0], b[0][0]), min(a[0][1], b[0][1])),
|
|
(max(a[1][0], b[1][0]), min(a[1][1], b[1][1])),
|
|
(max(a[2][0], b[2][0]), min(a[2][1], b[2][1])))
|
|
|
|
def cubes_in_cuboid(cuboid: tuple) -> int:
|
|
return (cuboid[0][1] - cuboid[0][0] + 1) * \
|
|
(cuboid[1][1] - cuboid[1][0] + 1) * (cuboid[2][1] - cuboid[2][0] + 1)
|
|
|
|
def changes_adding_cuboid(cuboids: list, state: bool, cuboid: tuple) -> list:
|
|
changes = []
|
|
signum = 1 if state else -1
|
|
for cub, sig in cuboids:
|
|
if areas_overlapping(cub, cuboid):
|
|
changes.append((calculate_overlap(cub, cuboid), -sig))
|
|
if signum == 1:
|
|
changes.append((cuboid, 1))
|
|
return changes
|
|
|
|
def part1(instructions: list) -> int:
|
|
reactor = defaultdict(bool)
|
|
area = ((-50, 50), (-50, 50), (-50, 50))
|
|
for state, x, y, z in instructions:
|
|
cur = (x, y, z)
|
|
if not areas_overlapping(cur, area):
|
|
continue
|
|
a, b, c = calculate_overlap(cur, area)
|
|
cubes = [(u, v, w) for u in range(a[0], a[1]+1) for v in range(b[0], b[1]+1) for w in range(c[0], c[1]+1)]
|
|
for cube in cubes:
|
|
reactor[cube] = state
|
|
return sum(reactor.values())
|
|
|
|
def part2(instructions: list) -> int:
|
|
cuboids = list()
|
|
for state, x, y, z in instructions:
|
|
cuboids += changes_adding_cuboid(cuboids, state, (x, y, z))
|
|
return sum(cubes_in_cuboid(cub) * sig for cub, sig in cuboids)
|
|
|
|
if __name__ == "__main__":
|
|
vals = read_file()
|
|
print(f"Part 1: {part1(vals)}")
|
|
print(f"Part 2: {part2(vals)}")
|
|
|