Skip to content

Commit

Permalink
feat(2024): day 23
Browse files Browse the repository at this point in the history
  • Loading branch information
scarf005 committed Jan 12, 2025
1 parent cea612a commit 76ecf85
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 0 deletions.
70 changes: 70 additions & 0 deletions 2024/day23.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package `2024`.day23

import prelude.*
import scala.collection.parallel.CollectionConverters.*
import scala.annotation.tailrec

type Connection = Map[String, Set[String]]

def parse(input: String): Connection = input
.split('\n')
.toSet
.flatMap { case s"$a-$b" => Set(a -> b, b -> a) }
.groupMap(_._1)(_._2)

def part1(input: String) =
val connection = parse(input)

extension (a: String)
inline infix def <->(b: String) =
connection(a).contains(b) && connection(b).contains(a)

def isValidTriangle(vertices: Set[String]): Boolean = vertices.toList match
case List(v1, v2, v3) => v1 <-> v2 && v2 <-> v3 && v3 <-> v1
case _ => false

connection.par
.flatMap { (vertex, neighbors) =>
neighbors
.subsets(2)
.map(_ + vertex)
.withFilter(_.exists(_.startsWith("t")))
.filter(isValidTriangle)
}
.toSet
.size

def part2(input: String) =
val connection = parse(input)
findMaximumCliqueBronKerbosch(connection).toList.sorted.mkString(",")

@main def main() =
val input = fromFile(".cache/2024/23.txt").mkString
println(part1(input))
println(part2(input))

def findMaximumCliqueBronKerbosch(connections: Connection): Set[String] =
def bronKerbosch(
potential: Set[String],
excluded: Set[String] = Set.empty,
result: Set[String] = Set.empty,
): Set[String] =
if (potential.isEmpty && excluded.isEmpty) then result
else
// Choose pivot to minimize branching
val pivot = (potential ++ excluded)
.maxBy(vertex => potential.count(connections(vertex).contains))

val remaining = potential -- connections(pivot)

remaining.foldLeft(Set.empty[String]) { (currentMax, vertex) =>
val neighbors = connections(vertex)
val newClique = bronKerbosch(
result = result + vertex,
potential = potential & neighbors,
excluded = excluded & neighbors,
)
if (newClique.size > currentMax.size) newClique else currentMax
}

bronKerbosch(potential = connections.keySet)
44 changes: 44 additions & 0 deletions 2024/day23.test.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package `2024`.day23

import munit.FunSuite
import prelude.dedent

val example = """
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
""".dedent

class Test extends FunSuite:
test("example"):
assertEquals(part1(example), 7)
assertEquals(part2(example), "co,de,ka,ta")

0 comments on commit 76ecf85

Please sign in to comment.