diff --git a/README.md b/README.md index f2fb0da..cfcddb2 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ | 2021 | ★ | ★ | ★ | ★ | ★ | ★ | ★ | ★ | ★ | ★ | ★ | | ★ | ★ | | | | | | | | | | | | 26 | | 2022 | ★ | ★ | ★ | ★ | ★ | ★ | ★ | ★ | ★ | ★ | ★ | ★ | ★ | | | | | | | | ☆ | | | | ☆ | 28 | | 2023 | ★ | ★ | ★ | ★ | ☆ | ★ | ☆ | | | | | | | | | | | | | | | | | | | 12 | -| 2024 | ★ | ★ | ★ | ★ | ★ | ★ | ★ | ★ | ★ | ★ | ★ | ★ | ☆ | | | | | | | | | | | | | 25 | +| 2024 | ★ | ★ | ★ | ★ | ★ | ★ | ★ | ★ | ★ | ★ | ★ | ★ | ★ | | | | | | | | | | | | | 26 | ## 🛷 How to run @@ -176,7 +176,7 @@ e.g. `HandyHaversacks`)* | | 10 | [Hoof It](https://adventofcode.com/2024/day/10) | [[Code](src/main/kotlin/adventofcode/year2024/Day10HoofIt.kt)] [[Test](src/test/kotlin/adventofcode/year2024/Day10HoofItSpec.kt)] | `746` | `1541` | | | 11 | [Plutonian Pebbles](https://adventofcode.com/2024/day/11) | [[Code](src/main/kotlin/adventofcode/year2024/Day11PlutonianPebbles.kt)] [[Test](src/test/kotlin/adventofcode/year2024/Day11PlutonianPebblesSpec.kt)] | `194482` | `232454623677743` | | | 12 | [Garden Groups](https://adventofcode.com/2024/day/12) | [[Code](src/main/kotlin/adventofcode/year2024/Day12GardenGroups.kt)] [[Test](src/test/kotlin/adventofcode/year2024/Day12GardenGroupsSpec.kt)] | `1573474` | `966476` | -| | 13 | [Claw Contraption](https://adventofcode.com/2024/day/13) | [[Code](src/main/kotlin/adventofcode/year2024/Day13ClawContraption.kt)] [[Test](src/test/kotlin/adventofcode/year2024/Day13ClawContraptionSpec.kt)] | `28138` | | +| | 13 | [Claw Contraption](https://adventofcode.com/2024/day/13) | [[Code](src/main/kotlin/adventofcode/year2024/Day13ClawContraption.kt)] [[Test](src/test/kotlin/adventofcode/year2024/Day13ClawContraptionSpec.kt)] | `28138` | `108394825772874` | ## 🕯️ Useful commands diff --git a/src/main/kotlin/adventofcode/common/Grid2d.kt b/src/main/kotlin/adventofcode/common/Grid2d.kt index 3ee9130..141f045 100644 --- a/src/main/kotlin/adventofcode/common/Grid2d.kt +++ b/src/main/kotlin/adventofcode/common/Grid2d.kt @@ -3,9 +3,11 @@ package adventofcode.common import kotlin.String data class Point2d( - val x: Int, - val y: Int, + val x: Long, + val y: Long, ) { + constructor(x: Number, y: Number) : this(x.toLong(), y.toLong()) + /** * Pretty formatted String representation. * @@ -17,6 +19,11 @@ data class Point2d( * Add two points together by adding their x and y coordinates */ operator fun plus(other: Point2d): Point2d = Point2d(x + other.x, y + other.y) + + /** + * Add a constant offset to the point's x and y coordinates + */ + operator fun plus(offset: Number): Point2d = Point2d(x + offset.toLong(), y + offset.toLong()) } val NORTH = Point2d(0, -1) @@ -56,19 +63,23 @@ data class Grid2d(val values: List>) { */ fun find(value: T): List = points - .filter { (x, y) -> values[y][x] == value } + .filter { (x, y) -> values[y.toInt()][x.toInt()] == value } .map { (x, y) -> Point2d(x, y) } /** * Returns the value at the given point if the point is within the grid, throws otherwise. */ operator fun get(point: Point2d): T = - if (point in this) values[point.y][point.x] else throw IndexOutOfBoundsException("Point $point is not part of this grid") + if (point in this) { + values[point.y.toInt()][point.x.toInt()] + } else { + throw IndexOutOfBoundsException("Point $point is outside of the grid") + } /** * Returns the value at the given point if the point is within the grid, or `null` otherwise. */ - fun getOrNull(point: Point2d): T? = if (point in this) values[point.y][point.x] else null + fun getOrNull(point: Point2d): T? = if (point in this) values[point.y.toInt()][point.x.toInt()] else null /** * Returns a set of valid neighbors for a given point P in the grid. diff --git a/src/main/kotlin/adventofcode/year2024/Day13ClawContraption.kt b/src/main/kotlin/adventofcode/year2024/Day13ClawContraption.kt index 9c542c3..260d1d8 100644 --- a/src/main/kotlin/adventofcode/year2024/Day13ClawContraption.kt +++ b/src/main/kotlin/adventofcode/year2024/Day13ClawContraption.kt @@ -21,9 +21,27 @@ class Day13ClawContraption(customInput: PuzzleInput? = null) : Puzzle(customInpu } } - override fun partOne() = + override fun partOne() = clawMachines.sumOf { clawMachine -> clawMachine.countTokens() } + + override fun partTwo() = clawMachines - .mapNotNull { (buttonA, buttonB, prize) -> + .map { (buttonA, buttonB, prize) -> ClawMachine(buttonA, buttonB, prize + PART_TWO_OFFSET) } + .sumOf { clawMachine -> clawMachine.countTokens() } + + companion object { + private val INPUT_REGEX = """X[+|=](\d+), Y[+|=](\d+)""".toRegex() + + private const val COST_A = 3 + private const val COST_B = 1 + + private const val PART_TWO_OFFSET = 10000000000000 + + private data class ClawMachine( + val buttonA: Point2d, + val buttonB: Point2d, + val prize: Point2d, + ) { + fun countTokens(): Long { val (ax, ay) = buttonA val (bx, by) = buttonB val (px, py) = prize @@ -32,24 +50,12 @@ class Day13ClawContraption(customInput: PuzzleInput? = null) : Puzzle(customInpu val a = px * by - bx * py val b = ax * py - px * ay - if (setOf(a, b).all { it % dividend == 0 }) { + return if (setOf(a, b).all { it % dividend == 0L }) { a / dividend * COST_A + b / dividend * COST_B } else { - null + 0 } } - .sum() - - companion object { - private val INPUT_REGEX = """X[+|=](\d+), Y[+|=](\d+)""".toRegex() - - private const val COST_A = 3 - private const val COST_B = 1 - - private data class ClawMachine( - val buttonA: Point2d, - val buttonB: Point2d, - val prize: Point2d, - ) + } } } diff --git a/src/test/kotlin/adventofcode/common/Grid2dSpec.kt b/src/test/kotlin/adventofcode/common/Grid2dSpec.kt index d91ca1a..818cff0 100644 --- a/src/test/kotlin/adventofcode/common/Grid2dSpec.kt +++ b/src/test/kotlin/adventofcode/common/Grid2dSpec.kt @@ -85,7 +85,7 @@ class Grid2dSpec : FreeSpec({ shouldThrow { grid[Point2d(10, 10)] }.apply { - message shouldBe "Point (10, 10) is not part of this grid" + message shouldBe "Point (10, 10) is outside of the grid" } } }