Compare commits

...

3 Commits

3 changed files with 185 additions and 27 deletions

View File

@ -82,7 +82,7 @@ Prize: X=18641, Y=10279
// Linear Diophantine equations // Linear Diophantine equations
/* The simplest linear Diophantine equation takes the form /* The simplest linear Diophantine equation takes the form
a*x + b*x = c a*x + b*y = c
where a, b and c are given integers. where a, b and c are given integers.
The solutions are described by the following theorem: The solutions are described by the following theorem:
This Diophantine equation has a solution (where x and y are integers), This Diophantine equation has a solution (where x and y are integers),

View File

@ -1,8 +1,10 @@
package aoc2025 package aoc2025
import calcCanonicalPrimesSieveOfEratosthenes
import println import println
import readInput import readInput
import splitInts import splitInts
import java.math.BigInteger
import java.util.* import java.util.*
/* /*
@ -29,7 +31,6 @@ fun main() {
val toggles = val toggles =
stuff.drop(1).dropLast(1) stuff.drop(1).dropLast(1)
.map { it.removeSurrounding("(", ")").splitInts(",").fold(0) { acc, v -> acc + (1 shl v) } } .map { it.removeSurrounding("(", ")").splitInts(",").fold(0) { acc, v -> acc + (1 shl v) } }
.sortedByDescending { it.countOneBits() }
.toIntArray() .toIntArray()
val joltages = stuff.last().removeSurrounding("{", "}").splitInts(",").toIntArray() val joltages = stuff.last().removeSurrounding("{", "}").splitInts(",").toIntArray()
machines.add(Machine(machSize, target, toggles, joltages)) machines.add(Machine(machSize, target, toggles, joltages))
@ -41,23 +42,17 @@ fun main() {
val machines = parse(input) val machines = parse(input)
var sumButts = 0 var sumButts = 0
for (m in machines) { for (m in machines) {
val pq = LinkedList<Pair<Int, Int>>() // look at which different possible sets of toggles need to be pressed to result in the target number
val killArray = BooleanArray(1 shl m.size) // pressing an even time will cancel out the effect, so only look what happens if you press once
pq.add(0 to 0) var minPresses = Int.MAX_VALUE
out@ while (pq.isNotEmpty()) { for (tm in 1 until (1 shl m.toggles.size)) {
val (v, bi) = pq.poll() val odds = m.toggles.filterIndexed { i, v -> (1 shl i) and tm != 0 }
for (t in m.toggles) { val result = odds.fold(0) { acc, iv -> acc xor iv }
val nv = v xor t if (result == m.target) {
if (nv == m.target) { minPresses = minPresses.coerceAtMost(odds.size)
sumButts += bi + 1
break@out
}
if (!killArray[nv]) {
killArray[v] = true
pq.add(nv to bi + 1)
}
} }
} }
sumButts += minPresses
} }
return sumButts return sumButts
} }
@ -99,11 +94,69 @@ fun main() {
fun part2(input: List<String>): Int { fun part2(input: List<String>): Int {
val machines = parse(input) val machines = parse(input)
val primes = calcCanonicalPrimesSieveOfEratosthenes(10000)
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<Pair<BigInteger, BigInteger>>()
for (t in m.toggles) {
var tt = t
var bigToggle = BigInteger.ZERO
var shift = 0
while (tt > 0) {
if (tt and 1 != 0) {
bigToggle = bigToggle.plus(BigInteger.ONE.shiftLeft(shift))
}
shift += numBits
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()))
}
}
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)
break
}
presses = presses.plus(BigInteger.ONE)
}
println(leastFingers)
sumButts += leastFingers
}
return sumButts
}
fun part2old(input: List<String>): Int {
val machines = parse(input)
var sumButts = 0 var sumButts = 0
for (m in machines) { for (m in machines) {
// generate toggles and calculate the global maximum of toggle presses for this toggle // generate toggles and calculate the global maximum of toggle presses for this toggle
val toggles = m.toggles.mapIndexed { i, t -> val toggles = m.toggles.mapIndexed { i, t ->
Toggle(i, Toggle(
i,
t, t,
max = IntRange(0, m.size).filter { b -> t and (1 shl b) != 0 }.minOf { m.joltage[it] }) max = IntRange(0, m.size).filter { b -> t and (1 shl b) != 0 }.minOf { m.joltage[it] })
} }
@ -128,19 +181,13 @@ fun main() {
v.min = minT v.min = minT
} }
// iterate over the possible odd sets
var minPushes = Int.MAX_VALUE var minPushes = Int.MAX_VALUE
val jolts = m.joltage.copyOf() val jolts = m.joltage.copyOf()
val pressCount = IntArray(m.toggles.size) val pressCount = IntArray(m.toggles.size)
// press all buttons regarding their minimal count (if any) // press all buttons regarding their minimal count (if any)
for (t in toggles) { for (t in toggles) {
if (pressCount[t.idx] + t.min > t.max || !applyJoltage( if (pressCount[t.idx] + t.min > t.max || !applyJoltage(jolts, t, times = t.min)) throw IllegalStateException()
jolts,
t,
times = t.min
)
) throw IllegalStateException()
pressCount[t.idx] += t.min pressCount[t.idx] += t.min
} }
// this is the starting point for the exhaustive search // this is the starting point for the exhaustive search
@ -157,7 +204,7 @@ fun main() {
} }
for (t in toggles) { for (t in toggles) {
if (tc[t.idx] + 2 <= t.max) { if (tc[t.idx] + 2 <= t.max) {
val maxTimes = findMaxButtonPresses(j, t) val maxTimes = 1//findMaxButtonPresses(j, t)
if (maxTimes > 0) { if (maxTimes > 0) {
val nj = j.copyOf() val nj = j.copyOf()
if (applyJoltage(nj, t, maxTimes)) { if (applyJoltage(nj, t, maxTimes)) {
@ -184,7 +231,7 @@ fun main() {
val testInputPart2Result = part2(testInput) val testInputPart2Result = part2(testInput)
println("Part 2 Test: $testInputPart2Result") println("Part 2 Test: $testInputPart2Result")
check(testInputPart1Result == 7) check(testInputPart1Result == 7)
//check(testInputPart2Result == 33) check(testInputPart2Result == 33)
val input = readInput("aoc2025/Day10") val input = readInput("aoc2025/Day10")
part1(input).println() part1(input).println()

111
src/aoc2025/Day11.kt Normal file
View File

@ -0,0 +1,111 @@
package aoc2025
import println
import readInput
/*
--- Day 11: Reactor ---
https://adventofcode.com/2025/day/11
*/
fun main() {
val inlineTestInput = """
aaa: you hhh
you: bbb ccc
bbb: ddd eee
ccc: ddd eee fff
ddd: ggg
eee: out
fff: out
ggg: out
hhh: ccc fff iii
iii: out
"""
val inlineTestInput2 = """
svr: aaa bbb
aaa: fft
fft: ccc
bbb: tty
tty: ccc
ccc: ddd eee
ddd: hub
hub: fff
eee: dac
dac: fff
fff: ggg hhh
ggg: out
hhh: out
"""
data class Node(val name: String, val children: Set<Node>)
fun rec(children: HashMap<String, MutableSet<String>>, p: String, visited: MutableSet<String>): Int {
if (p == "out") return 1
visited.add(p)
val res = children[p]!!.sumOf { rec(children, it, visited) }
visited.remove(p)
return res
}
fun parseInput(input: List<String>): HashMap<String, MutableSet<String>> {
val children = HashMap<String, MutableSet<String>>()
for (i in input) {
val (n, chs) = i.split(": ")
val ch = chs.split(" ")
children.getOrPut(n) { HashSet() }.addAll(ch)
}
return children
}
fun part1(input: List<String>): Int {
val children = parseInput(input)
return rec(children, "you", HashSet())
}
fun rec2(
children: HashMap<String, MutableSet<String>>,
p: String,
stop: String,
visited: MutableSet<String> = HashSet(),
memo: HashMap<String, Long> = HashMap()
): Long {
if (p == stop) return 1L
val memoVal = memo[p]
if (memoVal != null) return memoVal
visited.add(p)
val res = children[p]?.sumOf { rec2(children, it, stop, visited, memo) } ?: 0L
visited.remove(p)
memo[p] = res
return res
}
fun part2(input: List<String>): Long {
val children = parseInput(input)
val srvToDac = rec2(children, "svr", "dac")
val dacToFft = rec2(children, "dac", "fft")
val fftToOut = rec2(children, "fft", "out")
val srvToFft = rec2(children, "svr", "fft")
val fftToDac = rec2(children, "fft", "dac")
val dacToOut = rec2(children, "dac", "out")
return srvToDac * dacToFft * fftToOut + srvToFft * fftToDac * dacToOut
}
// test if implementation meets criteria from the description, like:
val testInput = inlineTestInput.trim().reader().readLines()
val testInput2 = inlineTestInput2.trim().reader().readLines()
//val testInput = readInput("aoc2025/Day11_test")
val testInputPart1Result = part1(testInput)
println("Part 1 Test: $testInputPart1Result")
val testInputPart2Result = part2(testInput2)
println("Part 2 Test: $testInputPart2Result")
check(testInputPart1Result == 5)
check(testInputPart2Result == 2L)
val input = readInput("aoc2025/Day11")
part1(input).println()
part2(input).println()
}