Compare commits
No commits in common. "a69be406b16ee4c161b2a18ba5edb48e6f3bda95" and "bd591263f6e11f24d022f0301d80f6e20d687c16" have entirely different histories.
a69be406b1
...
bd591263f6
@ -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*y = c
|
a*x + b*x = 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),
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
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.*
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -31,6 +29,7 @@ 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))
|
||||||
@ -42,17 +41,23 @@ fun main() {
|
|||||||
val machines = parse(input)
|
val machines = parse(input)
|
||||||
var sumButts = 0
|
var sumButts = 0
|
||||||
for (m in machines) {
|
for (m in machines) {
|
||||||
// look at which different possible sets of toggles need to be pressed to result in the target number
|
val pq = LinkedList<Pair<Int, Int>>()
|
||||||
// pressing an even time will cancel out the effect, so only look what happens if you press once
|
val killArray = BooleanArray(1 shl m.size)
|
||||||
var minPresses = Int.MAX_VALUE
|
pq.add(0 to 0)
|
||||||
for (tm in 1 until (1 shl m.toggles.size)) {
|
out@ while (pq.isNotEmpty()) {
|
||||||
val odds = m.toggles.filterIndexed { i, v -> (1 shl i) and tm != 0 }
|
val (v, bi) = pq.poll()
|
||||||
val result = odds.fold(0) { acc, iv -> acc xor iv }
|
for (t in m.toggles) {
|
||||||
if (result == m.target) {
|
val nv = v xor t
|
||||||
minPresses = minPresses.coerceAtMost(odds.size)
|
if (nv == m.target) {
|
||||||
|
sumButts += bi + 1
|
||||||
|
break@out
|
||||||
|
}
|
||||||
|
if (!killArray[nv]) {
|
||||||
|
killArray[v] = true
|
||||||
|
pq.add(nv to bi + 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sumButts += minPresses
|
|
||||||
}
|
}
|
||||||
return sumButts
|
return sumButts
|
||||||
}
|
}
|
||||||
@ -94,69 +99,11 @@ 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(
|
Toggle(i,
|
||||||
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] })
|
||||||
}
|
}
|
||||||
@ -181,13 +128,19 @@ 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(jolts, t, times = t.min)) throw IllegalStateException()
|
if (pressCount[t.idx] + t.min > t.max || !applyJoltage(
|
||||||
|
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
|
||||||
@ -204,7 +157,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 = 1//findMaxButtonPresses(j, t)
|
val maxTimes = 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)) {
|
||||||
@ -231,7 +184,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()
|
||||||
|
|||||||
@ -1,111 +0,0 @@
|
|||||||
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()
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user