<Advent of Code 2021 day 11> :thread:
# advent-of-code
a
d
Too bad I did have @Marcin Wisniowski’s
getAdjacentSides()
function
d
TIL
computeIfPresent()
- neat function
e
the
compute*
default methods on Map are additions in Java 8
👍 1
m
@Dan Fingal-Surma why the chunked(1)?
p
@Dan Fingal-Surma there is listOfNotNull in the stdlib
👍 1
m
https://github.com/mdekaste/AdventOfCode2021/blob/main/src/main/kotlin/year2021/day11/Day11.kt Using a map as an intermediate state to calculate neighbours, is disregarded after use. Trying to fit both part 1 and part 2 in the same function doesn't always look as nice as I want it to be.
sometimes I wish I could just use the oldschool for loop in these situations.
Copy code
for(var step = 0, steps == null || step < steps, step++){
    ...
}
just reads nicer to me than
Copy code
var step = 0
while(steps == null || step < steps){
    ...
    step++
}
StdlIb doesnt have open ranges so I can't do
Copy code
for(step in 0..steps){
    ....
}
which seems to me the best way to do it
k
m
A little late today (didn't feel like waking up at 5 AM on the weekend), but here is mine (part 2):
@David Whittaker It's
getAdjacent()
today,
getAdjacentSides()
does not return diagonals. 😄 Here is my utils file: https://gitlab.com/Nohus/adventofcode2021/-/blob/master/src/main/kotlin/utils/Geometry.kt
🆒 1
m
repurposed my code a bit to make the algorithm as pseudocodey as possible 😛
d
I didn’t realize you could directly
mapIndexed
on a String
n
I'm trying to find a super elegant way to write part2, I already have a step() function that returns the number of flashes. This is obviously a trivial exercise, could just do it with a while loop, but seems like there ought to be an elegant functional "one liner", but every time I try one, feels like something is missing for it
Maybe what's missing is a version of
count
that's a sequence, and counts forever? Python has this in itertools, it was my first thought.
p
For my solution part 1 and 2 were mostly the same
n
They are for me too
Copy code
fun part1() = getInputs().let { inputs -> (1..100).sumOf { inputs.step() } }
obviously, given step, part2() will be like 3-4 lines. I just wanted to make that bit as elegant as possible 🙂
Just left in the while loop for now
Copy code
fun getInputs() = (aocDataDir / "2021" / "day11.txt").useLines { lines ->
    lines.map { line -> line.mapTo(mutableListOf()) { it.toString().toInt() } }.toList()
}

fun List<List<Int>>.getNeighbors(row: Int, col: Int) = listOf(
    Pair(row-1, col), Pair(row+1, col), Pair(row, col-1), Pair(row, col+1),
    Pair(row+1, col+1), Pair(row+1, col-1), Pair(row-1, col+1), Pair(row-1, col-1)
).filter { getOrNull(it.first)?.getOrNull(it.second) != null }

fun List<MutableList<Int>>.startAvalanche(row: Int, col: Int): Long {
    if (this[row][col] == 10) {
        return 0
    }
    ++this[row][col]
    if (this[row][col] != 10) {
        return 0
    }
    return 1 + getNeighbors(row, col).sumOf { startAvalanche(it.first, it.second) }
}

fun List<MutableList<Int>>.step(): Long {
    val totalFlashes = withIndex().sumOf { row ->
        row.value.indices.sumOf { colIndex -> startAvalanche(row.index, colIndex) }
    }
    forEach { row -> row.indices.forEach { if (row[it] == 10) row[it] = 0 } }
    return totalFlashes
}

fun part1() = getInputs().let { inputs -> (1..100).sumOf { inputs.step() } }

fun part2(): Long {
    val inputs = getInputs()
    val size = inputs.sumOf { it.size.toLong() }
    var step = 1L
    while (inputs.step() != size) {
        ++step
    }
    return step
}

fun main() {
    println(part1())
    println(part2())
}
Alright I figured out the "clever" functional way. Side by side:
Copy code
fun part2(): Long {
    val inputs = getInputs()
    val size = inputs.sumOf { it.size.toLong() }
    var step = 1L
    while (inputs.step() != size) {
        ++step
    }
    return step
}

fun part2b(): Long {
    val inputs = getInputs()
    val size = inputs.sumOf { it.size.toLong() }
    return generateSequence(1L) {
        if (inputs.step() != size) it + 1 else null
    }.last()
}
t
I ended up using a sequence but was tempted by a recursive solution initially. It's late today because F1 qualifying took priority (and the race will tomorrow for sure!). • BlogCode
👍 1
n
@Michael de Kaste: you could use
for (step in 0 until steps)
though in this concrete case,
for (step in 1..steps)
is even nicer.
m
Yes I know, but steps was nullable in my context, but I already made it different 🙂
e
hasn't occurred in aoc yet, but in my real production code there's several instances of stuff like
for (i in nullable.orEmpty())
or
for (i in 0 until (count ?: 0))
. although you could of course use
nullable?.forEach { i -> }
or
repeat(count ?: 0) { i -> }
as well
d
I updated mine to use a
sequence
— much better
p
inspired to make a visualisation for this one, for the first time:

https://www.youtube.com/watch?v=GsSI8O_w33Q

👍 2