Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions src/main/kotlin/me/peckb/aoc/_2024/calendar/day18/Day18.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package me.peckb.aoc._2024.calendar.day18

import javax.inject.Inject
import me.peckb.aoc.generators.InputGenerator.InputGeneratorFactory
import me.peckb.aoc.pathing.GenericIntDijkstra

class Day18 @Inject constructor(
private val generatorFactory: InputGeneratorFactory,
) {
fun partOne(filename: String) = generatorFactory.forFile(filename).readAs(::location) { locations ->
val area = Array(HEIGHT) { Array(WIDTH) { Memory.EMPTY } }

locations.take(1024).forEach { (y, x) ->
area[y][x] = Memory.CORRUPTED
}

val solver = object : GenericIntDijkstra<Location>() { }

val solutions = solver.solve(
Location(0, 0).withArea(area).withPreviousPath(emptyList()),
Location(HEIGHT - 1, WIDTH- 1)
)

solutions[Location(HEIGHT - 1, WIDTH- 1)]
}

fun partTwo(filename: String) = generatorFactory.forFile(filename).readAs(::location) { locations ->
val area = Array(HEIGHT) { Array(WIDTH) { Memory.EMPTY } }
val start = Location(0, 0).withArea(area).withPreviousPath(emptyList())
val end = Location(HEIGHT - 1, WIDTH - 1)

val locationList = locations.toList()

var counter = 1024
locationList.take(1024).forEach { (y, x) -> area[y][x] = Memory.CORRUPTED }

var solutions: Map<Location, Int> = emptyMap()
val solver = object : GenericIntDijkstra<Location>() {}
search@ do {
val next = locationList[counter++]
area[next.y][next.x] = Memory.CORRUPTED

if (solutions.entries.firstOrNull { it.key == end }?.key?.path?.contains(next) == false) {
continue@search
}

solutions = solver.solve(start, end)
} while(solutions[end] != null)

locationList[counter - 1].let { "${it.x},${it.y}" }
}

private fun location(line: String) = line.split(",")
.map { it.toInt() }
.let { (x, y) -> Location(y, x) }

companion object {
const val WIDTH = 71
const val HEIGHT = 71
}
}

data class Location(val y: Int, val x: Int) : GenericIntDijkstra.DijkstraNode<Location> {
lateinit var path: List<Location>
lateinit var area: Array<Array<Memory>>

fun withArea(area: Array<Array<Memory>>) = apply { this.area = area }
fun withPreviousPath(path: List<Location>) = apply { this.path = path.plus(this) }

override fun neighbors(): Map<Location, Int> {
return Direction.entries.mapNotNull { d ->
val (newY, newX) = d.yDelta + y to d.xDelta + x
if (newY in area.indices && newX in area[newY].indices && area[newY][newX] == Memory.EMPTY) {
Location(newY, newX).withArea(area).withPreviousPath(path)
} else { null }
}.associateWith { 1 }
}
}

enum class Direction(val yDelta: Int, val xDelta: Int) {
N(-1, 0),
E(0, 1),
S(1, 0),
W(0, -1);
}

enum class Memory(val s: String) {
EMPTY("."), CORRUPTED("#");

override fun toString(): String = s
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
## [Day 18: RAM Run](https://adventofcode.com/2024/day/18)
2 changes: 2 additions & 0 deletions src/test/kotlin/me/peckb/aoc/_2024/TestDayComponent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import me.peckb.aoc._2024.calendar.day14.Day14Test
import me.peckb.aoc._2024.calendar.day15.Day15Test
import me.peckb.aoc._2024.calendar.day16.Day16Test
import me.peckb.aoc._2024.calendar.day17.Day17Test
import me.peckb.aoc._2024.calendar.day18.Day18Test
import javax.inject.Singleton
import me.peckb.aoc.DayComponent
import me.peckb.aoc.InputModule
Expand All @@ -42,4 +43,5 @@ internal interface TestDayComponent : DayComponent {
fun inject(day15Test: Day15Test)
fun inject(day16Test: Day16Test)
fun inject(day17Test: Day17Test)
fun inject(day18Test: Day18Test)
}
32 changes: 32 additions & 0 deletions src/test/kotlin/me/peckb/aoc/_2024/calendar/day18/Day18Test.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package me.peckb.aoc._2024.calendar.day18

import javax.inject.Inject

import me.peckb.aoc._2024.DaggerTestDayComponent
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test

internal class Day18Test {
@Inject
lateinit var day18: Day18

@BeforeEach
fun setup() {
DaggerTestDayComponent.create().inject(this)
}

@Test
fun testDay18PartOne() {
assertEquals(416, day18.partOne(DAY_18))
}

@Test
fun testDay18PartTwo() {
assertEquals("50,23", day18.partTwo(DAY_18))
}

companion object {
private const val DAY_18: String = "advent-of-code-input/2024/day18.input"
}
}
Loading