From de3b0795e32bb9c71c64f837860a90c862eb53eb Mon Sep 17 00:00:00 2001 From: chrisly42 Date: Thu, 11 Dec 2025 15:30:13 +0100 Subject: [PATCH] Intermediate commit before I break stuff. --- src/PrimesAndFactors.kt | 54 ++++++++++++++++- src/aoc2025/Day10.kt | 128 ++++------------------------------------ 2 files changed, 63 insertions(+), 119 deletions(-) diff --git a/src/PrimesAndFactors.kt b/src/PrimesAndFactors.kt index 2eb9cec..1035b97 100644 --- a/src/PrimesAndFactors.kt +++ b/src/PrimesAndFactors.kt @@ -187,7 +187,59 @@ fun gcdPositive(aIn: Long, bIn: Long): Long { return a shl shift } -fun calcPrimeFactorsAndPhi(n: Long, primes: MutableList, allPrimes: MutableSet): Pair>, Long> { +// ax + by = gcdExtendedPositive(a, b) +fun extendedGcd(a: Long, b: Long): Pair> { + var old_r = a + var r = b + var old_s = 1L + var s = 0L + var old_t = 0L + var t = 1L + while (r != 0L) { + val q = old_r / r + val rtmp = old_r + old_r = r + r = rtmp - q * r + val stmp = old_s + old_s = s + s = stmp - q * s + val ttmp = old_t + old_t = t + t = ttmp - q * t + } + + return old_r to (old_s to old_t) +} + +fun extendedGcd(v: List): Pair> { + if (v.size < 2) throw IllegalArgumentException("Expected at least 2 elements") + + val gcds = ArrayList(v.size) + val coeffs = ArrayList(v.size) + var (gcd, p1) = extendedGcd(v[0], v[1]) + coeffs.add(p1.first) + coeffs.add(p1.second) + gcds.add(gcd) + gcds.add(gcd) + for (i in 2 until v.size) { + val (gcdnew, pi) = extendedGcd(gcd, v[i]) + gcd = gcdnew + coeffs.add(pi.second) + gcds.add(gcd) + } + for (i in gcds.indices) { + if (gcds[i] != gcd) { + coeffs[i] *= gcds[i] / gcd + } + } + return gcd to coeffs +} + +fun calcPrimeFactorsAndPhi( + n: Long, + primes: MutableList, + allPrimes: MutableSet +): Pair>, Long> { val factors = ArrayList>() var phi = 1L var rem = n diff --git a/src/aoc2025/Day10.kt b/src/aoc2025/Day10.kt index 6d08e35..d6e25c7 100644 --- a/src/aoc2025/Day10.kt +++ b/src/aoc2025/Day10.kt @@ -1,14 +1,13 @@ package aoc2025 import chineseRemainder -import gcdPositive +import extendedGcd import primeFactors import primeSequence import println import readInput import sieveOfErastosthenes import splitInts -import java.util.* /* --- Day 10: Factory --- @@ -60,40 +59,6 @@ fun main() { return sumButts } - data class Toggle(val idx: Int, val v: Int, var min: Int = 0, var max: Int = Int.MAX_VALUE) - - fun applyJoltage(jolts: IntArray, toggle: Toggle, times: Int = 1): Boolean { - var tt = toggle.v - var jp = 0 - var valid = true - while (tt != 0) { - if (tt and 1 != 0) { - jolts[jp] -= times - if (jolts[jp] < 0) { - valid = false - break - } - } - tt = tt shr 1 - jp++ - } - return valid - } - - fun findMaxButtonPresses(jolts: IntArray, toggle: Toggle): Int { - var tt = toggle.v - var jp = 0 - val maxPresses = Int.MAX_VALUE - while (tt != 0) { - if (tt and 1 != 0) { - maxPresses.coerceAtMost(jolts[jp] / 2) - } - tt = tt shr 1 - jp++ - } - return maxPresses - } - fun part2(input: List): Int { val machines = parse(input) @@ -105,7 +70,12 @@ fun main() { val maxJoltage = m.joltage.max() val primefactors = primes.dropWhile { it <= maxJoltage }.take(m.size).map { it.toLong() } if (primefactors.size != m.size) throw IllegalStateException() - val bigTarget = m.joltage.foldIndexed(0L) { index, acc, i -> acc.plus(i.toLong() * primefactors[index]) } + val primePow = LongArray(m.size) + primePow[0] = primefactors[0] + for (i in 1 until m.size) { + primePow[i] = primePow[i - 1] * primefactors[i] + } + val bigTarget = m.joltage.foldIndexed(0L) { index, acc, i -> acc.plus(i.toLong() * primePow[index]) } val bigToggles = ArrayList() for (t in m.toggles) { var tt = t @@ -113,9 +83,9 @@ fun main() { var idx = 0 while (tt > 0) { if (tt and 1 != 0) { - bigToggle += primefactors[idx] + bigToggle += primePow[idx] } - idx += 1 + idx++ tt = tt shr 1 } bigToggles.add(bigToggle) @@ -124,10 +94,7 @@ fun main() { // j0 * bigtoggle[0] + j1 * bigtoggle[1] + ... = bigTarget // is a Linear Diophantine equation that can be solved with the extended Euclidean algorithm - var gcd = gcdPositive(bigToggles[0], bigToggles[1]) - for (i in 2 until bigToggles.size) { - gcd = gcdPositive(gcd, bigToggles[i]) - } + val (gcd, coeffients) = extendedGcd(bigToggles) if (bigTarget % gcd != 0L) throw IllegalStateException() val factorMap = HashMap() @@ -152,81 +119,6 @@ fun main() { return sumButts } - fun part2old(input: List): Int { - val machines = parse(input) - - var sumButts = 0 - for (m in machines) { - // generate toggles and calculate the global maximum of toggle presses for this toggle - val toggles = m.toggles.mapIndexed { i, t -> - Toggle( - i, - t, - max = IntRange(0, m.size).filter { b -> t and (1 shl b) != 0 }.minOf { m.joltage[it] }) - } - // try to calculate a minimum number of toggle presses as the joltage needs to be reached exactly - val subsets = Array(m.size) { toggles.filter { v -> (1 shl it) and v.v != 0 }.toTypedArray() } - for (v in toggles) { - var minT = 0 - for (b in 0 until m.size) { - var rj = m.joltage[b] - var found = false - for (s in subsets[b]) { - if (s === v) { - found = true - } else { - rj -= s.max - if (rj < 0) break - } - } - if (found) minT = minT.coerceAtLeast(rj) - } - if (minT > v.max) throw IllegalStateException() - v.min = minT - } - - var minPushes = Int.MAX_VALUE - val jolts = m.joltage.copyOf() - val pressCount = IntArray(m.toggles.size) - - // press all buttons regarding their minimal count (if any) - for (t in toggles) { - if (pressCount[t.idx] + t.min > t.max || !applyJoltage(jolts, t, times = t.min)) throw IllegalStateException() - pressCount[t.idx] += t.min - } - // this is the starting point for the exhaustive search - val pq = PriorityQueue(compareBy> { it.second.sum() }) - pq.add(jolts to pressCount) - while (pq.isNotEmpty()) { - val (j, tc) = pq.poll() - val pushes = tc.sum() - if (pushes >= minPushes) break - // if the joltage has counted down to zero, we're done - if (j.sum() == 0) { - minPushes = pushes - break - } - for (t in toggles) { - if (tc[t.idx] + 2 <= t.max) { - val maxTimes = 1//findMaxButtonPresses(j, t) - if (maxTimes > 0) { - val nj = j.copyOf() - if (applyJoltage(nj, t, maxTimes)) { - val ntc = tc.copyOf() - ntc[t.idx] += maxTimes - pq.add(nj to ntc) - } - } - } - } - } - println("$minPushes") - sumButts += minPushes - } - - return sumButts - } - // test if implementation meets criteria from the description, like: val testInput = inlineTestInput.trim().reader().readLines() //val testInput = readInput("aoc2025/Day10_test")