<Advent of Code 2021 day 4> :thread:
# advent-of-code
a
d
Is it "cheating" that I separated out the list of draw numbers into a string that I passed to the function?
🚫 1
👌 1
p
@Marcin Wisniowski cool solution! I hadn't thought that way. It looks simple now
🙏 1
c
Agreed, super clean! Nice job Marcin!
e
That is some great and concise way to get input parsed. Thanks for sharing.
p
j
Here we go 🎅 I put all the cells in
Map
such that the marking of them can be done quickly (not that it matters). https://github.com/The-Self-Taught-Software-Engineer/advent-of-code-2021/blob/master/src/main/kotlin/codes/jakob/aoc/Day04.kt
🎉 1
e
😍 1
m
https://github.com/mdekaste/AdventOfCode2021/blob/main/src/main/kotlin/year2021/day4/Day4.kt always feel like checking rows and cols can be done much cleaner, its the only clunky part of my code. Big fan of the chunked method though.
m
Here’s my solution. Interesting challenge!
Copy code
fun List<String>.day04(): Pair<Int, Int> {
    val numbers = first().split(",").map { it.toInt() }

    data class Pos(val x: Int, val y: Int)
    data class Slot(val pos: Pos, val number: Int, var bingo: Boolean = false)
    data class Board(val slots: List<Slot>)

    fun Board.isBingo() = sequence {
        for (i in 0..4) {
            yield((0..4).map { Pos(i, it) })
            yield((0..4).map { Pos(it, i) })
        }
    }.any { straight -> straight.all { pos -> slots.first { it.pos == pos }.bingo } }


    var boards = drop(1).chunked(6) { lines ->
        Board(slots = lines.drop(1).flatMapIndexed { y, row ->
            row.trim().split(Regex("""\s+""")).mapIndexed { x, n -> Slot(Pos(x, y), n.toInt()) }
        })
    }

    var winners = listOf<Int>()
    for (pick in numbers) {
        for (board in boards) {
            board.slots.filter { it.number == pick }.forEach { it.bingo = true }
            if (board.isBingo()) {
                winners = winners + pick * board.slots.filterNot { it.bingo }.sumOf { it.number }
                boards = boards - board
            }
        }
    }

    return winners.first() to winners.last()
}
t
After waking up late and having to run some errands (I am on US Eastern time and don't stay up late enough to jump on the puzzle), I'm finally done. Part 1 was fairly straight forward and part 2 is the reverse of part 1 (find the first to lose). • BlogCode Now I can go check on what y'all have done, which is my favorite part of this! 🙂
👍 3
p
Interesting one. Quite some went with a more mutable state approach
c
Here's mine - don't love it but got the job done! https://github.com/cak/advent-of-code-2021/blob/main/src/Day04.kt
t
I tried not to have any mutable state but I felt that it would have been a bit confusing to explain on my blog. I compromised by keeping the BingoBoard immutable but mutating a running set of drawn numbers.
m
Regarding mutable state: cannot be avoided, obviously. I refactored a bit and now the only obvious mutable state is in the Slot.bingo property. Maps nicely to real life! EDIT: Should have phrased it differently. Of course you can solve this without having any obvious mutability in your code. 🙂 https://github.com/MikeEnRegalia/AdventOfCode2021/blob/main/kotlin/src/main/kotlin/Day04.kt
👍 1
p
Why can't mutable state not be avoided?
e
of course it can be avoided, I have a Haskell solution that doesn't use mutable state. but I switched around my Kotlin solution to mutate a bitfield representing the bingo board, that seems to work quite well (half the runtime of the List<List>> solution I originally had)
m
I meant that you can remove the mutability from your code, but it’s always somewhere. If you go completely functional then it’s somewhere on the stack, or hidden in many functions provided by the Kotlin standard library.
d
p
https://github.com/tKe/aoc-21/blob/main/kotlin/src/main/kotlin/year2021/Day04.kt In the history is an in-line wrapper around a 26-slot int array, but I settled on this solution
p
Is more LOC better or less LOC?
d
it’s an imperfect proxy for using the tools the language gives you — I’m also structuring my code to be concise with heavy usage of single-line expression functions so it may not be apples to apples with other people’s code. I like your approach of treating the picks as something that can be overlaid on a row rather that modifying the state of individual squares, I didn’t think of that.
Which actually suggests a solution which avoids all mutable state (including working sets of boards). The immutable board object could be given the complete list of picks and report at which index in the picks it gets a bingo. Map over the boards to get a Pair(Board, Int), sort, then use the value of the pick at that index to compute the score.
m
Yes, I considered doing that. 😊
@Dan Fingal-Surma I think that change would decrease both performance and readability …
d
Oh definitely
m
If you guys don't mind sparing the time to take a look at my attempt at day4-part1, it's got me stumped, I got it working fine on the test input but it doesn't work on the real input. I didn't want to see other people's solutions either until I figure out where I went wrong with my method. Thanks!
I'm also learning Kotlin as I go along these challenges
e
logic-wise,
colBingoCheck(board, rIndex)
doesn't look right - that should be a column index, not a row index
☝️ 1
m
it returns a row of every nth element of each column of the board
then it counts if the 5 elements are tagged with *
d
You need to check the column of the marked number
m
yep...I finally spotted the problem with the column index...also took into account for repeated numbers. will definitely clean it up when I see other people's solutions. thanks