Compare commits

...

2 Commits

Author SHA1 Message Date
5e031c27cc WiP 2025-12-15 09:55:01 +01:00
de3b0795e3 Intermediate commit before I break stuff. 2025-12-11 15:30:13 +01:00
2 changed files with 117 additions and 126 deletions

View File

@ -1,4 +1,5 @@
import java.lang.Long.numberOfTrailingZeros import java.lang.Long.numberOfTrailingZeros
import java.math.BigInteger
import java.util.* import java.util.*
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.min import kotlin.math.min
@ -187,7 +188,106 @@ fun gcdPositive(aIn: Long, bIn: Long): Long {
return a shl shift return a shl shift
} }
fun calcPrimeFactorsAndPhi(n: Long, primes: MutableList<Long>, allPrimes: MutableSet<Long>): Pair<List<Pair<Long, Int>>, Long> { // ax + by = gcdExtendedPositive(a, b)
fun extendedGcd(a: Long, b: Long): Pair<Long, Pair<Long, Long>> {
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(a: BigInteger, b: BigInteger): Pair<BigInteger, Pair<BigInteger, BigInteger>> {
var old_r = a
var r = b
var old_s = BigInteger.ONE
var s = BigInteger.ZERO
var old_t = BigInteger.ZERO
var t = BigInteger.ONE
while (r != BigInteger.ZERO) {
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<Long>): Pair<Long, List<Long>> {
if (v.size < 2) throw IllegalArgumentException("Expected at least 2 elements")
val gcds = ArrayList<Long>(v.size)
val coeffs = ArrayList<Long>(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 extendedGcdBigInteger(v: List<BigInteger>): Pair<BigInteger, List<BigInteger>> {
if (v.size < 2) throw IllegalArgumentException("Expected at least 2 elements")
val gcds = ArrayList<BigInteger>(v.size)
val coeffs = ArrayList<BigInteger>(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<Long>,
allPrimes: MutableSet<Long>
): Pair<List<Pair<Long, Int>>, Long> {
val factors = ArrayList<Pair<Long, Int>>() val factors = ArrayList<Pair<Long, Int>>()
var phi = 1L var phi = 1L
var rem = n var rem = n

View File

@ -1,14 +1,14 @@
package aoc2025 package aoc2025
import chineseRemainder import chineseRemainder
import gcdPositive import extendedGcdBigInteger
import primeFactors import primeFactors
import primeSequence import primeSequence
import println import println
import readInput import readInput
import sieveOfErastosthenes import sieveOfErastosthenes
import splitInts import splitInts
import java.util.* import java.math.BigInteger
/* /*
--- Day 10: Factory --- --- Day 10: Factory ---
@ -60,40 +60,6 @@ fun main() {
return sumButts 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<String>): Int { fun part2(input: List<String>): Int {
val machines = parse(input) val machines = parse(input)
@ -103,19 +69,22 @@ fun main() {
for (m in machines) { for (m in machines) {
println() println()
val maxJoltage = m.joltage.max() val maxJoltage = m.joltage.max()
val primefactors = primes.dropWhile { it <= maxJoltage }.take(m.size).map { it.toLong() } val numBits = 32 - maxJoltage.countLeadingZeroBits()
if (primefactors.size != m.size) throw IllegalStateException() val bigTarget = m.joltage.foldIndexed(BigInteger.ZERO) { index, acc, i ->
val bigTarget = m.joltage.foldIndexed(0L) { index, acc, i -> acc.plus(i.toLong() * primefactors[index]) } acc.plus(
val bigToggles = ArrayList<Long>() BigInteger.valueOf(i.toLong()).shiftLeft(numBits * index)
)
}
val bigToggles = ArrayList<BigInteger>()
for (t in m.toggles) { for (t in m.toggles) {
var tt = t var tt = t
var bigToggle = 0L var bigToggle = BigInteger.ZERO
var idx = 0 var shift = 0
while (tt > 0) { while (tt > 0) {
if (tt and 1 != 0) { if (tt and 1 != 0) {
bigToggle += primefactors[idx] bigToggle += BigInteger.ONE.shiftLeft(shift)
} }
idx += 1 shift += numBits
tt = tt shr 1 tt = tt shr 1
} }
bigToggles.add(bigToggle) bigToggles.add(bigToggle)
@ -124,15 +93,12 @@ fun main() {
// j0 * bigtoggle[0] + j1 * bigtoggle[1] + ... = bigTarget // j0 * bigtoggle[0] + j1 * bigtoggle[1] + ... = bigTarget
// is a Linear Diophantine equation that can be solved with the extended Euclidean algorithm // is a Linear Diophantine equation that can be solved with the extended Euclidean algorithm
var gcd = gcdPositive(bigToggles[0], bigToggles[1]) val (gcd, coeffients) = extendedGcdBigInteger(bigToggles)
for (i in 2 until bigToggles.size) { if (bigTarget % gcd != BigInteger.ZERO) throw IllegalStateException()
gcd = gcdPositive(gcd, bigToggles[i])
}
if (bigTarget % gcd != 0L) throw IllegalStateException()
val factorMap = HashMap<Long, Long>() val factorMap = HashMap<Long, Long>()
var good = true var good = true
val primeFactors = primeFactors(bigTarget, sieve) val primeFactors = primeFactors(bigTarget.toLong(), sieve)
for (pf in primeFactors) { for (pf in primeFactors) {
val sf = factorMap[pf] val sf = factorMap[pf]
val pr = 1000 % pf val pr = 1000 % pf
@ -152,81 +118,6 @@ fun main() {
return sumButts return sumButts
} }
fun part2old(input: List<String>): 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<Pair<IntArray, IntArray>> { 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: // test if implementation meets criteria from the description, like:
val testInput = inlineTestInput.trim().reader().readLines() val testInput = inlineTestInput.trim().reader().readLines()
//val testInput = readInput("aoc2025/Day10_test") //val testInput = readInput("aoc2025/Day10_test")