From 453db1c29a1aa73a956eaa0fe5d345eb19d82dbb Mon Sep 17 00:00:00 2001 From: Brian Peck Date: Sun, 22 Dec 2024 22:12:43 -0800 Subject: [PATCH] Day 23 2024 (#287) --- .../peckb/aoc/_2024/calendar/day23/Day23.kt | 71 +++++++++++++++++++ .../peckb/aoc/_2024/calendar/day23/README.md | 1 + .../me/peckb/aoc/_2024/TestDayComponent.kt | 2 + .../aoc/_2024/calendar/day23/Day23Test.kt | 32 +++++++++ 4 files changed, 106 insertions(+) create mode 100644 src/main/kotlin/me/peckb/aoc/_2024/calendar/day23/Day23.kt create mode 100644 src/main/kotlin/me/peckb/aoc/_2024/calendar/day23/README.md create mode 100644 src/test/kotlin/me/peckb/aoc/_2024/calendar/day23/Day23Test.kt diff --git a/src/main/kotlin/me/peckb/aoc/_2024/calendar/day23/Day23.kt b/src/main/kotlin/me/peckb/aoc/_2024/calendar/day23/Day23.kt new file mode 100644 index 00000000..6ee84167 --- /dev/null +++ b/src/main/kotlin/me/peckb/aoc/_2024/calendar/day23/Day23.kt @@ -0,0 +1,71 @@ +package me.peckb.aoc._2024.calendar.day23 + +import javax.inject.Inject +import me.peckb.aoc.generators.InputGenerator.InputGeneratorFactory + +class Day23 @Inject constructor( + private val generatorFactory: InputGeneratorFactory, +) { + fun partOne(filename: String) = generatorFactory.forFile(filename).readAs(::connection) { input -> + val connections = findFriends(input) + val triplets = mutableSetOf>() + + findCommonFriend(connections) { me, them, ourFriends -> + ourFriends.forEach { ourFriend -> triplets.add(setOf(me, them, ourFriend)) } + } + + triplets.count { group -> group.any { it.startsWith('t') } } + } + + fun partTwo(filename: String) = generatorFactory.forFile(filename).readAs(::connection) { input -> + val connections = findFriends(input) + val friends = mutableSetOf>() + + findCommonFriend(connections) { me, them, ourFriends -> + if (ourFriends.isNotEmpty()) { + val everyFriend = ourFriends.all { maybeMutual -> + ourFriends.minus(maybeMutual).all { + (maybeMutual in connections[it]!!) + } + } + if (everyFriend) { + friends.add(ourFriends.plus(me).plus(them)) + } + } + } + + friends.maxBy { it.size }.toList().sorted().joinToString(",") + } + + private fun connection(line: String) : Pair { + return line.split("-").let { (a, b) -> a to b } + } + + private fun findFriends(input: Sequence>): MutableMap> { + val connections = mutableMapOf>() + + input.forEach { (c1, c2) -> + connections.merge(c1, setOf(c2)) { a, b -> a + b } + connections.merge(c2, setOf(c1)) { a, b -> a + b } + } + + return connections + } + + private fun findCommonFriend(connections: Map>, handleFriends: (String, String, Set) -> Unit) { + val keys = connections.keys.toList() + (0 until keys.size - 2).forEach { i -> + val me = keys[i] + val myFriends = connections[me]!! + + (i + 1 until keys.size - 1).forEach { j -> + val them = keys[j] + val theirFriends = connections[them]!! + + if (me in theirFriends) { + handleFriends(me, them, myFriends.intersect(theirFriends)) + } + } + } + } +} diff --git a/src/main/kotlin/me/peckb/aoc/_2024/calendar/day23/README.md b/src/main/kotlin/me/peckb/aoc/_2024/calendar/day23/README.md new file mode 100644 index 00000000..5ffa3cb4 --- /dev/null +++ b/src/main/kotlin/me/peckb/aoc/_2024/calendar/day23/README.md @@ -0,0 +1 @@ +## [Day 23: LAN Party](https://adventofcode.com/2024/day/23) \ No newline at end of file diff --git a/src/test/kotlin/me/peckb/aoc/_2024/TestDayComponent.kt b/src/test/kotlin/me/peckb/aoc/_2024/TestDayComponent.kt index e3e16447..ec833387 100644 --- a/src/test/kotlin/me/peckb/aoc/_2024/TestDayComponent.kt +++ b/src/test/kotlin/me/peckb/aoc/_2024/TestDayComponent.kt @@ -22,6 +22,7 @@ import me.peckb.aoc._2024.calendar.day19.Day19Test import me.peckb.aoc._2024.calendar.day20.Day20Test import me.peckb.aoc._2024.calendar.day21.Day21Test import me.peckb.aoc._2024.calendar.day22.Day22Test +import me.peckb.aoc._2024.calendar.day23.Day23Test import javax.inject.Singleton import me.peckb.aoc.DayComponent import me.peckb.aoc.InputModule @@ -52,4 +53,5 @@ internal interface TestDayComponent : DayComponent { fun inject(day20Test: Day20Test) fun inject(day21Test: Day21Test) fun inject(day22Test: Day22Test) + fun inject(day23Test: Day23Test) } diff --git a/src/test/kotlin/me/peckb/aoc/_2024/calendar/day23/Day23Test.kt b/src/test/kotlin/me/peckb/aoc/_2024/calendar/day23/Day23Test.kt new file mode 100644 index 00000000..b0fb7250 --- /dev/null +++ b/src/test/kotlin/me/peckb/aoc/_2024/calendar/day23/Day23Test.kt @@ -0,0 +1,32 @@ +package me.peckb.aoc._2024.calendar.day23 + +import javax.inject.Inject + +import me.peckb.aoc._2024.DaggerTestDayComponent +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test + +internal class Day23Test { + @Inject + lateinit var day23: Day23 + + @BeforeEach + fun setup() { + DaggerTestDayComponent.create().inject(this) + } + + @Test + fun testDay23PartOne() { + assertEquals(998, day23.partOne(DAY_23)) + } + + @Test + fun testDay23PartTwo() { + assertEquals("cc,ff,fh,fr,ny,oa,pl,rg,uj,wd,xn,xs,zw", day23.partTwo(DAY_23)) + } + + companion object { + private const val DAY_23: String = "advent-of-code-input/2024/day23.input" + } +}