diff --git a/src/aoc2025/Day09.kt b/src/aoc2025/Day09.kt new file mode 100644 index 0000000..2763135 --- /dev/null +++ b/src/aoc2025/Day09.kt @@ -0,0 +1,133 @@ +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,3 +7,1 +11,1 +11,7 +9,7 +9,5 +2,5 +2,3 +""" + + fun part1(input: List): 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 findRanges(set: TreeMap>, x1: Int, y1: Int, x2: Int, y2: Int): Boolean { + var it = set.ceilingEntry(y1) + while (it != null && it.key <= y2) { + val xRanges = it.value.filter { it.first() >= x1 && it.last() <= x2 } + if (it.key != y1 && it.key != y2 && xRanges.size > 0) return false + if ((it.key == y1 || it.key == y2) && xRanges.size > 1) return false + // Java TreeMap is crap -- I would like to iterate from first entry to last + it = set.ceilingEntry(it.key + 1) + } + return true + } + + fun intersects(coords: List>, x1: Int, y1: Int, x2: Int, y2: Int): Boolean { + for (z1 in 0 until coords.size) { + val z2 = if (z1 != coords.size - 1) z1 + 1 else 0 + if (coords[z1][0] == coords[z2][0]) { + // vertical + val miny = coords[z1][1].coerceAtMost(coords[z2][1]) + val maxy = coords[z1][1].coerceAtLeast(coords[z2][1]) + if (coords[z1][0] > x1 && coords[z1][0] < x2 && + (miny.coerceAtLeast(y1) < maxy.coerceAtMost(y2)) + ) + return true + } else { + // horizontal + val minx = coords[z1][0].coerceAtMost(coords[z2][0]) + val maxx = coords[z1][0].coerceAtLeast(coords[z2][0]) + if (coords[z1][1] > y1 && coords[z1][1] < y2 && + (minx.coerceAtLeast(x1) < maxx.coerceAtMost(x2)) + ) + return true + } + } + return false + } + + fun part2(input: List): Long { + val coords = input.map { it.splitInts(",") } + val xSpans = TreeMap>() + val ySpans = TreeMap>() + for (i1 in 0 until coords.size) { + val i2 = if (i1 != coords.size - 1) i1 + 1 else 0 + if (i1 and 1 == 1) { + xSpans.getOrPut(coords[i1][1]) { ArrayList() }.add( + IntRange( + coords[i1][0].coerceAtMost(coords[i2][0]), + coords[i1][0].coerceAtLeast(coords[i2][0]) + ) + ) + } else { + ySpans.getOrPut(coords[i1][0]) { ArrayList() }.add( + IntRange( + coords[i1][1].coerceAtMost(coords[i2][1]), + coords[i1][1].coerceAtLeast(coords[i2][1]) + ) + ) + } + } + + //xSpans.values.forEach { it.sortBy { it.first } } + //ySpans.values.forEach { it.sortBy { it.first } } + + var maxArea = 0L + for (i1 in 0 until coords.size step 1) { + for (i2 in i1 + 1 until coords.size step 1) { + 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]) + if (x1 == x2 || y1 == y2) continue + + val area = ((x2 - x1 + 1).toLong() * (y2 - y1 + 1).toLong()) + if (area > maxArea) { +// if (!findRanges(xSpans, x1, y1, x2, y2) || +// !findRanges(ySpans, y1, x1, y2, x2) +// ) continue + if (!intersects(coords, x1, y1, x2, y2)) + 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() +}