|
| 1 | +package y24 |
| 2 | + |
| 3 | +import common.puzzle.solvePuzzle |
| 4 | +import common.puzzle.Input |
| 5 | +import common.puzzle.Puzzle |
| 6 | +import common.datastructures.* |
| 7 | +import common.ext.* |
| 8 | +import common.util.* |
| 9 | +import java.util.* |
| 10 | +import kotlin.math.* |
| 11 | +import kotlin.system.exitProcess |
| 12 | + |
| 13 | + |
| 14 | +fun main() = solvePuzzle(year = 2024, day = 8) { Day8(it) } |
| 15 | + |
| 16 | +class Day8(val input: Input) : Puzzle { |
| 17 | + |
| 18 | + data class Antenna(val c: Char, val p: Point) |
| 19 | + |
| 20 | + data class CityMap( |
| 21 | + val antennas: Map<Char, List<Antenna>>, |
| 22 | + val rows: Int, |
| 23 | + val cols: Int, |
| 24 | + ) |
| 25 | + |
| 26 | + private fun parseInput(lines: List<String>): CityMap { |
| 27 | + val antennas = mutableListOf<Antenna>() |
| 28 | + input.lines.forEachIndexed { row, line -> |
| 29 | + line.forEachIndexed { col, c -> |
| 30 | + if (c != '.') { |
| 31 | + antennas += Antenna(c, Point(col, row)) |
| 32 | + } |
| 33 | + } |
| 34 | + } |
| 35 | + |
| 36 | + val grouped = antennas.groupBy { it.c } |
| 37 | + return CityMap(grouped, lines.size, lines[0].length) |
| 38 | + } |
| 39 | + |
| 40 | + fun antiNodes(a1: Point, a2: Point, rows: Int, cols: Int, onlyOne: Boolean): List<Point> { |
| 41 | + val delta = a2 - a1 |
| 42 | + fun computeForPoint(p: Point, delta: Point): List<Point> { |
| 43 | + val result = mutableListOf<Point>() |
| 44 | + var i = if (onlyOne) 1 else 0 |
| 45 | + while (true) { |
| 46 | + val node = p + (delta * i) |
| 47 | + if (!node.inBounds(rows, cols)) { |
| 48 | + return result |
| 49 | + } |
| 50 | + |
| 51 | + result += node |
| 52 | + i++ |
| 53 | + |
| 54 | + if (onlyOne) { |
| 55 | + return result |
| 56 | + } |
| 57 | + } |
| 58 | + } |
| 59 | + |
| 60 | + return computeForPoint(a1, delta * -1) + computeForPoint(a2, delta) |
| 61 | + } |
| 62 | + |
| 63 | + fun allAntiNodes(map: CityMap, onlyOne: Boolean): Set<Point> { |
| 64 | + val antiNodes = mutableSetOf<Point>() |
| 65 | + map.antennas.values.forEach { group -> |
| 66 | + for (i in group.indices) { |
| 67 | + for (j in i + 1 until group.size) { |
| 68 | + antiNodes += antiNodes(group[i].p, group[j].p, map.rows, map.cols, onlyOne) |
| 69 | + } |
| 70 | + } |
| 71 | + } |
| 72 | + return antiNodes |
| 73 | + } |
| 74 | + |
| 75 | + override fun solveLevel1(): Any { |
| 76 | + val map = parseInput(input.lines) |
| 77 | + return allAntiNodes(map, onlyOne = true).size |
| 78 | + } |
| 79 | + |
| 80 | + override fun solveLevel2(): Any { |
| 81 | + val map = parseInput(input.lines) |
| 82 | + return allAntiNodes(map, onlyOne = false).size |
| 83 | + } |
| 84 | +} |
0 commit comments