<Advent of Code 2022 day 22> :thread:
# advent-of-code
a
s
For the first part, it really helps to pad the maze array with spaces from all 4 sides. Then you don't need to take care of running out of the array index.
d
Ouch, part 2 made my brain hurt. 🤯
j
I'm also struggling to find a good representation of part 2. If at least the sample and actual input had the same shape... 😞
m
I have drawn my input shape on paper with named faces, actually cut it out, made a cube, and that made it easy to see how the wrapping works for each face. 😄
b
I also replicated the shape of my input on paper and folded it manually. I have no idea how to do it otherwise
j
so no code that would actually fold the cube itself based on the input shape?
o
I loooooooooove these challenges! 🥰
j
I wonder if all actual inputs look like this
Copy code
##
 #
##
#
j
@Jan Durovec problem with that is that if you name from top left to bottom right the faces 1..6 the faces next to each other are not the same as in the example
e
You can write code to do the folding. Conceptually it is easy, as all you have to do is to fold along each edge between vertices 90 degrees inwards, but you’ll have to maintain all coordinates in 3D which will take a lot of code altogether. Should be also fun to code, though. I might try it in the evening.
@Jonathan Kolberg Yes. If you fold manually, then you have to trust your part 2 code. No testing on example.
message has been deleted
j
If somebody has problems parsing the instructions (move x, left and right) recursivly, try writing a tailrec helper:
Copy code
private tailrec fun parseInstructionsHelper(
    restInput: String,
    currentList: List<Instruction>
): List<Instruction>
e
@Jonathan Kolberg Frankly, parsing is way easier to code if you simply maintain an integer index variable that advances along the string indices as you consume tokens of the input.
j
@elizarov yes, but I like writing recursive functions, to avoid having mutable variables
j
I've finally solved part 2 by hardcoding transitions based on the shape o actual input (i.e. if I leave the grid I'll end up somewhere else facing some direction)... which works fine but not on test input which has different shape 🤷‍♂️ I think I don't have a capacity to write a parsing+folding code and come up with some generic cube data structure that allows moving in a given direction.
e
@Jan Durovec AFAIU, no one had written a generic cube-folding code yet.
j
@Jan Durovec @elizarov maybe inject the shape of the cube projection as a workaround
j
This is actually the 2nd time this year where the actual input had unnecessarily different structure than test input (last time it was geode robots)
I don't remember this happening in previous years (but maybe my memory is just failing me)
r
Yeah, for part 2 I hard-coded the 14 special transitions... For parsing the walk instructions, I just did a regex
\d+|[LR]
and had it find all matches.
r
I started with grid, dynamic
list of list
(which is eating up extra blank spaces), i am sure there must be better approaches when it comes to forming the data structure.
j
@ritesh I typically represent sparse grids by
Set<Pair<Int,Int>>
however, in this case I just left it as
List<String>
which I read from the file and had in memory anyway and just checked
input[row][col] == '#'
m
Looks like we are sharing our cubes. advent of code intensifies
j
I came here just to share my cube pic. I'm surrounded by my 3 nephews for Christmas, so mine has a child vibe:
s
I "simply" hardcoded the wraparound rules both for the 4x sample cube and the 50x actual cube, so it's kind of a monstrosity, but it works https://github.com/forketyfork/aoc-2022/blob/main/src/main/kotlin/year2022/Day22.kt
j
@Sergei Petunin why are your wraparound rules you pass not a function but a map. You could still store in map and use
variable::getValue
, then you do not need
!!
m
Solved it, but now I have a headache. Did it without building a 3D model 🙂 https://github.com/MikeEnRegalia/advent-of-code/blob/master/src/main/kotlin/aoc2022/day22.kt
s
@Jonathan Kolberg indeed, you are right, refactored it as a function and now it looks better
m
@Jonathan Kolberg
Copy code
val instructions: List<Any> = lines.last().asSequence().fold(mutableListOf<String>()) { acc, c ->
        acc.apply {
            when {
                c.isDigit() -> {
                    if (isEmpty() || last().toIntOrNull() == null) add("")
                    set(lastIndex, last() + c)
                }
                else -> add(c.toString())
            }
        }
    }.map { it.toIntOrNull() ?: it }.toList()
