-
Notifications
You must be signed in to change notification settings - Fork 0
/
aoc-18.kts
105 lines (84 loc) · 3.01 KB
/
aoc-18.kts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// https://adventofcode.com/2021/day/18
import java.io.File
fun input() = File("input/aoc-18.txt").readLines()
sealed class Snail {
class Regular(var v: Long) : Snail()
class Pair(var l: Snail, var r: Snail) : Snail()
override fun toString() = when (this) {
is Snail.Regular -> v.toString()
is Snail.Pair -> "[$l,$r]"
}
}
fun parse(s: String): Snail {
var p = 0
s.forEachIndexed { i, c ->
when (c) {
'[' -> p++
']' -> p--
',' -> if (p == 1) return Snail.Pair(
parse(s.substring(1, i)),
parse(s.substring(i + 1, s.lastIndex))
)
else -> if (p == 0) return Snail.Regular(s.toLong())
}
}
error("oops")
}
fun Snail.findDepth(a: List<Snail.Pair>, depth: Int): List<Snail.Pair>? = when (this) {
is Snail.Regular -> null
is Snail.Pair -> when {
depth == 0 -> a + this
else -> l.findDepth(a + this, depth - 1) ?: r.findDepth(a + this, depth - 1)
}
}
fun Snail.findValue(p: Snail.Pair, value: Int): Pair<Snail.Pair, Snail.Regular>? = when (this) {
is Snail.Regular -> if (v >= value) p to this else null
is Snail.Pair -> l.findValue(this, value) ?: r.findValue(this, value)
}
fun Snail.rightLeaf(): Snail.Regular = when (this) {
is Snail.Regular -> this
is Snail.Pair -> r.rightLeaf()
}
fun Snail.leftLeaf(): Snail.Regular = when (this) {
is Snail.Regular -> this
is Snail.Pair -> l.leftLeaf()
}
fun Snail.Regular.split() = Snail.Pair(Snail.Regular(v / 2), Snail.Regular(v / 2 + v % 2))
fun Snail.Pair.reduceOnce(): Boolean {
findDepth(listOf(this), 4)?.let { a ->
val pairs = a.reversed().windowed(2) { x -> x[1] to x[0] }
pairs.find { (p, s) -> s == p.r }?.let { (p, _) -> p.l.rightLeaf().v += (a.last().l as Snail.Regular).v }
pairs.find { (p, s) -> s == p.l }?.let { (p, _) -> p.r.leftLeaf().v += (a.last().r as Snail.Regular).v }
val s = a.last()
val p = a[a.lastIndex - 1]
if (s == p.l) p.l = Snail.Regular(0) else p.r = Snail.Regular(0)
return true
}
findValue(this, 10)?.let { (p, s) ->
if (p.l == s) p.l = s.split() else p.r = s.split()
return true
}
return false
}
fun Snail.Pair.reduce() = apply { while (reduceOnce()) {} }
fun Snail.magnitude(): Long = when (this) {
is Snail.Regular -> v
is Snail.Pair -> 3L * l.magnitude() + 2L * r.magnitude()
}
// Part 1.
fun p1(input: List<String>): Long {
val snails = input.map { parse(it) as Snail.Pair }
return snails.reduce { a, b -> Snail.Pair(a, b).reduce() }.magnitude()
}
// Part 2.
fun p2(input: List<String>): Long {
fun <S, T> product(s: Iterable<S>, t: Iterable<T>) =
s.asSequence().flatMap { l -> t.map { r -> l to r } }
return product(input, input)
.mapNotNull { (a, b) -> if (a != b) parse(a) to parse(b) else null }
.maxOf { (a, b) -> Snail.Pair(a, b).reduce().magnitude() }
}
with(input()) {
println(p1(this)) // 4433
println(p2(this)) // 4559
}