diff --git a/2024/pyproject.toml b/2024/pyproject.toml index f3333f8..cb3a695 100644 --- a/2024/pyproject.toml +++ b/2024/pyproject.toml @@ -6,6 +6,7 @@ readme = "README.md" requires-python = ">=3.12" dependencies = [ "click>=8.1.7", + "networkx>=3.4.2", "numpy>=2.1.2", ] diff --git a/2024/src/aoc/days/day23.py b/2024/src/aoc/days/day23.py new file mode 100644 index 0000000..86e07ec --- /dev/null +++ b/2024/src/aoc/days/day23.py @@ -0,0 +1,42 @@ +from collections import defaultdict + +import networkx + +from . import SeparateRunner + + +class DayRunner(SeparateRunner): + @classmethod + def part1(cls, input: str) -> int: + edges = defaultdict(set) + + for line in input.strip().split("\n"): + a, b = line.split("-") + edges[a].add(b) + edges[b].add(a) + + found = set() + + for a, out in edges.items(): + if a[0] != "t": + continue + + for b in out: + for c in edges[b]: + if c in out: + found.add(tuple(sorted([a, b, c]))) + + return len(found) + + @classmethod + def part2(cls, input: str) -> str: + graph = networkx.Graph() + + for line in input.strip().split("\n"): + a, b = line.split("-") + graph.add_edge(a, b) + + cliques = networkx.find_cliques(graph) + max_clique = max(cliques, key=len) + + return ",".join(sorted(max_clique)) diff --git a/2024/tests/samples/23.txt b/2024/tests/samples/23.txt new file mode 100644 index 0000000..3d49766 --- /dev/null +++ b/2024/tests/samples/23.txt @@ -0,0 +1,32 @@ +kh-tc +qp-kh +de-cg +ka-co +yn-aq +qp-ub +cg-tb +vc-aq +tb-ka +wh-tc +yn-cg +kh-ub +ta-co +de-co +tc-td +tb-wq +wh-td +ta-ka +td-qp +aq-cg +wq-ub +ub-vc +de-ta +wq-aq +wq-vc +wh-yn +ka-de +kh-ta +co-tc +wh-qp +tb-vc +td-yn diff --git a/2024/tests/test_day23.py b/2024/tests/test_day23.py new file mode 100644 index 0000000..3e4bbda --- /dev/null +++ b/2024/tests/test_day23.py @@ -0,0 +1,11 @@ +from aoc.days.day23 import DayRunner + +from . import get_data + + +def test_sample_part1() -> None: + assert DayRunner.part1(get_data(23)) == 7 + + +def test_sample_part2() -> None: + assert DayRunner.part2(get_data(23)) == "co,de,ka,ta" diff --git a/2024/uv.lock b/2024/uv.lock index 3c62d22..df3b080 100644 --- a/2024/uv.lock +++ b/2024/uv.lock @@ -7,6 +7,7 @@ version = "0.1.0" source = { editable = "." } dependencies = [ { name = "click" }, + { name = "networkx" }, { name = "numpy" }, ] @@ -20,6 +21,7 @@ dev = [ [package.metadata] requires-dist = [ { name = "click", specifier = ">=8.1.7" }, + { name = "networkx", specifier = ">=3.4.2" }, { name = "numpy", specifier = ">=2.1.2" }, ] @@ -35,7 +37,7 @@ name = "click" version = "8.1.7" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "platform_system == 'Windows'" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 } wheels = [ @@ -92,6 +94,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695 }, ] +[[package]] +name = "networkx" +version = "3.4.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/1d/06475e1cd5264c0b870ea2cc6fdb3e37177c1e565c43f56ff17a10e3937f/networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1", size = 2151368 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f", size = 1723263 }, +] + [[package]] name = "numpy" version = "2.1.2"