Skip to content

Day 10 complete #15

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 10, 2024
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
28 changes: 28 additions & 0 deletions src/main/kotlin/common/intpos2d/intpos2d.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,31 @@ operator fun Int.times(pos: IntPos2D): IntPos2D =

operator fun IntPos2D.times(factor: Int) =
factor * this

enum class Direction(val delta: IntPos2D) {
NORTH(IntPos2D(-1, 0)),
EAST(IntPos2D(0, 1)),
SOUTH(IntPos2D(1, 0)),
WEST(IntPos2D(0, -1));

fun clockwise(): Direction = when (this) {
NORTH -> EAST
EAST -> SOUTH
SOUTH -> WEST
WEST -> NORTH
}

fun counterClockwise(): Direction = when (this) {
NORTH -> WEST
WEST -> SOUTH
SOUTH -> EAST
EAST -> NORTH
}

fun opposite(): Direction = when (this) {
NORTH -> SOUTH
EAST -> WEST
SOUTH -> NORTH
WEST -> EAST
}
}
17 changes: 0 additions & 17 deletions src/main/kotlin/day06/day06.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,6 @@ package day06
import common.aocreader.fetchAdventOfCodeInput
import common.intpos2d.*

/**
* The direction that the guard is facing and moves in.
*/
private enum class Direction(val delta: IntPos2D) {
NORTH(IntPos2D(-1, 0)),
SOUTH(IntPos2D(1, 0)),
EAST(IntPos2D(0, 1)),
WEST(IntPos2D(0, -1));

fun clockwise(): Direction = when (this) {
NORTH -> EAST
EAST -> SOUTH
SOUTH -> WEST
WEST -> NORTH
}
}

private typealias Orientation = Pair<Direction, IntPos2D>

private data class MapGrid(val rows: Int,
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/day09/day09.kt
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ fun answer2(input: String): BigInteger =
fun main() {
val input = fetchAdventOfCodeInput(2024, 9)

println("--- Day 9: Resonant Collinearity ---")
println("--- Day 9: Disk Fragmenter ---")

// Part 1: 6384282079460
println("Part 1: ${answer1(input)}")
Expand Down
68 changes: 68 additions & 0 deletions src/main/kotlin/day10/day10.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Advent of Code 2024, Day 09.
// By Sebastian Raaphorst, 2024.

package day10

import common.aocreader.fetchAdventOfCodeInput
import common.intpos2d.*

private typealias Trail = List<IntPos2D>
private typealias Trails = Set<List<IntPos2D>>

private fun parse(input: String): List<List<Int>> =
input.trim().lines()
.map { line -> line.trim().toList().map { it.digitToIntOrNull() ?: -1 } }

private fun findTrails(grid: List<List<Int>>): Map<IntPos2D, Trails> {
val height = grid.size
val width = grid[0].size

val zeros = grid.flatMapIndexed { rowIdx, row ->
row.mapIndexedNotNull { colIdx, height ->
if (height == 0) IntPos2D(rowIdx, colIdx) else null
}
}.toSet()

// For each 9, we want to find the trails that lead to the peak.
fun aux(trailSoFar: Trail): Trails {
val currentPos = trailSoFar.last()
val (currY, currX) = currentPos
val currHeight = grid[currY][currX]
if (currHeight == 9) return setOf(trailSoFar)

// Try all the valid neighbours.
val neighbours = Direction.entries
.map { currentPos + it.delta }
.filter { coords -> coords.first in 0 until height && coords.second in 0 until width }
.filter { coords -> grid[coords.first][coords.second] == currHeight + 1 }
if (neighbours.isEmpty()) return emptySet()

return neighbours.flatMap { pos -> aux(trailSoFar + pos) }.toSet()
}

return zeros.associate { zero -> zero to aux(listOf(zero)) }
}

private fun countTrailheads(trails: Map<IntPos2D, Trails>): Int =
trails.values.sumOf { it.map { it.last() }.toSet().size }

private fun countTrails(trails: Map<IntPos2D, Trails>): Int =
trails.values.sumOf { it.count() }

fun answer1(input: String): Int =
parse(input).let(::findTrails).let(::countTrailheads)

fun answer2(input: String): Int =
parse(input).let(::findTrails).let(::countTrails)

fun main() {
val input = fetchAdventOfCodeInput(2024, 10)

println("--- Day 10: Hoof It ---")

// Part 1: 719
println("Part 1: ${answer1(input)}")

// Part 2: 1530
println("Part 2: ${answer2(input)}")
}
31 changes: 31 additions & 0 deletions src/test/kotlin/day10/day10.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Advent of Code 2024, Day 10.
// By Sebastian Raaphorst, 2024.

package day10

import org.junit.jupiter.api.Test
import kotlin.test.assertEquals

class Day10Test {
private companion object {
val input =
"""
89010123
78121874
87430965
96549874
45678903
32019012
01329801
10456732
""".trimIndent().trim()
}

@Test
fun `Problem 1 example`() =
assertEquals(36, answer1(input))

@Test
fun `Problem 2 example`() =
assertEquals(81, answer2(input))
}
Loading