<Advent of Code 2021 day 3> :thread:
# advent-of-code
a
d
I can't wait to see how you all solved this in a functional way. My solve is way too procedural.
p
Same goes for me as well. Challenges faced today include copying a list (I assumed there was a
.clone()
or
.copy()
method; ended up using
.toMutableList
)
Also, learnt not to use
.toString()
on a list of bits. 🤦‍♂️
d
Not sure if this is cool or not, but I started with
var oxyInput = input
and
var co2Input = input
and then used
filter
to reassign on each iteration
p
Hmmm, I thought that would mutate the original list, but yeah I should have done the same
d
@Marcin Wisniowski
xor invert
I love it!
m
Updated both parts to be a little shorter. 😄
m
That looks pretty clean! Can't wait to get home and solve these problems!!!
e
https://github.com/ephemient/aoc2021/blob/main/kt/src/commonMain/kotlin/com/github/ephemient/aoc2021/Day3.kt I didn't use xor to invert the final value - that depends on the length of the input values - but I did use xor to invert the individual characters representing each bit
K 1
BTW you can
.retainAll()
on a
MutableList
instead of re-assigning after
.filter()
. it does some clever swapping in-place to avoid allocating
👍 1
m
Here’s my solution … https://github.com/MikeEnRegalia/AdventOfCode2021/blob/main/kotlin/src/main/kotlin/Day03.kt
Copy code
fun List<String>.day03(): Pair<Int, Int> {
    fun part1(value: Boolean) = first().indices
        .joinToString("") { if (moreCommon(it, value)) "1" else "0" }
        .toInt(2)

    fun part2(findMoreCommon: Boolean) = toMutableList().run {
        for (bit in first().indices) {
            val keep = moreCommon(bit, true).let { if (findMoreCommon) it else !it }
            retainAll { it[bit] == keep.toChar() }
            if (size == 1) break
        }
        first().toInt(2)
    }

    return part1(true) * part1(false) to part2(true) * part2(false)
}

private fun List<String>.moreCommon(bit: Int, value: Boolean) =
    map { it[bit] }.count { it == value.toChar() } >= size / 2.0

private fun Boolean.toChar() = if (this) '1' else '0'
👍 1
p
m
^ Not bad at all, but there are some redundancies. You don’t need the joinToStrings, for example. And you only need to count ones and compare that to the total size. 🙂
e
mine is generic enough that it would still work if you replaced the base with any value in 2..36. unnecessary but it was simple enough…
m
@ephemient How does your solution address the event of a “tie” in part2? EDIT: if it’s the sorting that does it, shouldn’t the uncommon path then sort by keys in descending order? EDIT2: Ah … I get it now. Very clever! 😎
j
My functional approach (in Kotlin) is for me less readable than my for-loops approach in ts-node, but hey, it’s functional 🙂
g
@David Whittaker that’s how much functional I can go 😅 https://github.com/cortinico/adventofcode-2021/blob/main/src/main/java/com/ncorti/aoc2021/Exercise03.kt Open to suggestions for improvements
K 1
m
@gammax Integer.parseInt(string, 2)? Whats wrong with string.toInt(2)? 😛
g
TIL I guess
c
Looking forward to catching up and reviewing all y'all's great solves. I'm looking forward to refactoring my rished (ran out of time this morning before work) ugly and maybe flawed attempt! 😬 https://github.com/cak/advent-of-code-2021/blob/main/src/Day03.kt
e
This year, I'm trying to comment my solutions more, so that: a) they still make sense the next year day; b) others can perhaps better understand what's going on. Also, yay, first recursion of the year! https://github.com/edgars-supe/advent-of-code/blob/master/src/main/kotlin/lv/esupe/aoc/year2021/Day3.kt
t
I’m pretty happy with how mine turned out. For part 1 I examined each column and added its binary value to a running total (via
sumOf
) to calculate the gamma. For part 2 I took advantage of
partition
and a
fold
to successively pick either the largest or smallest side of the partition. • BlogCode Thankfully, I had the day off work today so I could focus on refactoring. 🙂
K 1
e
@todd.ginsberg A bit of copy/paste, your part headers say "Day 1, Part #" 😉
t
Thanks for the catch @Edgars! 🙂
g
I've got not much to add to the previous solutions except for the much longer function names ... but hey: I folded, again! https://github.com/gnu11111/aoc-2021-in-kotlin/blob/main/src/main/kotlin/at/gnu/adventofcode/year2021/Day03.kt
l
I ended up with a fold + partition in part 2 as well https://github.com/TheSunshinator/Advent-of-Code-2021/tree/main/src/day03
j
For Part 1, I spotted a nice property: If one takes the arithmetic mean of a column, if the value is > 0.5, the 1 was more common and vice versa. That together with transposing the input as a matrix, makes for very lean code K
🆒 1
j
I’m sure I’m being dense, but where are people seeing Part 2? I’m looking here and nothing mentions oxygen or CO2 that I see in some of the solutions posted here.
e
Solve part one to unlock part 2 :)
j
Muchos ta.
t
Bah. I woke up from a nap (I have the day off today!) and realized how overcomplicated my previous Part 1 was, so I rewrote it. Basically, create a new binary string for gamma, flip all the bits for epsilon, and call toInt(2) on them. Anyway, rewritten and re-explained: • BlogCode
🙌 2
p
I have the feeling that this is a really crap solution and could be simlified by some bitshift magic 🙈 https://github.com/PaulWoitaschek/Advent-of-Code-2021/blob/main/src/main/kotlin/day3.kt
🙌 1
e
I'm challenging myself to implement everything using lazy computations and for this day (though only part 1 yet) I used fold + zip to count the most common bits of all columns at the same time, iterating over the whole input only once. Not the shortest implementation but I'm pretty happy with how clean it looks and with the fact this solution would handle any input size with very low memory footprint and good performance 🙂 Suggestions on how to improve while keeping the lazy computations are welcome!
p
@edrd I have thought about the bit inline class as well. But then I noticed we already have a bit. It's called boolean 😁
e
@Paul Woitaschek yeah, in the end it was just an excuse for me to do things like
.map(Bit::flip)
(could have been
.map(Boolean::not)
, but come on, the former looks neater 😄)
p
Yeah it took me a moment to realize that we have that yes or no type already 😉
🙂 1
m
I try to always use Bitset when working with bits, the interop between binary numbers, list of booleans and bitsets just doesnt exist so you need to constantly define them. Other that that, bitsets are really good.
p
Yeah I looked into it when solving the task but could not make sense of it
1
e
(must try to implement it lazily now 😛)