Compare commits

...
20 Commits
Author SHA1 Message Date
chrisly42 cda0dccc65 Day 12. Argh. 2025-12-15 21:29:08 +01:00
chrisly42 5e031c27cc WiP 2025-12-15 09:55:01 +01:00
chrisly42 de3b0795e3 Intermediate commit before I break stuff. 2025-12-11 15:30:13 +01:00
chrisly42 2190f9e1ac No need to have two different recursion functions for Day 11. Tidied up. 2025-12-11 08:00:08 +01:00
chrisly42 0192b33570 Day 10 still not working, but math will save me. 2025-12-11 07:25:11 +01:00
chrisly42 a69be406b1 Day 11. 2025-12-11 07:24:13 +01:00
chrisly42 7495f9e378 Still non-working part 2. But I have an idea. 2025-12-10 21:43:08 +01:00
chrisly42 ccc3fdad4c Restored deleted code from previous commit and used it to solve Part 1 much faster. 2025-12-10 18:44:40 +01:00
chrisly42 bd591263f6 Still not working, but stuff removed that was wrong. 2025-12-10 17:02:28 +01:00
chrisly42 4982f2cb3c Non working solution before I re-read the instructions regarding the light diagrams to be ignored for part 2. 2025-12-10 16:54:58 +01:00
chrisly42 6299b10b85 Day 10. Part 2 doesn't terminate in time and space yet. 2025-12-10 07:44:08 +01:00
Chris Hodges caf82dd7a9 Restored "clever" method for day 9. Not much faster, though.
Change-Id: I8ced811be7415db8281a13f1f8200192b05914e2
2025-12-09 13:06:28 +01:00
chrisly42 d2044f2d6a Day 9. Removed all smart code. 2025-12-09 08:36:22 +01:00
chrisly42 9a2a22805b Day 9. Tried to be smart, that was a failure. 2025-12-09 08:34:40 +01:00
chrisly42 909fb5c7d2 Day 8: Use long for result of part 2. X coords are > 16 bit. That it didn't overflow was pure chance. 2025-12-08 07:07:39 +01:00
chrisly42 52af74ecd5 Day 8: Use priority queue. 2025-12-08 07:04:34 +01:00
chrisly42 7a58627132 Day 8. 2025-12-08 06:58:11 +01:00
chrisly42 5fc0e8756a Day 7 :( 2025-12-07 07:41:53 +01:00
chrisly42 2b3549c84c Day 6. 2025-12-06 06:46:07 +01:00
chrisly42 128ffbb10f English... 2025-12-06 06:46:02 +01:00
10 changed files with 815 additions and 3 deletions
+101 -1
View File
@@ -1,4 +1,5 @@
import java.lang.Long.numberOfTrailingZeros
import java.math.BigInteger
import java.util.*
import kotlin.math.abs
import kotlin.math.min
@@ -187,7 +188,106 @@ fun gcdPositive(aIn: Long, bIn: Long): Long {
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>>()
var phi = 1L
var rem = n
+1 -1
View File
@@ -82,7 +82,7 @@ Prize: X=18641, Y=10279
// Linear Diophantine equations
/* 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.
The solutions are described by the following theorem:
This Diophantine equation has a solution (where x and y are integers),
+56
View File
@@ -0,0 +1,56 @@
package aoc2025
import println
import readInput
import splitLongs
/*
--- Day 6: Trash Compactor ---
https://adventofcode.com/2025/day/6
*/
fun main() {
val inlineTestInput = """
123 328 51 64
45 64 387 23
6 98 215 314
* + * +
"""
fun part1(input: List<String>): Long {
val numbers = input.dropLast(1).map { it.splitLongs().toLongArray() }.toList()
val ops = input.last().split(" ").filter(String::isNotBlank)
return ops.withIndex().sumOf { (c, op) -> if (op == "+") numbers.sumOf { it[c] } else numbers.fold(1L) { acc, row -> acc * row[c] } }
}
fun part2(input: List<String>): Long {
val numbers = ArrayList<LongArray>()
val maxLineLength = input.maxOf { it.length }
val spaceMask = BooleanArray(maxLineLength)
input.forEach { it.withIndex().filter { (_, ch) -> ch != ' ' }.forEach { (c, _) -> spaceMask[c] = true } }
val numColl = ArrayList<Long>()
for (c in 0 until maxLineLength) {
if (spaceMask[c]) numColl.add(input.dropLast(1).map { it[c] }.joinToString("").trim().toLong())
if (!spaceMask[c] || c == maxLineLength - 1) {
numbers.add(numColl.toLongArray())
numColl.clear()
}
}
return input.last().split(" ").filter(String::isNotBlank).withIndex()
.sumOf { (c, op) -> if (op == "+") numbers[c].sum() else numbers[c].fold(1L) { acc, row -> acc * row } }
}
// test if implementation meets criteria from the description, like:
val testInput = inlineTestInput.trim().reader().readLines()
//val testInput = readInput("aoc2025/Day06_test")
val testInputPart1Result = part1(testInput)
println("Part 1 Test: $testInputPart1Result")
val testInputPart2Result = part2(testInput)
println("Part 2 Test: $testInputPart2Result")
check(testInputPart1Result == 4277556L)
check(testInputPart2Result == 3263827L)
val input = readInput("aoc2025/Day06")
part1(input).println()
part2(input).println()
}
+84
View File
@@ -0,0 +1,84 @@
package aoc2025
import CharGrid
import println
import readInput
/*
--- Day 7: Laboratories ---
https://adventofcode.com/2025/day/7
*/
fun main() {
val inlineTestInput = """
.......S.......
...............
.......^.......
...............
......^.^......
...............
.....^.^.^.....
...............
....^.^...^....
...............
...^.^...^.^...
...............
..^...^.....^..
...............
.^.^.^.^.^...^.
...............
"""
val memo = ArrayList<HashMap<Int, Long>>()
fun part1(input: List<String>): Int {
val grid = CharGrid(input)
var splits = 0
for (row in 2 until grid.height step 2) {
for (col in 1 until grid.width - 1) {
val ch = grid[col, row - 2]
if (ch == 'S') {
if (grid[col, row] == '^') {
grid[col - 1, row] = 'S'
grid[col + 1, row] = 'S'
splits++
} else {
grid[col, row] = 'S'
}
}
}
}
return splits
}
fun rec(grid: CharGrid, col: Int, row: Int): Long {
if (row >= grid.height) return 1
return memo[row / 2].getOrPut(col) {
if (grid[col, row + 2] == '^')
rec(grid, col - 1, row + 2) + rec(grid, col + 1, row + 2)
else
rec(grid, col, row + 2)
}
}
fun part2(input: List<String>): Long {
val grid = CharGrid(input)
val col = grid.collectMatches { it == 'S' }.single().second.dc
while (memo.size <= grid.height / 2) memo.add(HashMap())
return rec(grid, col, 0)
}
// test if implementation meets criteria from the description, like:
val testInput = inlineTestInput.trim().reader().readLines()
//val testInput = readInput("aoc2025/Day07_test")
val testInputPart1Result = part1(testInput)
println("Part 1 Test: $testInputPart1Result")
val testInputPart2Result = part2(testInput)
println("Part 2 Test: $testInputPart2Result")
check(testInputPart1Result == 21)
check(testInputPart2Result == 40L)
val input = readInput("aoc2025/Day07")
part1(input).println()
part2(input).println()
}
+123
View File
@@ -0,0 +1,123 @@
package aoc2025
import println
import readInput
import splitInts
import java.util.*
import kotlin.math.sqrt
/*
--- Day 8: Playground ---
https://adventofcode.com/2025/day/8
*/
fun main() {
val inlineTestInput = """
162,817,812
57,618,57
906,360,560
592,479,940
352,342,300
466,668,158
542,29,236
431,825,988
739,650,466
52,470,668
216,146,977
819,987,18
117,168,530
805,96,715
346,949,466
970,615,88
941,993,340
862,61,35
984,92,344
425,690,689
"""
fun dist(n1: IntArray, n2: IntArray) =
sqrt(((n1[0] - n2[0]).toFloat() * (n1[0] - n2[0]) + (n1[1] - n2[1]).toFloat() * (n1[1] - n2[1]) + (n1[2] - n2[2]).toFloat() * (n1[2] - n2[2])))
fun find(parent: IntArray, n: Int): Int {
if (parent[n] != n) {
parent[n] = find(parent, parent[n])
}
return parent[n]
}
fun union(parent: IntArray, n1: Int, n2: Int): Boolean {
val r1 = find(parent, n1)
val r2 = find(parent, n2)
if (r1 != r2) {
parent[r1] = r2
return true
}
return false
}
// having an oct-tree might speed up things here, so we skip far distances
fun createDistances(nodes: Array<IntArray>): PriorityQueue<Pair<Pair<Int, Int>, Float>> {
val distances = PriorityQueue<Pair<Pair<Int, Int>, Float>>(nodes.size * nodes.size / 2, Comparator.comparing { it.second })
for (i1 in 0 until nodes.size) {
for (i2 in i1 + 1 until nodes.size) {
val d = dist(nodes[i1], nodes[i2])
distances.add((i1 to i2) to d)
}
}
return distances
}
fun part1(input: List<String>, numConnections: Int): Long {
val nodes = input.map { it.splitInts(",").toIntArray() }.toTypedArray()
val distances = createDistances(nodes)
val n = nodes.size
var numCircuits = 0
val unionFindParentArray = IntArray(n) { it }
while (distances.isNotEmpty()) {
val (n1, n2) = distances.remove().first
union(unionFindParentArray, n1, n2)
numCircuits++
if (numCircuits == numConnections) break
}
val circuitSizes = LongArray(n)
for (i in 0 until n) {
circuitSizes[find(unionFindParentArray, i)]++
}
return circuitSizes.sortedDescending().take(3).fold(1L) { acc, l -> acc * l }
}
fun part2(input: List<String>): Long {
val nodes = input.map { it.splitInts(",").toIntArray() }.toTypedArray()
val distances = createDistances(nodes)
val n = nodes.size
var numCircuits = 1
val unionFindParentArray = IntArray(n) { it }
while (distances.isNotEmpty()) {
val (n1, n2) = distances.remove().first
if (union(unionFindParentArray, n1, n2)) {
numCircuits++
if (numCircuits == n) {
return nodes[n1][0].toLong() * nodes[n2][0]
}
}
}
return -1L
}
// test if implementation meets criteria from the description, like:
val testInput = inlineTestInput.trim().reader().readLines()
//val testInput = readInput("aoc2025/Day08_test")
val testInputPart1Result = part1(testInput, 10)
println("Part 1 Test: $testInputPart1Result")
val testInputPart2Result = part2(testInput)
println("Part 2 Test: $testInputPart2Result")
check(testInputPart1Result == 40L)
check(testInputPart2Result == 25272L)
val input = readInput("aoc2025/Day08")
part1(input, 1000).println()
part2(input).println()
}
+91
View File
@@ -0,0 +1,91 @@
package aoc2025
import println
import readInput
import splitInts
import java.util.*
import kotlin.math.abs
/*
--- Day 9: Movie Theater ---
https://adventofcode.com/2025/day/9
*/
fun main() {
val inlineTestInput = """
7,1
11,1
11,7
9,7
9,5
2,5
2,3
7,3
"""
fun part1(input: List<String>): Long {
val coords = input.map { it.splitInts(",") }
var maxArea = 0L
for (i1 in 0 until coords.size step 2) {
for (i2 in i1 + 2 until coords.size step 2) {
maxArea =
((abs(coords[i1][0] - coords[i2][0]) + 1).toLong() * (abs(coords[i1][1] - coords[i2][1]) + 1).toLong()).coerceAtLeast(
maxArea
)
}
}
return maxArea
}
fun intersectsRanges(set: TreeMap<Int, ArrayList<IntRange>>, x1: Int, y1: Int, x2: Int, y2: Int) =
set.subMap(y1 + 1, y2).values.any { it.any { it.first < x2 && it.last > x1 } }
fun part2(input: List<String>): Long {
val coords = input.map { it.splitInts(",") }
val xSpans = TreeMap<Int, ArrayList<IntRange>>()
val ySpans = TreeMap<Int, ArrayList<IntRange>>()
for (i1 in 0 until coords.size) {
val i2 = if (i1 != coords.size - 1) i1 + 1 else 0
if (coords[i1][1] == coords[i2][1]) {
xSpans.getOrPut(coords[i1][1]) { ArrayList<IntRange>() }.add(
IntRange(coords[i1][0].coerceAtMost(coords[i2][0]), coords[i1][0].coerceAtLeast(coords[i2][0]))
)
} else {
ySpans.getOrPut(coords[i1][0]) { ArrayList<IntRange>() }.add(
IntRange(coords[i1][1].coerceAtMost(coords[i2][1]), coords[i1][1].coerceAtLeast(coords[i2][1]))
)
}
}
var maxArea = 0L
for (i1 in 0 until coords.size step 2) {
for (i2 in i1 + 2 until coords.size step 2) {
val x1 = coords[i1][0].coerceAtMost(coords[i2][0])
val x2 = coords[i1][0].coerceAtLeast(coords[i2][0])
val y1 = coords[i1][1].coerceAtMost(coords[i2][1])
val y2 = coords[i1][1].coerceAtLeast(coords[i2][1])
val area = ((x2 - x1 + 1).toLong() * (y2 - y1 + 1).toLong())
if (area > maxArea &&
!(intersectsRanges(xSpans, x1, y1, x2, y2) || intersectsRanges(ySpans, y1, x1, y2, x2))
) {
maxArea = area
}
}
}
return maxArea
}
// test if implementation meets criteria from the description, like:
val testInput = inlineTestInput.trim().reader().readLines()
//val testInput = readInput("aoc2025/Day09_test")
val testInputPart1Result = part1(testInput)
println("Part 1 Test: $testInputPart1Result")
val testInputPart2Result = part2(testInput)
println("Part 2 Test: $testInputPart2Result")
check(testInputPart1Result == 50L)
check(testInputPart2Result == 24L)
val input = readInput("aoc2025/Day09")
part1(input).println()
part2(input).println()
}
+134
View File
@@ -0,0 +1,134 @@
package aoc2025
import chineseRemainder
import extendedGcdBigInteger
import primeFactors
import primeSequence
import println
import readInput
import sieveOfErastosthenes
import splitInts
import java.math.BigInteger
/*
--- Day 10: Factory ---
https://adventofcode.com/2025/day/10
*/
fun main() {
val inlineTestInput = """
[.##.] (3) (1,3) (2) (2,3) (0,2) (0,1) {3,5,4,7}
[...#.] (0,2,3,4) (2,3) (0,4) (0,1,2) (1,2,3,4) {7,5,12,7,2}
[.###.#] (0,1,2,3,4) (0,3,4) (0,1,2,4,5) (1,2) {10,11,11,5,10,5}
"""
data class Machine(val size: Int, val target: Int, val toggles: IntArray, val joltage: IntArray)
fun parse(input: List<String>): ArrayList<Machine> {
val machines = ArrayList<Machine>()
for (i in input) {
val stuff = i.split(" ")
val machSize = stuff[0].length - 2
val target = stuff[0].removeSurrounding("[", "]")
.foldIndexed(0) { i, acc, ch -> acc + if (ch == '#') (1 shl i) else 0 }
val toggles =
stuff.drop(1).dropLast(1)
.map { it.removeSurrounding("(", ")").splitInts(",").fold(0) { acc, v -> acc + (1 shl v) } }
.toIntArray()
val joltages = stuff.last().removeSurrounding("{", "}").splitInts(",").toIntArray()
machines.add(Machine(machSize, target, toggles, joltages))
}
return machines
}
fun part1(input: List<String>): Int {
val machines = parse(input)
var sumButts = 0
for (m in machines) {
// look at which different possible sets of toggles need to be pressed to result in the target number
// pressing an even time will cancel out the effect, so only look what happens if you press once
var minPresses = Int.MAX_VALUE
for (tm in 1 until (1 shl m.toggles.size)) {
val odds = m.toggles.filterIndexed { i, v -> (1 shl i) and tm != 0 }
val result = odds.fold(0) { acc, iv -> acc xor iv }
if (result == m.target) {
minPresses = minPresses.coerceAtMost(odds.size)
}
}
sumButts += minPresses
}
return sumButts
}
fun part2(input: List<String>): Int {
val machines = parse(input)
val sieve = sieveOfErastosthenes(10000)
val primes = primeSequence(sieve).take(500).toList()
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<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 += BigInteger.ONE.shiftLeft(shift)
}
shift += numBits
tt = tt shr 1
}
bigToggles.add(bigToggle)
}
// j0 * bigtoggle[0] + j1 * bigtoggle[1] + ... = bigTarget
// is a Linear Diophantine equation that can be solved with the extended Euclidean algorithm
val (gcd, coeffients) = extendedGcdBigInteger(bigToggles)
if (bigTarget % gcd != BigInteger.ZERO) throw IllegalStateException()
val factorMap = HashMap<Long, Long>()
var good = true
val primeFactors = primeFactors(bigTarget.toLong(), sieve)
for (pf in primeFactors) {
val sf = factorMap[pf]
val pr = 1000 % pf
if (sf != null && sf != pr) {
good = false
break
}
factorMap[pf] = pr
}
val reducedPairs = factorMap.map { it.value to it.key }.sortedBy { it.second }
val rx = reducedPairs.chineseRemainder()
val leastFingers = 0
println(leastFingers)
sumButts += leastFingers
}
return sumButts
}
// test if implementation meets criteria from the description, like:
val testInput = inlineTestInput.trim().reader().readLines()
//val testInput = readInput("aoc2025/Day10_test")
val testInputPart1Result = part1(testInput)
println("Part 1 Test: $testInputPart1Result")
val testInputPart2Result = part2(testInput)
println("Part 2 Test: $testInputPart2Result")
check(testInputPart1Result == 7)
//check(testInputPart2Result == 33)
val input = readInput("aoc2025/Day10")
part1(input).println()
part2(input).println()
}
+98
View File
@@ -0,0 +1,98 @@
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
"""
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 rec(
children: HashMap<String, MutableSet<String>>,
p: String,
stop: String,
visited: MutableSet<String> = HashSet(),
memo: HashMap<String, Long> = HashMap()
): Long {
if (p == stop) return 1L
return memo.getOrPut(p) {
visited.add(p)
val res = children[p]?.sumOf { rec(children, it, stop, visited, memo) } ?: 0L
visited.remove(p)
res
}
}
fun part1(input: List<String>): Long {
return rec(parseInput(input), "you", "out")
}
fun part2(input: List<String>): Long {
val children = parseInput(input)
val srvToDac = rec(children, "svr", "dac")
val dacToFft = rec(children, "dac", "fft")
val fftToOut = rec(children, "fft", "out")
val srvToFft = rec(children, "svr", "fft")
val fftToDac = rec(children, "fft", "dac")
val dacToOut = rec(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 == 5L)
check(testInputPart2Result == 2L)
val input = readInput("aoc2025/Day11")
part1(input).println()
part2(input).println()
}
+126
View File
@@ -0,0 +1,126 @@
package aoc2025
import CharGrid
import println
import readInput
import splitInts
/*
--- Day 12: Christmas Tree Farm ---
https://adventofcode.com/2025/day/12
*/
fun main() {
val inlineTestInput = """
0:
###
##.
##.
1:
###
##.
.##
2:
.##
###
##.
3:
##.
###
##.
4:
###
#..
###
5:
###
.#.
###
4x4: 0 0 0 0 2 0
12x5: 1 0 1 0 2 2
12x5: 1 0 1 0 3 2
"""
fun fits(grid: LongArray, x: Int, y: Int, present: Long) =
(grid[y] or ((7L and present) shl x) == grid[y]) &&
(grid[y + 1] or ((7L and (present shr 3)) shl x) == grid[y + 1]) &&
(grid[y + 2] or ((7L and (present shr 6)) shl x) == grid[y + 2])
fun part1(input: List<String>): Int {
var lp = 0
val presents = ArrayList<IntArray>()
// nothing of this stuff is needed :-(
while (!input[lp].contains("x")) {
var charGrid = CharGrid(input.subList(lp + 1, lp + 4))
lp += 5
val setRot = HashSet<Int>()
for (r in 0..7) {
val present = charGrid.generateGridPos().foldIndexed(0) { index, acc, pos -> acc + (if (charGrid[pos] == '#') (1 shl index) else 0) }
setRot.add(present)
if (r != 3) {
// rotate
val newGrid = charGrid.copyOf()
newGrid.generateGridPos().forEach { (dc, dr) -> newGrid[2 - dr, dc] = charGrid[dc, dr] }
charGrid = newGrid
} else {
// flip
val newGrid = charGrid.copyOf()
newGrid.generateGridPos().forEach { (dc, dr) -> newGrid[2 - dc, dr] = charGrid[dc, dr] }
charGrid = newGrid
}
}
presents.add(setRot.toIntArray())
}
var fitted = 0
val presentSizes = presents.map { it[0].countOneBits() }.toIntArray()
for (p in lp until input.size) {
val (dim, pl) = input[p].split(": ")
val (width, height) = dim.splitInts("x")
val placements = pl.splitInts().toIntArray()
val totalSize = placements.mapIndexed { i, v -> v * presentSizes[i] }.sum()
if (totalSize > width * height) {
continue
}
val totalPresents = placements.sum()
// just assume it will fit if there is enough area
if (totalPresents * 9 <= width * height) {
fitted++
continue
}
println("Oh no!")
// here the hard part would have started, but except for the example input,
// it never gets here
//val grid = LongArray(height) { (1L shl width) - 1L }
}
return fitted
}
fun part2(input: List<String>): Int {
return 0
}
// test if implementation meets criteria from the description, like:
val testInput = inlineTestInput.trim().reader().readLines()
//val testInput = readInput("aoc2025/Day12_test")
val testInputPart1Result = part1(testInput)
println("Part 1 Test: $testInputPart1Result")
val testInputPart2Result = part2(testInput)
println("Part 2 Test: $testInputPart2Result")
//check(testInputPart1Result == 2)
check(testInputPart2Result == 0)
val input = readInput("aoc2025/Day12")
part1(input).println()
part2(input).println()
}
+1 -1
View File
@@ -69,7 +69,7 @@ class Downloader(val year: Int, val packageName: String, val sessionCookie: Stri
break
}
while (day == lastDay && LocalTime.now(ZoneId.of("UTC+1")).hour == 5) {
println("Waiting until puzzle is available...")
println("Waiting for puzzle to become available...")
runBlocking {
if (LocalTime.now(ZoneId.of("UTC+1")).minute < 59) {
delay(1.minutes)