Skip to content

Commit caee02b

Browse files
committed
Day 22, 23
1 parent f401656 commit caee02b

File tree

5 files changed

+269
-2
lines changed

5 files changed

+269
-2
lines changed

src/main/kotlin/common/datastructures/DisjointSets.kt

+9-2
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ class DisjointSets<T> {
55
val parent: MutableMap<T, T> = mutableMapOf()
66

77
val size get() = rank.size
8-
val sets: MutableSet<T> = mutableSetOf()
8+
val sets: MutableMap<T, MutableSet<T>> = mutableMapOf()
99

1010
private fun checkInit(x: T) {
1111
if (x in rank) return
1212
rank[x] = 0
1313
parent[x] = x
14-
sets += x
14+
sets[x] = mutableSetOf(x)
1515
}
1616

1717
fun find(x: T): T {
@@ -22,6 +22,10 @@ class DisjointSets<T> {
2222
return parent[x]!!
2323
}
2424

25+
fun elementsInSet(root: T): Set<T> {
26+
return sets.getValue(root)
27+
}
28+
2529
fun union(x: T, y: T) {
2630
val rootX = find(x)
2731
val rootY = find(y)
@@ -30,13 +34,16 @@ class DisjointSets<T> {
3034
}
3135
if (rank[rootX]!! < rank[rootY]!!) {
3236
parent[rootX] = rootY
37+
sets.getValue(rootY).addAll(sets.getValue(rootX))
3338
sets -= rootX
3439
} else if (rank[rootY]!! < rank[rootX]!!) {
3540
parent[rootY] = rootX
41+
sets.getValue(rootX).addAll(sets.getValue(rootY))
3642
sets -= rootY
3743
} else {
3844
parent[rootY] = rootX
3945
rank[rootX] = rank[rootX]!! + 1
46+
sets.getValue(rootX).addAll(sets.getValue(rootY))
4047
sets -= rootY
4148
}
4249
}

src/main/kotlin/y24/Day22.kt

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package y24
2+
3+
import common.puzzle.solvePuzzle
4+
import common.puzzle.Input
5+
import common.puzzle.Puzzle
6+
import common.datastructures.*
7+
import common.ext.*
8+
import common.util.*
9+
import java.util.*
10+
import kotlin.math.*
11+
import kotlin.system.exitProcess
12+
13+
14+
fun main() = solvePuzzle(year = 2024, day = 22, dryRun = true) { Day22(it) }
15+
16+
// 2^24=16777216
17+
class Day22(val input: Input) : Puzzle {
18+
19+
fun evolve(secret: Long): Long {
20+
var s = secret
21+
s = (s shl 6) xor s
22+
s = s and 16777215 // 2^24 - 1
23+
24+
s = (s shr 5) xor s
25+
s = s and 16777215 // 2^24 - 1
26+
27+
s = (s shl 11) xor s
28+
s = s and 16777215 // 2^24 - 1
29+
30+
return s
31+
}
32+
33+
fun sequence(secret: Long, n: Int): List<Long> {
34+
var s = secret
35+
return (0..n).map {
36+
s.also { s = evolve(s) }
37+
}
38+
}
39+
40+
override fun solveLevel1(): Any {
41+
return input.lines.sumOf { sequence(it.toLong(), 2000).last() }
42+
}
43+
44+
data class Sequence(
45+
val priceDiffs: List<Long>,
46+
)
47+
48+
private fun computeBananas(prices: List<Long>, diffs: List<Long>): Map<Sequence, Long> {
49+
val result = mutableMapOf<Sequence, Long>()
50+
for (i in 0 until diffs.size - 3) {
51+
val sequence = Sequence(diffs.subList(i, i + 4))
52+
val bananas = prices[i + 4]
53+
if (sequence !in result) {
54+
result[sequence] = bananas
55+
}
56+
}
57+
58+
return result
59+
}
60+
61+
override fun solveLevel2(): Any {
62+
val sequences = input.lines.map { sequence(it.toLong(), 2000) }
63+
val sequencePrices = sequences.map { sequence ->
64+
sequence.map { l -> l % 10 }
65+
}
66+
val diffs = sequencePrices.map { prices ->
67+
prices.mapIndexedNotNull { index, price ->
68+
if (index == 0) {
69+
null
70+
} else {
71+
price - prices[index - 1]
72+
}
73+
}
74+
}
75+
76+
val bananas = List(sequences.size) { i ->
77+
computeBananas(sequencePrices[i], diffs[i])
78+
}
79+
80+
val allSequences = bananas.flatMap { it.keys }.distinct()
81+
return allSequences.maxOf { seq ->
82+
bananas.sumOf { it[seq] ?: 0 }
83+
}
84+
}
85+
}

src/main/kotlin/y24/Day23.kt

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
@file:Suppress("UnstableApiUsage")
2+
package y24
3+
4+
import com.google.common.graph.Graph
5+
import com.google.common.graph.GraphBuilder
6+
import common.puzzle.solvePuzzle
7+
import common.puzzle.Input
8+
import common.puzzle.Puzzle
9+
import common.datastructures.*
10+
import common.ext.*
11+
import common.util.*
12+
import java.util.*
13+
import kotlin.math.*
14+
import kotlin.system.exitProcess
15+
16+
17+
fun main() = solvePuzzle(year = 2024, day = 23) { Day23(it) }
18+
19+
class Day23(val input: Input) : Puzzle {
20+
private val links = input.lines.map {
21+
val (a, b) = it.split("-")
22+
a to b
23+
}
24+
25+
private fun largestFullyConnectedSet(graph: Graph<String>, edges: List<String>, curSet: MutableSet<String>, i: Int): Set<String> {
26+
// Try adding edges i+
27+
var maxSet = curSet.toSet()
28+
for (j in i until edges.size) {
29+
// Try adding j
30+
if (curSet.any { it !in graph.adjacentNodes(edges[j]) }) {
31+
continue
32+
}
33+
34+
curSet += edges[j]
35+
val set = largestFullyConnectedSet(graph, edges, curSet, j + 1)
36+
if (set.size > maxSet.size) {
37+
maxSet = set.toSet()
38+
}
39+
curSet -= edges[j]
40+
}
41+
42+
return maxSet
43+
}
44+
45+
override fun solveLevel1(): Any {
46+
val graph = GraphBuilder.undirected().build<String>()
47+
links.forEach { (a, b) ->
48+
graph.putEdge(a, b)
49+
}
50+
51+
val uniqueSets = mutableSetOf<List<String>>()
52+
53+
graph.nodes().forEach { node ->
54+
val edges = graph.adjacentNodes(node).toList()
55+
for (i in edges.indices) {
56+
for (j in i + 1 until edges.size) {
57+
if (edges[j] !in graph.adjacentNodes(edges[i])) {
58+
continue
59+
}
60+
61+
val set = listOf(node, edges[i], edges[j])
62+
if (set.none { it.startsWith('t') }) {
63+
continue
64+
}
65+
66+
uniqueSets += set.sorted()
67+
}
68+
}
69+
}
70+
71+
return uniqueSets.size
72+
}
73+
74+
override fun solveLevel2(): Any {
75+
val graph = GraphBuilder.undirected().build<String>()
76+
links.forEach { (a, b) ->
77+
graph.putEdge(a, b)
78+
}
79+
80+
var maxSet: Set<String>? = null
81+
graph.nodes().forEach { node ->
82+
val max = largestFullyConnectedSet(graph, graph.adjacentNodes(node).toList(), mutableSetOf(node), 0)
83+
if (maxSet == null || max.size > maxSet!!.size) {
84+
maxSet = max
85+
}
86+
}
87+
88+
return maxSet!!.sorted().joinToString(",")
89+
}
90+
}

src/test/kotlin/y24/Day22Test.kt

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package y24
2+
3+
import common.puzzle.Input
4+
import org.junit.jupiter.api.Assertions.assertEquals
5+
import org.junit.jupiter.api.Test
6+
7+
internal class Day22Test {
8+
private val sample = Input("""
9+
1
10+
10
11+
100
12+
2024
13+
""".trimIndent())
14+
15+
private val day = Day22(sample)
16+
17+
@Test
18+
fun solveLevel1() {
19+
assertEquals(37327623L, day.solveLevel1())
20+
}
21+
22+
@Test
23+
fun solveLevel2() {
24+
assertEquals(23L, Day22(Input("""
25+
1
26+
2
27+
3
28+
2024
29+
""".trimIndent())).solveLevel2())
30+
}
31+
}

src/test/kotlin/y24/Day23Test.kt

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package y24
2+
3+
import common.puzzle.Input
4+
import org.junit.jupiter.api.Assertions.assertEquals
5+
import org.junit.jupiter.api.Test
6+
7+
internal class Day23Test {
8+
private val sample = Input("""
9+
kh-tc
10+
qp-kh
11+
de-cg
12+
ka-co
13+
yn-aq
14+
qp-ub
15+
cg-tb
16+
vc-aq
17+
tb-ka
18+
wh-tc
19+
yn-cg
20+
kh-ub
21+
ta-co
22+
de-co
23+
tc-td
24+
tb-wq
25+
wh-td
26+
ta-ka
27+
td-qp
28+
aq-cg
29+
wq-ub
30+
ub-vc
31+
de-ta
32+
wq-aq
33+
wq-vc
34+
wh-yn
35+
ka-de
36+
kh-ta
37+
co-tc
38+
wh-qp
39+
tb-vc
40+
td-yn
41+
""".trimIndent())
42+
43+
private val day = Day23(sample)
44+
45+
@Test
46+
fun solveLevel1() {
47+
assertEquals(7, day.solveLevel1())
48+
}
49+
50+
@Test
51+
fun solveLevel2() {
52+
assertEquals("co,de,ka,ta", day.solveLevel2())
53+
}
54+
}

0 commit comments

Comments
 (0)