Compare commits
No commits in common. "5e031c27cc3bd7a9d90d8780f886d9da0df73fc2" and "2190f9e1ac81fec68b9179b6a341cf5cdf13eedb" have entirely different histories.
5e031c27cc
...
2190f9e1ac
@ -1,5 +1,4 @@
|
|||||||
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
|
||||||
@ -188,106 +187,7 @@ fun gcdPositive(aIn: Long, bIn: Long): Long {
|
|||||||
return a shl shift
|
return a shl shift
|
||||||
}
|
}
|
||||||
|
|
||||||
// ax + by = gcdExtendedPositive(a, b)
|
fun calcPrimeFactorsAndPhi(n: Long, primes: MutableList<Long>, allPrimes: MutableSet<Long>): Pair<List<Pair<Long, Int>>, Long> {
|
||||||
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
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
package aoc2025
|
package aoc2025
|
||||||
|
|
||||||
import chineseRemainder
|
import chineseRemainder
|
||||||
import extendedGcdBigInteger
|
import gcdPositive
|
||||||
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.math.BigInteger
|
import java.util.*
|
||||||
|
|
||||||
/*
|
/*
|
||||||
--- Day 10: Factory ---
|
--- Day 10: Factory ---
|
||||||
@ -60,6 +60,40 @@ 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)
|
||||||
|
|
||||||
@ -69,22 +103,19 @@ fun main() {
|
|||||||
for (m in machines) {
|
for (m in machines) {
|
||||||
println()
|
println()
|
||||||
val maxJoltage = m.joltage.max()
|
val maxJoltage = m.joltage.max()
|
||||||
val numBits = 32 - maxJoltage.countLeadingZeroBits()
|
val primefactors = primes.dropWhile { it <= maxJoltage }.take(m.size).map { it.toLong() }
|
||||||
val bigTarget = m.joltage.foldIndexed(BigInteger.ZERO) { index, acc, i ->
|
if (primefactors.size != m.size) throw IllegalStateException()
|
||||||
acc.plus(
|
val bigTarget = m.joltage.foldIndexed(0L) { index, acc, i -> acc.plus(i.toLong() * primefactors[index]) }
|
||||||
BigInteger.valueOf(i.toLong()).shiftLeft(numBits * index)
|
val bigToggles = ArrayList<Long>()
|
||||||
)
|
|
||||||
}
|
|
||||||
val bigToggles = ArrayList<BigInteger>()
|
|
||||||
for (t in m.toggles) {
|
for (t in m.toggles) {
|
||||||
var tt = t
|
var tt = t
|
||||||
var bigToggle = BigInteger.ZERO
|
var bigToggle = 0L
|
||||||
var shift = 0
|
var idx = 0
|
||||||
while (tt > 0) {
|
while (tt > 0) {
|
||||||
if (tt and 1 != 0) {
|
if (tt and 1 != 0) {
|
||||||
bigToggle += BigInteger.ONE.shiftLeft(shift)
|
bigToggle += primefactors[idx]
|
||||||
}
|
}
|
||||||
shift += numBits
|
idx += 1
|
||||||
tt = tt shr 1
|
tt = tt shr 1
|
||||||
}
|
}
|
||||||
bigToggles.add(bigToggle)
|
bigToggles.add(bigToggle)
|
||||||
@ -93,12 +124,15 @@ 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
|
||||||
|
|
||||||
val (gcd, coeffients) = extendedGcdBigInteger(bigToggles)
|
var gcd = gcdPositive(bigToggles[0], bigToggles[1])
|
||||||
if (bigTarget % gcd != BigInteger.ZERO) throw IllegalStateException()
|
for (i in 2 until bigToggles.size) {
|
||||||
|
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.toLong(), sieve)
|
val primeFactors = primeFactors(bigTarget, 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
|
||||||
@ -118,6 +152,81 @@ 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")
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user