Advent of Code 2023 day 18
12/18/2024, 5:00 AMDan Fingal-Surma
12/18/2024, 5:23 AMDan Fingal-Surma
12/18/2024, 5:23 AMDan Fingal-Surma
12/18/2024, 5:29 AMMarcin Wisniowski
12/18/2024, 5:29 AMMarcin Wisniowski
12/18/2024, 5:29 AMbj0
12/18/2024, 5:29 AMbj0
12/18/2024, 5:29 AMMarcin Wisniowski
12/18/2024, 5:29 AMDan Fingal-Surma
12/18/2024, 5:29 AMkingsley
12/18/2024, 5:30 AMbj0
12/18/2024, 5:30 AMbj0
12/18/2024, 5:30 AMDan Fingal-Surma
12/18/2024, 5:31 AMDan Fingal-Surma
12/18/2024, 5:31 AMRenette Ros
12/18/2024, 5:33 AMbj0
12/18/2024, 5:35 AMDan Fingal-Surma
12/18/2024, 5:42 AMkingsley
12/18/2024, 5:42 AMDan Fingal-Surma
12/18/2024, 5:43 AMDan Fingal-Surma
12/18/2024, 5:43 AMkingsley
12/18/2024, 5:44 AMkingsley
12/18/2024, 5:47 AMOzioma Ogbe
12/18/2024, 5:50 AMOzioma Ogbe
12/18/2024, 5:51 AMDan Fingal-Surma
12/18/2024, 5:57 AMJonathan Kolberg
12/18/2024, 6:05 AMJakub Gwóźdź
12/18/2024, 6:21 AMsolve(...)
returns the "path?", so I just store it and skip testing for all the blocks that aren't on the already found path, then repeat until no path is to be found anymore
fun part2(input: List<Pos>): String {
val fallen = mutableSetOf<Pos>()
var lastPath = solve(fallen)!!.toSet()
input.forEach { block ->
fallen += block
if (block in lastPath) {
lastPath = solve(fallen)?.toSet() ?: return "${block.first},${block.second}"
}
}
error("No solution found")
}
saves some time (from around 2.4s to 85ms)Andriy
12/18/2024, 6:28 AM.readText().split('\n')
might be simply replaces with one call .lines()
bj0
12/18/2024, 6:39 AMMichael de Kaste
12/18/2024, 6:52 AMDan Fingal-Surma
12/18/2024, 7:03 AMDan Fingal-Surma
12/18/2024, 7:13 AMDan Fingal-Surma
12/18/2024, 7:21 AMJakub Gwóźdź
12/18/2024, 7:21 AMAlbert Chang
12/18/2024, 7:22 AMAnirudh
12/18/2024, 7:27 AMAlbert Chang
12/18/2024, 7:29 AMDan Fingal-Surma
12/18/2024, 7:36 AMDan Fingal-Surma
12/18/2024, 7:38 AMphldavies
12/18/2024, 7:39 AMbfsRoute
helper return null rather than throwing when no route found.Dan Fingal-Surma
12/18/2024, 7:41 AMAnirudh
12/18/2024, 7:50 AMThe binary search smart is so smart, I feel like mine is too hacky.
I let an initial floodfill determine my initial searchspace.@Michael de Kaste since part 2 is really any path, flood fill from the starting point and then checking if the end point is in the same "region" seems less computationally intensive, if even if it appears like more iterations or lines-of-code. especially if you stick to just the "first" region. and the way you described a point being blocked off, it might be more lines of code but without needing to actually flood fill every time. the flood fill from the starting point is the same loop needed just to set up all the nodes in a graph, before even needing to find paths. I think that's a win.
Anirudh
12/18/2024, 8:59 AM#2959 (69) final: Pt(...)
ie only 69 very nice shortest path computes after 2950 iterations!
especially when the graph is huge & empty, adding points just doesn't matter much.Jakub Gwóźdź
12/18/2024, 9:06 AMno optimalization: 2862 tests
test only when blocks previous: 90 tests
bisect: 12 tests
this is from my inputAndriy
12/18/2024, 9:07 AMval resultIndex = (1..bytes.size)
.map { bytes.take(it) }
.binarySearch {
if (isExitReachable(it.toSet()))
-1
else {
val previousList = it.subList(0, it.size - 1)
if (isExitReachable(previousList.toSet()))
0
else
1
}
}
return bytes[resultIndex].let { (y, x) -> Point(x, y) }
Jakub Gwóźdź
12/18/2024, 9:09 AMAnirudh
12/18/2024, 9:10 AMyeah, but bisect still does it in 12 testsyes, definitely. for ~4500 inputs, that's 12 (or 13) checks, since 2 ^ 12 < 4500 < 2 ^ 13 (grid size is 71x71 = 5041)
Jakub Gwóźdź
12/18/2024, 9:21 AM.absoluteValues()
😆
it basically prefers zig-zagged diagonal, but I too noticed that for my input no heuristic is actually faster 🙂Michael de Kaste
12/18/2024, 9:34 AM(1..parsed.size)
.map(parsed::take)
.binarySearch { if(floodFill(it.toSet())) -1 else 1 }
.let { parsed[it.absoluteValue - 1] }
since binary search return the (-wouldBeIndex - 1) result if it can't find a '0' in the resultAnirudh
12/18/2024, 9:41 AMespecially when the graph is huge & empty, adding points just doesn't matter much.that was an incorrect assumption. it seems Mr. Wastl has carefully selected points earlier on which are on the shortest path. the re-calcs needed at the start were at a higher rate (42 in 1000) than in the middle (27 in 1500 ≈ 18 in 1000), with the extreme end being flat, (1 in 500).
Michael de Kaste
12/18/2024, 9:53 AMSolution for Day18:
---------Part 1-----------
time: 939us
answer: 260
---------Part 2-----------
time: 1.100300ms
answer: (24, 48)
---------Total-----------
time: 2.039300ms
---------End-----------
Jaap Beetstra
12/18/2024, 10:58 AMfun solvePart2(blocked: List<Position>, size: Int): String {
val blockMap = blocked.mapIndexed { index, position -> position to index }.toMap()
val bounds = ZeroBasedBounds(size, size)
val visited = mutableSetOf<Position>()
val edges = mutableListOf<Int>()
var lastEdge = blocked.size
val target = Position(size - 1, size - 1)
var lastRemovedPosition = target
val queue = mutableListOf(Position(0, 0))
while (target !in queue) {
val active = queue.removeLast()
visited.add(active)
for (nextPosition in active.neighbours4) {
if (nextPosition !in visited && nextPosition in bounds) {
val pos = blockMap.getOrDefault(nextPosition, -1)
if (pos in 0..<lastEdge)
edges.add(pos)
else
queue.add(nextPosition)
}
}
if (queue.isEmpty()) {
lastEdge = edges.max()
edges.remove(lastEdge)
lastRemovedPosition = blocked[lastEdge]
queue.add(lastRemovedPosition)
}
}
return lastRemovedPosition.column.toString() + "," + lastRemovedPosition.row
}
HCP
12/18/2024, 12:12 PMephemient
12/18/2024, 3:18 PMMax Thiele
12/18/2024, 3:50 PMJakub Gwóźdź
12/18/2024, 4:29 PMS
from E
.
So I came back to keyboard and implemented something for it:
Basically I'm dropping the bricks and either creating a new set of borders(together with diagonal) for each one, or if the new brick belongs to borders of one or more existing sets, add it to this set instead (merging sets when necessary).
A merged (continuous) set of bricks is considered as blocking the path if it had a brick on (top or right) grid line and another brick on (bottom or left)
And that approach is to be honest pretty darn quick!Dan Fingal-Surma
12/18/2024, 7:00 PMJakub Gwóźdź
12/18/2024, 7:00 PMDan Fingal-Surma
12/18/2024, 7:01 PMJakub Gwóźdź
12/18/2024, 7:03 PMDan Fingal-Surma
12/18/2024, 7:13 PMJakub Gwóźdź
12/18/2024, 8:10 PMParsing took 188.25us
Part 1 took 389.208us, result is 226
Part 2 took 306.459us, result is 60,46
And the code is actually pretty ok, after cleanup.Jakub Gwóźdź
12/19/2024, 11:23 AMPaul Woitaschek
12/19/2024, 8:11 PMplastiv
12/19/2024, 8:28 PMPaul Woitaschek
12/20/2024, 6:32 AM