Skip to content

Commit 0569bb9

Browse files
committed
AoC 2023 Day 25 - general solution
1 parent c4a9b83 commit 0569bb9

File tree

1 file changed

+31
-39
lines changed

1 file changed

+31
-39
lines changed

src/main/python/AoC2023_25.py

Lines changed: 31 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
from __future__ import annotations
77

8+
import random
89
import sys
910
from collections import defaultdict
1011
from copy import deepcopy
@@ -33,37 +34,33 @@
3334

3435

3536
class Graph(NamedTuple):
36-
edges: dict[str, set[str]]
37+
edges: dict[str, list[str]]
3738

3839
@classmethod
3940
def from_input(cls, input: InputData) -> Graph:
40-
edges = defaultdict[str, set[str]](set)
41+
edges = defaultdict[str, list[str]](list)
4142
for line in input:
4243
key, values = line.split(": ")
43-
edges[key] |= {_ for _ in values.split()}
44+
edges[key] += [_ for _ in values.split()]
4445
for v in values.split():
45-
edges[v].add(key)
46+
edges[v].append(key)
4647
return Graph(edges)
4748

48-
def remove_edges(self, edges: list[tuple[str, str]]) -> Graph:
49-
new_edges = deepcopy(self.edges)
50-
for edge in edges:
51-
first, second = edge
52-
new_edges[first].remove(second)
53-
new_edges[second].remove(first)
54-
return Graph(new_edges)
49+
def combine_nodes(self, node_1: str, node_2: str, new_node: str) -> Graph:
50+
self.edges[new_node] = [
51+
d for d in self.edges[node_1] if d != node_2
52+
] + [d for d in self.edges[node_2] if d != node_1]
53+
for node in {node_1, node_2}:
54+
for dst in self.edges[node]:
55+
self.edges[dst] = [
56+
new_node if d == node else d for d in self.edges[dst]
57+
]
58+
del self.edges[node]
59+
return Graph(self.edges)
5560

5661
def get_connected(self, node: str) -> set[str]:
5762
return flood_fill(node, lambda n: (_ for _ in self.edges[n]))
5863

59-
def visualize(self, file_name: str) -> None:
60-
with open(file_name, "w") as f:
61-
print("Graph {", file=f)
62-
for k, v in self.edges.items():
63-
for vv in v:
64-
print(f"{k} -- {vv}", file=f)
65-
print("}", file=f)
66-
6764

6865
Input = Graph
6966
Output1 = int
@@ -74,31 +71,26 @@ class Solution(SolutionBase[Input, Output1, Output2]):
7471
def parse_input(self, input_data: InputData) -> Input:
7572
return Graph.from_input(input_data)
7673

77-
def solve_1(
78-
self, graph: Input, disconnects: list[tuple[str, str]]
79-
) -> Output1:
80-
g = graph.remove_edges(disconnects)
81-
first = g.get_connected(disconnects[0][0])
82-
second = g.get_connected(disconnects[0][1])
83-
return len(first) * len(second)
84-
85-
def sample_1(self, graph: Input) -> Output1:
86-
return self.solve_1(
87-
graph, [("hfx", "pzl"), ("bvb", "cmg"), ("nvd", "jqt")]
88-
)
89-
9074
def part_1(self, graph: Input) -> Output1:
91-
# visualize with graphviz/neato:
92-
# graph.visualize("/mnt/c/temp/graph.dot")
93-
# -> to cut: ssd--xqh, nrs--khn, qlc--mqb
94-
return self.solve_1(
95-
graph, [("ssd", "xqh"), ("nrs", "khn"), ("qlc", "mqb")]
96-
)
75+
while True:
76+
g = deepcopy(graph)
77+
counts = {node: 1 for node in g.edges.keys()}
78+
while len(g.edges) > 2:
79+
a = random.sample(list(g.edges.keys()), 1)[0]
80+
b = random.sample(list(g.edges[a]), 1)[0]
81+
new_node = f"{a}-{b}"
82+
counts[new_node] = counts.get(a, 0) + counts.get(b, 0)
83+
del counts[a]
84+
del counts[b]
85+
g = g.combine_nodes(a, b, new_node)
86+
a, b = g.edges.keys()
87+
if len(g.edges[a]) == 3:
88+
return counts[a] * counts[b]
9789

9890
def part_2(self, input: Input) -> Output2:
9991
return "🎄"
10092

101-
@aoc_samples((("sample_1", TEST, 54),))
93+
@aoc_samples((("part_1", TEST, 54),))
10294
def samples(self) -> None:
10395
pass
10496

0 commit comments

Comments
 (0)