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): 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() 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): 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() }