Skip to content

Commit

Permalink
D18P2
Browse files Browse the repository at this point in the history
Bad solution, but it gets there in <8s so whatever
  • Loading branch information
hibob224 committed Dec 18, 2024
1 parent d61db06 commit b8755c2
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 16 deletions.
66 changes: 66 additions & 0 deletions src/main/kotlin/utils/Point.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package utils

import java.util.*
import kotlin.math.abs
import kotlin.math.atan2
import kotlin.math.pow
Expand Down Expand Up @@ -63,6 +64,71 @@ data class Point(val x: Int, val y: Int) {
override fun toString(): String = "($x, $y)"
}

//region A*
/**
* Calculate shortest path from [start] to [end] using A*. [Score] should return a cost for moving to the new position. Return -1 if the new
* spot is invalid (i.e. a 'wall')
*/
fun <T> Map<Point, T>.shortestPath(
start: Point,
target: Point,
gridWidthRange: IntRange = 0..maxOf(start.x, target.x),
gridHeightRange: IntRange = 0..maxOf(start.y, target.y),
score: (currentPos: Point, newPos: Point, newTerrain: T?) -> Int,
): Pair<List<Point>, Int> {
val open = mutableSetOf(start)
val closed = mutableSetOf<Point>()
val cameFrom = mutableMapOf<Point, Point>()
val gScore = mutableMapOf(start to 0)
val fScore = mutableMapOf(start to heuristicDistance(start, target)).withDefault { Int.MAX_VALUE }

while (open.isNotEmpty()) {
val currentPos = open.minBy { fScore.getValue(it) }

if (currentPos == target) {
val path = generatePath(currentPos, cameFrom)
return Pair(path, fScore.getValue(currentPos))
}

open.remove(currentPos)
closed += currentPos

currentPos.getNeighbours()
.filterNot { it in closed }
.filter { it.x in gridWidthRange && it.y in gridHeightRange }
.forEach { neighbour ->
val movementScore = score(currentPos, neighbour, get(neighbour))
if (movementScore == -1) return@forEach
val score = gScore.getValue(currentPos) + movementScore
if (score < gScore.getOrDefault(neighbour, Int.MAX_VALUE)) {
if (!open.contains(neighbour)) {
open.add(neighbour)
}
cameFrom[neighbour] = currentPos
gScore[neighbour] = score
fScore[neighbour] = score + heuristicDistance(neighbour, target)
}
}
}

error("Couldn't find a path")
}

fun generatePath(currentPos: Point, cameFrom: Map<Point, Point>): List<Point> = buildList {
var current = currentPos
while (cameFrom.containsKey(current)) {
current = cameFrom.getValue(current)
add(0, current)
}
}

private fun heuristicDistance(start: Point, finish: Point): Int {
val dx = abs(start.x - finish.x)
val dy = abs(start.y - finish.y)
return (dx + dy) + (-2) * minOf(dx, dy)
}
//endregion

fun <T> List<String>.toPointGrid(mapper: (Point, Char) -> T): Map<Point, T> =
flatMapIndexed { y, line ->
line.mapIndexed { x, c ->
Expand Down
39 changes: 24 additions & 15 deletions src/main/kotlin/y2024/day18/Day18.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,43 @@ fun main() {
object Day18 {

private val example = false
private val p1GridSize = if (example) 6 else 70
private val gridSize = if (example) 6 else 70
private val p1Bytes = if (example) 12 else 1024
private val input = getInputFile(this::class.java.packageName, example = example).readLines()

private fun parseInput(bytes: Int) = getInputFile(this::class.java.packageName, example = example)
.readLines()
.take(bytes)
.associate {
val (x, y) = it.split(",").map(String::toInt)
Point(x, y) to '#'
}
private fun parseInput(bytes: Int) =
input
.take(bytes)
.associate {
val (x, y) = it.split(",").map(String::toInt)
Point(x, y) to '#'
}


fun solvePartOne(): Int {
val grid = parseInput(p1Bytes)

// grid.printGrid()

return grid.shortestPath(
start = Point(0, 0),
target = Point(p1GridSize, p1GridSize),
target = Point(gridSize, gridSize),
) { _, new, _ ->
if (new in grid) -1 else 1
}.also {
// println(it.first)
}.second
}

fun solvePartTwo(): Long {
return 0
fun solvePartTwo(): String {
var bytes = gridSize
val start = Point(0, 0)
val target = Point(gridSize, gridSize)

runCatching {
while (true) {
val grid = parseInput(bytes)
grid.shortestPath(start, target) { _, new, _ -> if (new in grid) -1 else 1 }
bytes++
}
}

return parseInput(bytes).keys.last().let { "${it.x},${it.y}" }
}
}
2 changes: 1 addition & 1 deletion src/test/kotlin/y2024/day18/Day18Test.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ internal class Day18Test {

@Test
fun solvePartTwo() {
assertEquals(0, Day18.solvePartTwo())
assertEquals("20,12", Day18.solvePartTwo())
}
}

0 comments on commit b8755c2

Please sign in to comment.