124 lines
4.4 KiB
Kotlin
124 lines
4.4 KiB
Kotlin
package aoc2024
|
||
|
||
import println
|
||
import readInput
|
||
|
||
/*
|
||
--- Day 13: Claw Contraption ---
|
||
https://adventofcode.com/2024/day/13
|
||
*/
|
||
fun main() {
|
||
|
||
val inlineTestInput = """
|
||
Button A: X+94, Y+34
|
||
Button B: X+22, Y+67
|
||
Prize: X=8400, Y=5400
|
||
|
||
Button A: X+26, Y+66
|
||
Button B: X+67, Y+21
|
||
Prize: X=12748, Y=12176
|
||
|
||
Button A: X+17, Y+86
|
||
Button B: X+84, Y+37
|
||
Prize: X=7870, Y=6450
|
||
|
||
Button A: X+69, Y+23
|
||
Button B: X+27, Y+71
|
||
Prize: X=18641, Y=10279
|
||
"""
|
||
|
||
fun part1(input: List<String>): Int {
|
||
var i = 0
|
||
var sum = 0
|
||
while (i < input.size) {
|
||
val (ax, ay) = "Button A: X\\+(\\d+), Y\\+(\\d+)".toRegex().find(input[i++])!!.groupValues.drop(1).map { it.toInt() }
|
||
val (bx, by) = "Button B: X\\+(\\d+), Y\\+(\\d+)".toRegex().find(input[i++])!!.groupValues.drop(1).map { it.toInt() }
|
||
val (px, py) = "Prize: X=(\\d+), Y=(\\d+)".toRegex().find(input[i++])!!.groupValues.drop(1).map { it.toInt() }
|
||
i++
|
||
val xpos = IntArray(101 * 101)
|
||
val ypos = IntArray(101 * 101)
|
||
val solutions = ArrayList<Int>()
|
||
for (b in 1..100) {
|
||
for (a in 1..100) {
|
||
val op = (a - 1) + (b - 1) * 101
|
||
if ((xpos[op] == px) && (ypos[op] == py)) {
|
||
solutions.add(op)
|
||
}
|
||
if ((xpos[op] > px) || (ypos[op] > py)) break
|
||
xpos[a + (b - 1) * 101] = xpos[op] + ax
|
||
xpos[(a - 1) + b * 101] = xpos[op] + bx
|
||
ypos[a + (b - 1) * 101] = ypos[op] + ay
|
||
ypos[(a - 1) + b * 101] = ypos[op] + by
|
||
}
|
||
}
|
||
val minTokens = solutions.minOfOrNull { (it % 101) * 3 + (it / 101) }
|
||
sum += minTokens ?: 0
|
||
}
|
||
return sum
|
||
}
|
||
|
||
fun part2(input: List<String>): Long {
|
||
var i = 0
|
||
var sum = 0L
|
||
|
||
// 1. ax * pa + bx * pb = px
|
||
// 2. ay * pa + by * pb = py
|
||
// 3. pa * 3 + pb <- min
|
||
// 4. pa, pb in N (int > 0)
|
||
|
||
// ax * pa + bx * pb - px = ay * pa + by * pb - py
|
||
// (ax - ay) * pa + (bx - by) * pb + py - px = 0
|
||
// (ax - ay) * pa + (bx - by) * pb = px - py
|
||
|
||
while (i < input.size) {
|
||
val (ax, ay) = "Button A: X\\+(\\d+), Y\\+(\\d+)".toRegex().find(input[i++])!!.groupValues.drop(1).map { it.toLong() }
|
||
val (bx, by) = "Button B: X\\+(\\d+), Y\\+(\\d+)".toRegex().find(input[i++])!!.groupValues.drop(1).map { it.toLong() }
|
||
val (px, py) = "Prize: X=(\\d+), Y=(\\d+)".toRegex().find(input[i++])!!.groupValues.drop(1).map { it.toLong() + 10000000000000L }
|
||
i++
|
||
|
||
// val t1 = ax - ay
|
||
// val t2 = bx - by
|
||
// val t3 = px - py
|
||
|
||
// Linear Diophantine equations
|
||
/* The simplest linear Diophantine equation takes the form
|
||
a*x + b*x = c
|
||
where a, b and c are given integers.
|
||
The solutions are described by the following theorem:
|
||
This Diophantine equation has a solution (where x and y are integers),
|
||
IFF c is a multiple of the greatest common divisor of a and b.
|
||
Moreover, if (x, y) is a solution, then the other solutions have the
|
||
form (x + kv, y − ku), where
|
||
- k is an arbitrary integer, and
|
||
- u and v are the quotients of a and b (respectively) by the greatest common divisor of a and b.
|
||
*/
|
||
// With our input data, all equations have exactly one solution
|
||
val pad = (px * by - py * bx)
|
||
val pan = (ax * by - ay * bx)
|
||
if (pad % pan == 0L) {
|
||
val pa = pad / pan
|
||
val pbd = (px - pa * ax)
|
||
if (pbd % bx == 0L) {
|
||
val pb = pbd / bx
|
||
sum += pa * 3 + pb
|
||
}
|
||
}
|
||
}
|
||
return sum
|
||
}
|
||
|
||
// test if implementation meets criteria from the description, like:
|
||
val testInput = inlineTestInput.trim().reader().readLines()
|
||
//val testInput = readInput("aoc2024/Day13_test")
|
||
val testInputPart1Result = part1(testInput)
|
||
println("Part 1 Test: $testInputPart1Result")
|
||
val testInputPart2Result = part2(testInput)
|
||
println("Part 2 Test: $testInputPart2Result")
|
||
check(testInputPart1Result == 480)
|
||
//check(testInputPart2Result == 0L)
|
||
|
||
val input = readInput("aoc2024/Day13")
|
||
part1(input).println()
|
||
part2(input).println()
|
||
}
|