DEV Community

Discussion on: AoC Day 1: Chronal Calibration

Collapse
 
jbristow profile image
Jon Bristow • Edited

Kotlin Solution!

Part 1

Please exuse my tricked out kotlin, I've added some personal extension functions to let me think about list comprehensions more simply.

private fun String.parseN() = let { (head, tail) ->
    when (head) {
        '+' -> 1
        '-' -> -1
        else -> throw Exception("Illegal input!")
    } * tail.toInt()
}

fun answer1(input: List<String>) = input.sumBy(String::parseN)

Part 2

I made a silly mistake, and lost about an hour trying to figure out where I went wrong. I should set up my test runners ahead of day 2 so I don't end up with this same kind of typo.

fun answer2(input: List<String>): Int {
    val ns = input.map(String::parseN).scan(Int::plus)
    val ending = ns.last
    return (sequenceOf(listOf(0)) + generateSequence(ns) {
        it.map(ending::plus)
    }).findFirstDupe(emptySet())
}


tailrec fun Sequence<List<Int>>.findFirstDupe(seen: Set<Int>): Int {
    val (head, tail) = this
    val intersections = head intersect seen
    return when {
        intersections.isNotEmpty() -> head.find { it in intersections }!!
        else -> tail.findFirstDupe(seen + head)
    }
}

/**
 * My prewritten `scan` function... it's just a `fold` that keeps every step.
 */
fun <A, B> Sequence<A>.scan(initial: B, operation: (B, A) -> B) =
        fold(sequenceOf(initial)) { scanList, curr ->
            scanList + operation(scanList.last(), curr)
        }

Part 2 is "slow", but it's still under a minute 5 seconds to brute force through 150 iterations (or so) of the cycle.