From 150322aa1a07495c01115c057fdc55b6ad401ac7 Mon Sep 17 00:00:00 2001 From: Oscar Molnar Date: Wed, 18 Dec 2024 12:17:27 +0000 Subject: [PATCH] Finish 2024 day 18 both parts --- 2024/kotlin/src/main/kotlin/Main.kt | 2 + .../kotlin/com/tymscar/day18/part1/part1.kt | 60 +++++++++++++++- .../kotlin/com/tymscar/day18/part2/part2.kt | 69 ++++++++++++++++++- 3 files changed, 129 insertions(+), 2 deletions(-) diff --git a/2024/kotlin/src/main/kotlin/Main.kt b/2024/kotlin/src/main/kotlin/Main.kt index 6715f5b..0e39d8f 100644 --- a/2024/kotlin/src/main/kotlin/Main.kt +++ b/2024/kotlin/src/main/kotlin/Main.kt @@ -17,6 +17,7 @@ import com.tymscar.day14.solve as day14 import com.tymscar.day15.solve as day15 import com.tymscar.day16.solve as day16 import com.tymscar.day17.solve as day17 +import com.tymscar.day18.solve as day18 fun main() { day01() @@ -36,4 +37,5 @@ fun main() { day15() day16() day17() + day18() } \ No newline at end of file diff --git a/2024/kotlin/src/main/kotlin/com/tymscar/day18/part1/part1.kt b/2024/kotlin/src/main/kotlin/com/tymscar/day18/part1/part1.kt index 710e1b9..9e596d8 100644 --- a/2024/kotlin/src/main/kotlin/com/tymscar/day18/part1/part1.kt +++ b/2024/kotlin/src/main/kotlin/com/tymscar/day18/part1/part1.kt @@ -1,5 +1,63 @@ package com.tymscar.day18.part1 +import java.util.PriorityQueue + +const val MAP_SIZE = 71 +const val NUM_BYTES = 1024 + +private typealias Map = HashMap + +private data class Vec2(var x: Int, var y: Int) { + constructor(list: List) : this(list[0], list[1]) + + fun getValidNeighbours(): List { + return listOf( + Vec2(x + 1, y), + Vec2(x - 1, y), + Vec2(x, y + 1), + Vec2(x, y - 1) + ).filter { it.x in 0 until MAP_SIZE && it.y in 0 until MAP_SIZE } + } +} + +private enum class MemoryType { CORRUPTED, SAFE } + +private fun dijkstra(start: Vec2, end: Vec2, map: Map): Int { + val visited = HashSet() + val costs = HashMap() + val queue = PriorityQueue>(compareBy { it.second }) + + queue.add(start to 0) + while (queue.isNotEmpty()) { + val (currPos, currCost) = queue.poll() + if (currPos == end) return currCost + + if (visited.contains(currPos)) continue + visited.add(currPos) + + val neighbours = currPos.getValidNeighbours() + for (neighbour in neighbours) { + if (map.getOrDefault( + neighbour, + MemoryType.SAFE + ) == MemoryType.CORRUPTED || visited.contains(neighbour) + ) continue + val nextCost = currCost + 1 + if (nextCost < costs.getOrDefault(neighbour, Int.MAX_VALUE)) { + costs[neighbour] = nextCost + queue.add(neighbour to nextCost) + } + } + } + return Int.MAX_VALUE +} + fun solve(input: String): String { - return input + val bytes = input.lines().map { Vec2(it.split(",").map { it.toInt() }) } + val map = (0 until NUM_BYTES).associate { bytes[it] to MemoryType.CORRUPTED }.toMap() + + val start = Vec2(0, 0) + val end = Vec2(MAP_SIZE - 1, MAP_SIZE - 1) + + return dijkstra(start, end, map as Map).toString() } diff --git a/2024/kotlin/src/main/kotlin/com/tymscar/day18/part2/part2.kt b/2024/kotlin/src/main/kotlin/com/tymscar/day18/part2/part2.kt index 3a67638..a041de9 100644 --- a/2024/kotlin/src/main/kotlin/com/tymscar/day18/part2/part2.kt +++ b/2024/kotlin/src/main/kotlin/com/tymscar/day18/part2/part2.kt @@ -1,5 +1,72 @@ package com.tymscar.day18.part2 +import java.util.PriorityQueue + +const val MAP_SIZE = 71 +const val NUM_BYTES = 1024 + +private typealias Map = HashMap + +private data class Vec2(var x: Int, var y: Int) { + constructor(list: List) : this(list[0], list[1]) + + fun getValidNeighbours(): List { + return listOf( + Vec2(x + 1, y), + Vec2(x - 1, y), + Vec2(x, y + 1), + Vec2(x, y - 1) + ).filter { it.x in 0 until MAP_SIZE && it.y in 0 until MAP_SIZE } + } + + override fun toString(): String = "$x,$y" +} + +private enum class MemoryType { CORRUPTED, SAFE } + +private fun canFindPath(start: Vec2, end: Vec2, map: Map): Boolean { + val visited = HashSet() + val costs = HashMap() + val queue = PriorityQueue>(compareBy { it.second }) + + queue.add(start to 0) + while (queue.isNotEmpty()) { + val (currPos, currCost) = queue.poll() + if (currPos == end) return true + + if (visited.contains(currPos)) continue + visited.add(currPos) + + val neighbours = currPos.getValidNeighbours() + for (neighbour in neighbours) { + if (map.getOrDefault( + neighbour, + MemoryType.SAFE + ) == MemoryType.CORRUPTED || visited.contains(neighbour) + ) continue + val nextCost = currCost + 1 + if (nextCost < costs.getOrDefault(neighbour, Int.MAX_VALUE)) { + costs[neighbour] = nextCost + queue.add(neighbour to nextCost) + } + } + } + return false +} + fun solve(input: String): String { - return input + val bytes = input.lines().map { Vec2(it.split(",").map { it.toInt() }) } + val map = (0 until NUM_BYTES).associate { bytes[it] to MemoryType.CORRUPTED }.toMutableMap() + + val start = Vec2(0, 0) + val end = Vec2(MAP_SIZE - 1, MAP_SIZE - 1) + + var currentByte = NUM_BYTES - 1 + + while (canFindPath(start, end, map as Map)) { + map[bytes[currentByte]] = MemoryType.CORRUPTED + currentByte++ + } + + return bytes[currentByte - 1].toString() }