|
| 1 | +// https://adventofcode.com/2024/day/8 |
| 2 | + |
| 3 | +data class Point2(val x: Int, val y: Int) |
| 4 | + |
| 5 | +data class Antinodes(val xSize: Int, val ySize: Int) { |
| 6 | + |
| 7 | + val array = Array(ySize) { Array(xSize) { false } } |
| 8 | + |
| 9 | + fun isInBounds(x: Int, y: Int) = x in 0 until xSize && y in 0 until ySize |
| 10 | + |
| 11 | + operator fun get(x: Int, y: Int) = if (isInBounds(x, y)) array[y][x] else null |
| 12 | + operator fun set(x: Int, y: Int, field: Boolean) { |
| 13 | + if (isInBounds(x, y)) { |
| 14 | + array[y][x] = field |
| 15 | + } |
| 16 | + } |
| 17 | + |
| 18 | + fun count() = array.sumOf { it.count { it } } |
| 19 | + |
| 20 | + fun printArray() { |
| 21 | + for (y in array.indices) { |
| 22 | + for (x in array[y].indices) { |
| 23 | + print(if (get(x, y)!!) "#" else ".") |
| 24 | + } |
| 25 | + println("") |
| 26 | + } |
| 27 | + println("") |
| 28 | + } |
| 29 | +} |
| 30 | + |
| 31 | +data class Antenas(val xSize: Int, val ySize: Int) { |
| 32 | + |
| 33 | + val array = Array(ySize) { Array<Char?>(xSize) { null } } |
| 34 | + |
| 35 | + operator fun get(x: Int, y: Int) = if (isInBounds(x, y)) array[y][x] else null |
| 36 | + operator fun set(x: Int, y: Int, field: Char) { |
| 37 | + array[y][x] = field |
| 38 | + } |
| 39 | + |
| 40 | + fun getPoints(): Map<Char, List<Point>> { |
| 41 | + val map: MutableMap<Char, MutableSet<Point>> = mutableMapOf() |
| 42 | + for (y in array.indices) { |
| 43 | + for (x in array[y].indices) { |
| 44 | + get(x, y) |
| 45 | + ?.let { it.takeIf { it != '.' } } |
| 46 | + ?.let { map[it] = map.getOrDefault(it, mutableSetOf()).apply { add(Point(x, y)) } } |
| 47 | + } |
| 48 | + } |
| 49 | + return map.mapValues { it.value.toList() } |
| 50 | + } |
| 51 | + |
| 52 | + fun isInBounds(x: Int, y: Int) = x in 0 until xSize && y in 0 until ySize |
| 53 | + |
| 54 | + fun printArray() { |
| 55 | + for (y in array.indices) { |
| 56 | + for (x in array[y].indices) { |
| 57 | + print(array[y][x]) |
| 58 | + } |
| 59 | + println("") |
| 60 | + } |
| 61 | + println("") |
| 62 | + } |
| 63 | +} |
| 64 | + |
| 65 | +fun main() { |
| 66 | + |
| 67 | + fun part1(input: List<String>): Int { |
| 68 | + |
| 69 | + val antenas = Antenas(input[0].length, input.size) |
| 70 | + val antinodes = Antinodes(input[0].length, input.size) |
| 71 | + |
| 72 | + input.forEachIndexed { y, list -> |
| 73 | + list.forEachIndexed { x, char -> |
| 74 | + antenas[x, y] = char |
| 75 | + } |
| 76 | + } |
| 77 | + |
| 78 | + antenas.printArray() |
| 79 | + |
| 80 | + antenas.getPoints().forEach { (char, points) -> |
| 81 | + for (i in points.indices) { |
| 82 | + for (j in (i + 1) until points.size) { |
| 83 | + val dx = points[i].x - points[j].x |
| 84 | + val dy = points[i].y - points[j].y |
| 85 | + listOf( |
| 86 | + Point(points[i].x + dx, points[i].y + dy), |
| 87 | + Point(points[j].x - dx, points[j].y - dy) |
| 88 | + ).forEach { |
| 89 | + antinodes[it.x, it.y] = true |
| 90 | + } |
| 91 | + } |
| 92 | + } |
| 93 | + } |
| 94 | + |
| 95 | + antinodes.printArray() |
| 96 | + |
| 97 | + return antinodes.count() |
| 98 | + } |
| 99 | + |
| 100 | + fun part2(input: List<String>): Int { |
| 101 | + val antenas = Antenas(input[0].length, input.size) |
| 102 | + val antinodes = Antinodes(input[0].length, input.size) |
| 103 | + |
| 104 | + input.forEachIndexed { y, list -> |
| 105 | + list.forEachIndexed { x, char -> |
| 106 | + antenas[x, y] = char |
| 107 | + } |
| 108 | + } |
| 109 | + |
| 110 | + antenas.printArray() |
| 111 | + |
| 112 | + antenas.getPoints().forEach { (char, points) -> |
| 113 | + for (i in points.indices) { |
| 114 | + for (j in (i + 1) until points.size) { |
| 115 | + val dx = points[i].x - points[j].x |
| 116 | + val dy = points[i].y - points[j].y |
| 117 | + |
| 118 | + var newPoint = Point(points[i].x, points[i].y) |
| 119 | + while (antinodes.isInBounds(newPoint.x, newPoint.y)) { |
| 120 | + antinodes[newPoint.x, newPoint.y] = true |
| 121 | + newPoint = Point(newPoint.x + dx, newPoint.y + dy) |
| 122 | + } |
| 123 | + |
| 124 | + newPoint = Point(newPoint.x - dx, newPoint.y - dy) |
| 125 | + while (antinodes.isInBounds(newPoint.x, newPoint.y)) { |
| 126 | + antinodes[newPoint.x, newPoint.y] = true |
| 127 | + newPoint = Point(newPoint.x - dx, newPoint.y - dy) |
| 128 | + } |
| 129 | + } |
| 130 | + } |
| 131 | + } |
| 132 | + |
| 133 | + antinodes.printArray() |
| 134 | + |
| 135 | + return antinodes.count() |
| 136 | + } |
| 137 | + |
| 138 | + val testInput = readInput("Day08_test") |
| 139 | + val input = readInput("Day08") |
| 140 | + |
| 141 | + test(14) { part1(testInput) } |
| 142 | + exec { part1(input) } |
| 143 | + test(34) { part2(testInput) } |
| 144 | + exec { part2(input) } |
| 145 | +} |
0 commit comments