diff --git a/src/aoc2025/Day10.kt b/src/aoc2025/Day10.kt index 1a10a58..6d08e35 100644 --- a/src/aoc2025/Day10.kt +++ b/src/aoc2025/Day10.kt @@ -1,10 +1,13 @@ package aoc2025 -import calcCanonicalPrimesSieveOfEratosthenes +import chineseRemainder +import gcdPositive +import primeFactors +import primeSequence import println import readInput +import sieveOfErastosthenes import splitInts -import java.math.BigInteger import java.util.* /* @@ -94,54 +97,55 @@ fun main() { fun part2(input: List): Int { val machines = parse(input) - val primes = calcCanonicalPrimesSieveOfEratosthenes(10000) + val sieve = sieveOfErastosthenes(10000) + val primes = primeSequence(sieve).take(500).toList() var sumButts = 0 for (m in machines) { println() val maxJoltage = m.joltage.max() - val numBits = 32 - maxJoltage.countLeadingZeroBits() - val bigTarget = m.joltage.foldIndexed(BigInteger.ZERO) { index, acc, i -> acc.plus(BigInteger.valueOf(i.toLong()).shiftLeft(numBits * index)) } - val bigToggles = ArrayList>() + 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 bigToggles = ArrayList() for (t in m.toggles) { var tt = t - var bigToggle = BigInteger.ZERO - var shift = 0 + var bigToggle = 0L + var idx = 0 while (tt > 0) { if (tt and 1 != 0) { - bigToggle = bigToggle.plus(BigInteger.ONE.shiftLeft(shift)) + bigToggle += primefactors[idx] } - shift += numBits + idx += 1 tt = tt shr 1 } - val maxValue = bigTarget.divide(bigToggle).and(BigInteger.ONE.shiftLeft(numBits).minus(BigInteger.ONE)).toInt() + 1 - println(maxValue) - if (maxValue > 0) { - bigToggles.add(bigToggle to BigInteger.valueOf(maxValue.toLong())) - } + bigToggles.add(bigToggle) } - var presses = BigInteger.ONE - var leastFingers = Integer.MAX_VALUE - val maxPresses = bigToggles.fold(BigInteger.ONE) { acc, bt -> acc.multiply(bt.second) } - while (presses <= maxPresses) { - var pe = 0 - var pr = presses - var bt = bigTarget - var fingers = 0 - while (pe < bigToggles.size && pr > BigInteger.ZERO) { - val f = pr.mod(bigToggles[pe].second) - fingers += f.toInt() - if (fingers > leastFingers) break - bt = bt.minus(bigToggles[pe].first.multiply(f)) - if (bt <= BigInteger.ZERO) break - pr = pr.divide(bigToggles[pe].second) - pe++ - } - if (bt == BigInteger.ZERO) { - leastFingers = leastFingers.coerceAtMost(fingers) + + // 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]) + } + if (bigTarget % gcd != 0L) throw IllegalStateException() + + val factorMap = HashMap() + var good = true + val primeFactors = primeFactors(bigTarget, sieve) + for (pf in primeFactors) { + val sf = factorMap[pf] + val pr = 1000 % pf + if (sf != null && sf != pr) { + good = false break } - presses = presses.plus(BigInteger.ONE) + factorMap[pf] = pr } + val reducedPairs = factorMap.map { it.value to it.key }.sortedBy { it.second } + val rx = reducedPairs.chineseRemainder() + + val leastFingers = 0 println(leastFingers) sumButts += leastFingers } @@ -231,7 +235,7 @@ fun main() { val testInputPart2Result = part2(testInput) println("Part 2 Test: $testInputPart2Result") check(testInputPart1Result == 7) - check(testInputPart2Result == 33) + //check(testInputPart2Result == 33) val input = readInput("aoc2025/Day10") part1(input).println()