Skip to content

Commit 28c79e2

Browse files
committed
Day 8
1 parent e02947c commit 28c79e2

File tree

3 files changed

+123
-0
lines changed

3 files changed

+123
-0
lines changed

src/main/kotlin/common/datastructures/Point.kt

+5
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ data class Point(val col: Int, val row: Int) {
1717

1818
operator fun plus(other: Point) = Point(col + other.col, row + other.row)
1919
operator fun minus(other: Point) = Point(col - other.col, row - other.row)
20+
operator fun times(n: Int) = Point(col * n, row * n)
2021

2122
fun manhattanDistTo(other: Point) = abs(x - other.x) + abs(y - other.y)
23+
24+
fun inBounds(numRows: Int, numCols: Int): Boolean {
25+
return x in 0..<numCols && y in 0..<numRows
26+
}
2227
}

src/main/kotlin/y24/Day8.kt

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
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+
}

src/test/kotlin/y24/Day8Test.kt

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package y24
2+
3+
import common.puzzle.Input
4+
import org.junit.jupiter.api.Assertions.assertEquals
5+
import org.junit.jupiter.api.Test
6+
7+
internal class Day8Test {
8+
private val sample = Input("""
9+
............
10+
........0...
11+
.....0......
12+
.......0....
13+
....0.......
14+
......A.....
15+
............
16+
............
17+
........A...
18+
.........A..
19+
............
20+
............
21+
""".trimIndent())
22+
23+
private val day = Day8(sample)
24+
25+
@Test
26+
fun solveLevel1() {
27+
assertEquals(14, day.solveLevel1())
28+
}
29+
30+
@Test
31+
fun solveLevel2() {
32+
assertEquals(34, day.solveLevel2())
33+
}
34+
}

0 commit comments

Comments
 (0)