p
https://github.com/tke/aoc-22/blob/main/kt/src/main/kotlin/year2022/Day22.kt I broke the map/board down into each section/face/field and traversed it using a definition of which fields link on which sides. The only thing missing from a generic solver is a way to automatically determine the links for a given cube net to replace this:
Copy code
private val netLinks: Map<String, String> = mapOf(
    "--0-:123-:--45" to "0DU3;0LU2;0RR5;0UU1;1DD4;1LD5;1RL2;2DL4;2RL3;3DU4;3RU5;4RL5", // example
    "-01:-2-:34-:5--" to "0DU2;0LL3;0RL1;0UL5;1DR2;1RR4;1UD5;2DU4;2LU3;3DU5;3RL4;4DR5", // input
)
r
parsing was easy indeed with a regex 🙂
Copy code
Regex("""\d+|[LR]""").findAll(lines.last()).map { it.value }
it took me ages but I figured out how to do the folding in the code without mucking around with 3d
basically, I walk around the perimeter clockwise. if there's two adjacent edges that form a concave corner, they should be joined together; I remove them and decrement the angle of all the angles further down (relative to the ones before). repeat until all edges are joined
I didn't have paper so I couldn't build a cube model lmao
r
you make it sound so easy mind blown
b
unpairedEdges
that’s wild @ephemient!
well done
p
Finally find time to get back to AoC and see if I can fold my nets automatically, only to find @ephemient has beaten me to to punch 👏 . A slightly different approach but same principal (find adjacent edges and pair). https://github.com/tke/aoc-22/blob/main/kt/src/main/kotlin/year2022/Day22.kt As my solver users a graph of fields to navigate, finding the folds is really a case of completing the graph - so I start with all edges, link the trivial edges based on the cube net layout, and then for each remaining edge to pair, I try to find an appropriate edge by walking the existing graph and turning twice (to find a corner).
p
Oh Fancy
But that doesn't work with the terminal right? Last time I tried that it broke mono fonts
p
they work fine as long as you don’t mix non-emoji after them as they don’t quite seem to be double-width. but they are more squarer which is nicer for visualising grids
o
https://github.com/Oziomajnr/AdventOfCodeSolutions/blob/main/solutions/src/year_2022/day22/Day22_2.kt Took me while to figure out the direction also changes when moving between some faces of the cube. I wonder what the thought process is to come up with these questions.
e
I finally wrote the folding for an arbitrary net, too. I do it in 3D. I pre-fold faces and compute the 3D basis of each face (row direction, column direction, and normal). When walking out of the board, I convert the position and direction on the next face into 3D, then project it onto the actual basis of the next face. This way flipping of coordinates gets accounted for automatically by the negative sign in the projection. It takes a while to figure out how all the pieces tie together, but the resulting code is quite straightforward with zero hard-coding or special cases to take care of. https://github.com/elizarov/AdventOfCode2022/blob/main/src/Day22Part2CubeFolding.kt
m
Looks great. I just wish the variable names were a little less cryptic.
I’m wondering if there is a reason you used
LinkedHashMap<F, Int>()
, rather than the idiomatic (I think)
mutableMapOf()
?
r
I always end up doing some silly mistakes in problem. For part 1 -> i was checking if
[row][col] != '.'
- assuming even tiles are blockers, simple change was to just check for
[row][col] != '#'
It was passing for testInput but not for real input, until i changed it to
[row][col] != '#'
e
@Marcin Wisniowski I don't like how
xxxOf()
functions read without parameters. Anyway, I rewrote it without a mutable set and without manual counting. It looks nicer using
groupingBy { it }.eachCount()
t
Better late that never! That one was difficult for me, I really struggled with how to represent things but ended up with a solution I am happy with. I ended up rewriting Part One to use the same method I use for Part Two, which worked out well. • BlogCode
j
Took me a while (especially when I only had small chunks of available time), but I got a generic solver. High-level idea was to create a box with faces and edges that linked pairs of sides together. I then started at the first region and mapped it to one of the faces and mapped each of its sides (top, right, bottom, left) to an edge in the face in clockwise order. Then I repeated the process for each neighboring region, keeping track of which side it was covered by and mapping it to the face connected to the previous region by looking up which edge was on that side. When I was done, each face on the box was married to a region and each edge was mapped to the sides of the two regions it represented. I was then able to extract a mapping of region and side to another region and side to get the final shape. Still needs a fair amount of refactoring, with two similar concepts (region/side) and (face/edge) leading to confusing variable names at times.