diff options
Diffstat (limited to 'aoc-2021-kotlin')
-rw-r--r-- | aoc-2021-kotlin/README.md | 6 | ||||
-rw-r--r-- | aoc-2021-kotlin/src/Day19.kt | 18 | ||||
-rw-r--r-- | aoc-2021-kotlin/src/Day22.kt | 90 | ||||
-rw-r--r-- | aoc-2021-kotlin/src/Utils.kt | 18 |
4 files changed, 111 insertions, 21 deletions
diff --git a/aoc-2021-kotlin/README.md b/aoc-2021-kotlin/README.md index 4d07eee..5a5e967 100644 --- a/aoc-2021-kotlin/README.md +++ b/aoc-2021-kotlin/README.md @@ -1,7 +1,7 @@ # Advent of Code 2021 in Kotlin  - - + + Welcome to the Advent of Code Kotlin project created by [tchojnacki][github] using the [Advent of Code Kotlin Template][template] delivered by JetBrains. @@ -31,7 +31,7 @@ Welcome to the Advent of Code Kotlin project created by [tchojnacki][github] usi | Day 19: Beacon Scanner | 🌟 | 🌟 | | Day 20: Trench Map | 🌟 | 🌟 | | Day 21: Dirac Dice | 🌟 | 🌟 | -| Day 22: Reactor Reboot | | | +| Day 22: Reactor Reboot | 🌟 | 🌟 | | Day 23: Amphipod | | | | Day 24: Arithmetic Logic Unit | 🌟 | 🌟 | | Day 25: Sea Cucumber | 🌟 | | diff --git a/aoc-2021-kotlin/src/Day19.kt b/aoc-2021-kotlin/src/Day19.kt index bcdabac..2092691 100644 --- a/aoc-2021-kotlin/src/Day19.kt +++ b/aoc-2021-kotlin/src/Day19.kt @@ -172,24 +172,6 @@ object Day19 { } } - private data class Pos3D(val x: Int, val y: Int, val z: Int) { - companion object { - val zero = Pos3D(0, 0, 0) - val unique = Pos3D(1, 2, 3) - - fun fromString(string: String) = string - .split(",") - .map(String::toInt) - .let { Pos3D(it[0], it[1], it[2]) } - } - - operator fun unaryMinus() = Pos3D(-x, -y, -z) - - operator fun plus(other: Pos3D) = Pos3D(x + other.x, y + other.y, z + other.z) - - operator fun minus(other: Pos3D) = Pos3D(x - other.x, y - other.y, z - other.z) - } - private class Graph(private val adjacencyList: List<Set<Edge>>) { data class Edge(val destination: Int, val transform: Transform) diff --git a/aoc-2021-kotlin/src/Day22.kt b/aoc-2021-kotlin/src/Day22.kt new file mode 100644 index 0000000..687011b --- /dev/null +++ b/aoc-2021-kotlin/src/Day22.kt @@ -0,0 +1,90 @@ +import java.lang.Integer.max +import java.lang.Integer.min + +object Day22 { + private val IntRange.width get() = last - first + 1 + + private infix fun IntRange.and(other: IntRange) = + if (last >= other.first && other.last >= first) + max(first, other.first)..min(last, other.last) + else + null + + data class Cuboid(val x: IntRange, val y: IntRange, val z: IntRange) { + val volume get() = x.width.toLong() * y.width.toLong() * z.width.toLong() + val cubes + get() = sequence { + x.forEach { xv -> y.forEach { yv -> z.forEach { zv -> yield(Pos3D(xv, yv, zv)) } } } + } + + infix fun and(other: Cuboid): Cuboid? { + val x = (x and other.x) ?: return null + val y = (y and other.y) ?: return null + val z = (z and other.z) ?: return null + return Cuboid(x, y, z) + } + + operator fun contains(pos: Pos3D) = pos.x in x && pos.y in y && pos.z in z + } + + data class RebootStep(val on: Boolean, val cuboid: Cuboid) { + companion object { + fun readSteps(input: List<String>) = input.asSequence().map { line -> + """(on|off) x=(-?\d+)..(-?\d+),y=(-?\d+)..(-?\d+),z=(-?\d+)..(-?\d+)""" + .toRegex() + .matchEntire(line) + ?.destructured + ?.let { (action, minX, maxX, minY, maxY, minZ, maxZ) -> + RebootStep( + when (action) { + "on" -> true + "off" -> false + else -> throw IllegalArgumentException() + }, + Cuboid( + minX.toInt()..maxX.toInt(), + minY.toInt()..maxY.toInt(), + minZ.toInt()..maxZ.toInt() + ) + ) + } ?: throw IllegalArgumentException() + } + } + } + + fun part1(input: List<String>) = RebootStep.readSteps(input).toList().let { steps -> + Cuboid(-50..50, -50..50, -50..50).cubes.sumOf { pos -> + if (steps.lastOrNull { pos in it.cuboid }?.on == true) 1L else 0L + } + } + + fun part2(input: List<String>): Long { + val counts = mutableMapOf<Cuboid, Int>() + + RebootStep.readSteps(input).forEach { step -> + val countChanges = mutableMapOf<Cuboid, Int>() + + for (key in counts.keys) { + val overlap = (step.cuboid and key) ?: continue + countChanges.putIfAbsent(overlap, 0) + countChanges.merge(overlap, counts[key]!!, Int::minus) + } + + if (step.on) countChanges.merge(step.cuboid, 1, Int::plus) + + countChanges.forEach { (key, value) -> counts.merge(key, value, Int::plus) } + } + + return counts.map { (cuboid, count) -> cuboid.volume * count }.sum() + } +} + +fun main() { + val testInput = readInputAsLines("Day22_test") + check(Day22.part1(testInput) == 474140L) + check(Day22.part2(testInput) == 2758514936282235L) + + val input = readInputAsLines("Day22") + println(Day22.part1(input)) + println(Day22.part2(input)) +} diff --git a/aoc-2021-kotlin/src/Utils.kt b/aoc-2021-kotlin/src/Utils.kt index 4f78a1f..2be34ac 100644 --- a/aoc-2021-kotlin/src/Utils.kt +++ b/aoc-2021-kotlin/src/Utils.kt @@ -26,6 +26,24 @@ data class Pos2D(val x: Int, val y: Int) { operator fun minus(other: Pos2D) = Pos2D(x - other.x, y - other.y) } +data class Pos3D(val x: Int, val y: Int, val z: Int) { + companion object { + val zero = Pos3D(0, 0, 0) + val unique = Pos3D(1, 2, 3) + + fun fromString(string: String) = string + .split(",") + .map(String::toInt) + .let { Pos3D(it[0], it[1], it[2]) } + } + + operator fun unaryMinus() = Pos3D(-x, -y, -z) + + operator fun plus(other: Pos3D) = Pos3D(x + other.x, y + other.y, z + other.z) + + operator fun minus(other: Pos3D) = Pos3D(x - other.x, y - other.y, z - other.z) +} + fun parseToMap(input: List<String>): Map<Pos2D, Int> = input.flatMapIndexed { y, line -> line.mapIndexed { x, char -> |