<Advent of Code 2024 day 4> (spoilers) :thread:
# advent-of-code
a
p
This is how my code looks like before cleaning it up 🚒 https://gist.github.com/PaulWoitaschek/335eaa0001f9aa2748f76bea91f9daa3 Next up: Bringing Kids to school and then cleaning that mess up kodee happy And cleaned up: https://github.com/PaulWoitaschek/AdventOfCode/blob/main/2024/src/main/kotlin/aoc/year2024/Day4.kt
n
Very straightforward. Don't love my solution but it's the best I could do in 24 minutes. https://github.com/nbanman/Play2022/blob/master/src/main/kotlin/org/gristle/adventOfCode/y2024/d4/Y2024D4.kt
🎉 1
m
This is what I can come up with after my cleanup, my initial solution was manually checking all directions. Some helper functions and constants e.g.
toGrid()
,
WINDS
etc.
j
Today was pretty strait forward https://github.com/bulldog98/advent-of-code/blob/main/advent2024/src/main/kotlin/year2024/Day04.kt When you look at the git history you can see my first solution.
m
Part 1
❤️ 1
Part 2
❤️ 2
Grid utils came in handy
m
seeing your 'move' function, I completely forgot I had added operator funs to my Point typealias (Point = Pair<Int, Int>), so I refactored my code a little bit and now ours is almost identical haha
😄 1
j
Am I the only one who created all the Grid, Pos, Move classes/typealiases again for the n-th time? 🙂
🚫 2
I keep everything self-contained
b
ouch that one hurt
j
Today's part one brings more fun than part two, as it can be done in plenty of good ways. My approach just takes all
X
-es on the grid, performs cartesian products with possible directions, and in this list goes step after step, filtering out the cases when the consecutive values aren't
M
,
A
, and
S
r
My initial solution for part 1 involved mapping the columns + diagonals to strings and then doing a regex search on them. That was incredibly hard to adjust to part 2. After cleaning up and simplifying to a nested loop + grid based solution, this is what I came up with.
Copy code
fun solveA(text: String, debug: Debug = Debug.Disabled): Int {
    val lines = text.lines()
    val rRange = 0..lines.lastIndex
    val cRange = 0..lines[0].lastIndex
    return rRange.sumOf { r ->
        cRange.sumOf { c ->
            val h = if (c + 3 in cRange) "${lines[r][c]}${lines[r][c + 1]}${lines[r][c + 2]}${lines[r][c + 3]}" else ""
            val v = if (r + 3 in rRange) "${lines[r][c]}${lines[r + 1][c]}${lines[r + 2][c]}${lines[r + 3][c]}" else ""
            val tlbr =
                if (c + 3 in cRange && r + 3 in rRange) "${lines[r][c]}${lines[r + 1][c + 1]}${lines[r + 2][c + 2]}${lines[r + 3][c + 3]}" else ""
            val bltr =
                if (c + 3 in cRange && r + 3 in rRange) "${lines[r + 3][c]}${lines[r + 2][c + 1]}${lines[r + 1][c + 2]}${lines[r][c + 3]}" else ""

            listOf(h, v, tlbr, bltr).count { it == "XMAS" || it == "SAMX" }
        }
    }
}

fun solveB(text: String, debug: Debug = Debug.Disabled): Int {
    val lines = text.lines()
    return (1..<lines.lastIndex).sumOf { r ->
        (1..<lines[0].lastIndex).count { c ->
            val tlbr = "${lines[r - 1][c - 1]}${lines[r][c]}${lines[r + 1][c + 1]}"
            val bltr = "${lines[r - 1][c + 1]}${lines[r][c]}${lines[r + 1][c - 1]}"

            (tlbr == "MAS" || tlbr == "SAM") && (bltr == "MAS" || bltr == "SAM")
        }
    }
}
same 1
n
My approach was to create 4 sets of points from the input, and then check e.g. which of the 8 neighbors of an 'X' is in allM.
b
im use to just using
dict
for grids from python, maybe i should just write an actual grid class...
m
I just use typealias for a lot of things
Map<Pair<Int, Int>, T> -> Map<Point, T> -> Grid<T>
n
@bj0 I haven't gotten around to writing a Grid struct for my Rust solutions, so for there I just work on the string directly. And honestly, there's a lot of things that take me a lot longer to write my Rust solution, but working on the strings isn't one of them. The width of the string as a 2d representation is
indexOf('\n') + 1
. Then going up is -width, down is width, left is -1, right is 1. If you use
getOrNull
then that handles anything above and below the area. The sides return \n, so it's easy to filter them out as well.
p
Solved part1 with regexes 🙂
a
I used Point(2D) along with Direction N(Point(0, -1)), S(Point(0, 1)), etc. like many here. in part 2 I have this filter
Copy code
aLetters.size == 2 && aLetters.all { it in setOf("MAS", "SAM") }
but if I make it just
Copy code
aLetters.all { it in setOf("MAS", "SAM") }
it still works - ie there are no X's with just one MAS/SAM 🤔
is there no
isSubset
/ operator in Kotlin ? I mean, it's a simple extension function with ⬇️ but still
Copy code
Set<T>.isSubset(other: Set<T>) = all { it in other }
(edit: just subset, not proper subset)
j
other.containsAll(this)
?
but honestly, your
all { it in other }
is cleaner
❤️ 1
e
a
@Jakub Gwóźdź containsAll doesn't work entirely as expected and would need extra checks:
Copy code
setOf("SAM", "SAM").containsAll(setOf("SAM", "MAS"))  // false but we want true
setOf("SAM", "MAS", "XYZ").containsAll(setOf("SAM", "MAS"))  // true but we want false
j
@Anirudh you need to flip receiver and argument, I think
1
so your
Set<T>.isProperSubset(other: Set<T>) = other.containsAll(this)
a
ah yes, when I flip it works
m
@Anirudh You're asking, on line one, if ["SAM"] contains all of ["SAM", "MAS"]; logically thats a no
a
@Michael de Kaste yeah the order of reciever/param of
containsAll
confused me
c
One of those where I felt Part 2 was considerably more straightforward than Part 1, not that Part 1 was anything tricky itself.
1
p
for some reason I didn't use my grid utils for this one
👍 1
m
hehe I out magic numbered myself today. It's not pretty , it's not maintainable, it's not general purpose but it is worth 2 stars. amazingly I had no off by one errors.
Copy code
// check diagonals
        if ((i < this[0].length - 3) && (j < this.size - 3)) {
            val diagonal1 = "${this[j][i]}${this[j + 1][i + 1]}${this[j + 2][i + 2]}${this[j + 3][i + 3]}"
            val diagonal2 = "${this[j + 3][i]}${this[j + 2][i + 1]}${this[j + 1][i + 2]}${this[j][i + 3]}"
            if (diagonal1.isXmas()) count++
            if (diagonal2.isXmas()) count++
        }
m
Definitely not pretty but quite fast
d
Hi, does anyone know if the sourcecode of this session can be found somewhere. I would love to check out the details on compose and the hot reload. cc: @Sebastian Aigner
s