generated from public/aoc_template
124 lines
3.4 KiB
Python
124 lines
3.4 KiB
Python
from __future__ import annotations
|
|
from collections import deque
|
|
from tools.aoc import AOCDay
|
|
from typing import Any
|
|
|
|
|
|
class Component:
|
|
def __init__(self, name: str):
|
|
self.name = name
|
|
self.connections = set()
|
|
|
|
def __hash__(self) -> int:
|
|
return hash(self.name)
|
|
|
|
|
|
def separate(component1: Component, component2: Component) -> (int, int, int):
|
|
"""returns len(group1), len(group2), len(wires_to_disconnect)"""
|
|
group1, group2, wires_to_disconnect = set(), set(), set()
|
|
q1, q2 = deque([component1]), deque([component2])
|
|
while q1 or q2:
|
|
if q1 and len(q1) != 3:
|
|
c1 = q1.popleft()
|
|
if c1 in group1 or c1 in group2:
|
|
continue
|
|
group1.add(c1)
|
|
for c in c1.connections:
|
|
if c in group2:
|
|
wires_to_disconnect.add((c1, c) if c1.name < c.name else (c, c1))
|
|
else:
|
|
q1.append(c)
|
|
|
|
if q2 and len(q2) != 3:
|
|
c2 = q2.popleft()
|
|
if c2 in group1 or c2 in group2:
|
|
continue
|
|
group2.add(c2)
|
|
for c in c2.connections:
|
|
if c in group1:
|
|
wires_to_disconnect.add(((c2, c) if c2.name < c.name else (c, c2)))
|
|
else:
|
|
q2.append(c)
|
|
|
|
if len(q1) == 3 and len(q2) == 3:
|
|
return len(group1), len(group2), len(wires_to_disconnect)
|
|
|
|
return len(group1), len(group2), len(wires_to_disconnect)
|
|
|
|
|
|
class Wiring:
|
|
def __init__(self):
|
|
self.components = {}
|
|
|
|
def get_component(self, name: str):
|
|
if name not in self.components:
|
|
self.components[name] = Component(name)
|
|
|
|
return self.components[name]
|
|
|
|
def get_connections(self) -> set:
|
|
connections = set()
|
|
for component in self.components.values():
|
|
for connection in component.connections:
|
|
connections.add(
|
|
(component.name, connection.name)
|
|
if component.name < connection.name
|
|
else (connection.name, component.name)
|
|
)
|
|
|
|
return connections
|
|
|
|
@classmethod
|
|
def from_input(cls, data: list[str]) -> Wiring:
|
|
wiring = cls()
|
|
for line in data:
|
|
left, rights = line.split(": ")
|
|
rights = rights.split()
|
|
|
|
left = wiring.get_component(left)
|
|
for r in rights:
|
|
right = wiring.get_component(r)
|
|
left.connections.add(right)
|
|
right.connections.add(left)
|
|
|
|
return wiring
|
|
|
|
|
|
class Day(AOCDay):
|
|
inputs = [
|
|
[
|
|
# (54, "input25_test"), # Test breaks sometimes. Live always works?!
|
|
(545528, "input25_dennis"),
|
|
(544523, "input25"),
|
|
],
|
|
[
|
|
(None, "input25"),
|
|
],
|
|
]
|
|
|
|
def part1(self) -> Any:
|
|
wiring = Wiring.from_input(self.getInput())
|
|
the_first = wiring.get_component(next(iter(wiring.components)))
|
|
for component in wiring.components.values():
|
|
if component == the_first:
|
|
continue
|
|
|
|
g1, g2, c = separate(the_first, component)
|
|
if c == 3:
|
|
return g1 * g2
|
|
|
|
g1, g2, c = separate(component, the_first)
|
|
if c == 3:
|
|
return g1 * g2
|
|
|
|
print("Missed, try again.")
|
|
return ""
|
|
|
|
def part2(self) -> Any:
|
|
return ""
|
|
|
|
|
|
if __name__ == "__main__":
|
|
day = Day(2023, 25)
|
|
day.run(verbose=True)
|