advent-of-code/2017-python/solutions/day_07.py

99 lines
3 KiB
Python
Raw Normal View History

2021-11-01 16:40:46 +01:00
from solutions import BaseSolution
class Program:
def __init__(self, data=None):
if data:
name, weight, disc = self._parse(data)
self.name = name
self.weight = weight
self.disc = disc
def __repr__(self):
return str(self.name)
def _parse(self, data):
disc = []
try:
name, weight = data.split()
except ValueError:
name, weight, _, *disc = data.split()
2025-05-06 20:14:58 +02:00
weight = int(weight[1 : len(weight) - 1])
disc = tuple(p.replace(",", "") for p in disc)
2021-11-01 16:40:46 +01:00
return name, weight, disc
def has_disc(self):
return len(self.disc) > 0
def unseen_discs(self, seen_discs):
return [t for t in self.disc if t not in seen_discs]
class Solution(BaseSolution):
2025-05-06 20:14:58 +02:00
input_file = "07.txt"
2021-11-01 16:40:46 +01:00
def __str__(self):
2025-05-06 20:14:58 +02:00
return "Day 7: Recursive Circus"
2021-11-01 16:40:46 +01:00
def _get_programs(self, puzzle_input):
return [Program(data) for data in puzzle_input.splitlines()]
def _get_discs(self, disc, programs):
2025-05-06 20:14:58 +02:00
subdisc = [
{"own_weight": p.weight, "obj": p} for p in programs if p.name in disc
]
2021-11-01 16:40:46 +01:00
for t in subdisc:
2025-05-06 20:14:58 +02:00
t["weight"] = t["own_weight"]
if t["obj"].has_disc():
t["disc"] = self._get_discs(t["obj"].disc, programs)
t["weight"] += sum([st["weight"] for st in t["disc"]])
del t["obj"]
2021-11-01 16:40:46 +01:00
return subdisc
def _find_unbalanced_disc(self, disc):
2025-05-06 20:14:58 +02:00
disc = sorted(disc, key=lambda t: t["weight"])
if not disc[0]["weight"] < disc[1]["weight"]:
disc = sorted(disc, key=lambda t: t["weight"], reverse=True)
return disc[0], disc[1]["weight"] - disc[0]["weight"]
2021-11-01 16:40:46 +01:00
def solve(self, puzzle_input):
programs = self._get_programs(puzzle_input)
programs_with_discs = []
seen = []
for p in programs:
if p.has_disc():
programs_with_discs.append(p)
else:
seen.append(p.name)
for p in programs_with_discs:
unseen = p.unseen_discs(seen)
if len(unseen) > 0:
seen += unseen
2025-05-06 20:14:58 +02:00
bottom_program = list(
filter(lambda p: p.name not in seen, programs_with_discs)
)[0]
2021-11-01 16:40:46 +01:00
return bottom_program
def solve_again(self, puzzle_input):
programs = self._get_programs(puzzle_input)
bottom_program = self.solve(puzzle_input)
disc_tree = {
2025-05-06 20:14:58 +02:00
"own_weight": bottom_program.weight,
"disc": self._get_discs(bottom_program.disc, programs),
2021-11-01 16:40:46 +01:00
}
diff = -1
unbalanced = True
while unbalanced:
2025-05-06 20:14:58 +02:00
disc, new_diff = self._find_unbalanced_disc(disc_tree["disc"])
2021-11-01 16:40:46 +01:00
if new_diff == 0:
unbalanced = False
else:
disc_tree = disc
diff = new_diff
2025-05-06 20:14:58 +02:00
return disc_tree["own_weight"] + diff
2021-11-01 16:40:46 +01:00
2025-05-06 20:14:58 +02:00
if __name__ == "__main__":
2021-11-01 16:40:46 +01:00
solution = Solution()
solution.show_results()