Intermediate commit before I break stuff.

This commit is contained in:
Chris Hodges 2025-12-11 15:30:13 +01:00
parent 2190f9e1ac
commit de3b0795e3
2 changed files with 63 additions and 119 deletions

View File

@ -187,7 +187,59 @@ 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(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 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,13 @@
package aoc2025 package aoc2025
import chineseRemainder import chineseRemainder
import gcdPositive import extendedGcd
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.*
/* /*
--- Day 10: Factory --- --- Day 10: Factory ---
@ -60,40 +59,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)
@ -105,7 +70,12 @@ fun main() {
val maxJoltage = m.joltage.max() val maxJoltage = m.joltage.max()
val primefactors = primes.dropWhile { it <= maxJoltage }.take(m.size).map { it.toLong() } val primefactors = primes.dropWhile { it <= maxJoltage }.take(m.size).map { it.toLong() }
if (primefactors.size != m.size) throw IllegalStateException() 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<Long>() val bigToggles = ArrayList<Long>()
for (t in m.toggles) { for (t in m.toggles) {
var tt = t var tt = t
@ -113,9 +83,9 @@ fun main() {
var idx = 0 var idx = 0
while (tt > 0) { while (tt > 0) {
if (tt and 1 != 0) { if (tt and 1 != 0) {
bigToggle += primefactors[idx] bigToggle += primePow[idx]
} }
idx += 1 idx++
tt = tt shr 1 tt = tt shr 1
} }
bigToggles.add(bigToggle) bigToggles.add(bigToggle)
@ -124,10 +94,7 @@ 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) = extendedGcd(bigToggles)
for (i in 2 until bigToggles.size) {
gcd = gcdPositive(gcd, bigToggles[i])
}
if (bigTarget % gcd != 0L) throw IllegalStateException() if (bigTarget % gcd != 0L) throw IllegalStateException()
val factorMap = HashMap<Long, Long>() val factorMap = HashMap<Long, Long>()
@ -152,81 +119,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")