Skip to content

Commit 2bec635

Browse files
committed
Day 08 part 1.
1 parent 65a301c commit 2bec635

File tree

4 files changed

+209
-1
lines changed

4 files changed

+209
-1
lines changed

src/main/kotlin/day08/day08.kt

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// Advent of Code 2024, Day 08.
2+
// By Sebastian Raaphorst, 2024.
3+
4+
package day08
5+
6+
import common.day
7+
import common.readInput
8+
9+
typealias Frequency = Char
10+
typealias Position = Pair<Int, Int>
11+
typealias AntennaMap = Map<Frequency, Set<Position>>
12+
13+
private operator fun Position.minus(other: Position): Position =
14+
Position(this.first - other.first, this.second - other.second)
15+
16+
private operator fun Position.plus(other: Position): Position =
17+
Position(this.first + other.first, this.second + other.second)
18+
19+
data class Grid(val height: Int, val width: Int, val antennae: AntennaMap) {
20+
/**
21+
* Calculate the slope of the line that the points are on, namely:
22+
* pos1 - pos2
23+
* Then pos1 = pos2 + delta, and pos2 = pos1 - delta, so we want the
24+
* other two candidates, namely:
25+
* 1. pos1 + delta
26+
* 2. pos2 - delta
27+
* and if they are in the grid, then they contribute.
28+
*/
29+
private fun calculateAntinodePair(pos1: Position, pos2: Position): List<Position> {
30+
val delta = pos1 - pos2
31+
return listOf(pos1 + delta, pos2 - delta)
32+
.filter { (row, col) -> row in (0 until height) && col in (0 until width) }
33+
.also { it.forEach { t -> println("For $pos1 + $pos2 -> $t") }}
34+
}
35+
36+
/**
37+
* Calculate the slope of the line that the antinodes are on, namely
38+
* pos1 - pos2
39+
* and then continue to calculate all possible other candidates (including themselves).
40+
*/
41+
private fun calculateAllAntinodes(pos1: Position, pos2: Position): Set<Position> {
42+
val delta = pos1 - pos2
43+
tailrec fun aux(newAntinodes: Set<Position> = setOf(pos1, pos2),
44+
antinodes: Set<Position> = emptySet()): Set<Position> = when {
45+
newAntinodes.isEmpty() -> antinodes
46+
else -> {
47+
val possibleNewAntinodes = newAntinodes.flatMap { listOf(it + delta, it - delta) }
48+
.toSet()
49+
.filter { (row, col) -> row in (0 until height) && col in (0 until width) }
50+
.toSet()
51+
aux(possibleNewAntinodes, antinodes + newAntinodes)
52+
}
53+
}
54+
return aux()
55+
}
56+
57+
/**
58+
* For a given set of positions corresponding to a frequency, calculate
59+
* the set of generated antinodes.
60+
*/
61+
private fun calculateAntinodesForFrequency(positions: Set<Position>): Set<Position> =
62+
positions.withIndex()
63+
.flatMap { (idx, pos1) -> positions.drop(idx + 1)
64+
.flatMap { pos2 ->
65+
calculateAntinodePair(pos1, pos2)
66+
}
67+
}.toSet()
68+
69+
private fun calculateAntinodesForFrequency2(positions: Set<Position>): Set<Position> =
70+
positions.withIndex()
71+
.flatMap { (idx, pos1) -> positions.drop(idx + 1)
72+
.flatMap { pos2 ->
73+
calculateAllAntinodes(pos1, pos2)
74+
}
75+
}.toSet()
76+
77+
fun calculateAntinodeCount(): Int =
78+
antennae.values
79+
.flatMap(::calculateAntinodesForFrequency)
80+
.toSet()
81+
.size
82+
83+
fun calculateAntinodeCount2() : Int =
84+
antennae.values
85+
.flatMap(::calculateAntinodesForFrequency2)
86+
.toSet()
87+
.size
88+
89+
companion object {
90+
private fun parseMap(input: String): AntennaMap =
91+
input.lines()
92+
.withIndex()
93+
.flatMap { (rowIdx, row) ->
94+
row.withIndex()
95+
.filter { (_, frequency) -> frequency != '.' }
96+
.map { (colIdx, frequency) -> frequency to Pair(rowIdx, colIdx) }
97+
}.groupBy({ it.first }, { it.second })
98+
.mapValues { (_, positions) -> positions.toSet() }
99+
100+
fun parse(input: String) =
101+
Grid(input.lines().size, input.lines().get(0).length, parseMap(input))
102+
}
103+
}
104+
105+
fun answer1(input: String): Int =
106+
Grid.parse(input).calculateAntinodeCount()
107+
108+
fun answer2(input: String): Int =
109+
Grid.parse(input).calculateAntinodeCount2()
110+
111+
112+
fun main() {
113+
val input = readInput({}::class.day()).trim()
114+
115+
println("--- Day 8: Resonant Collinearity ---")
116+
117+
// Part 1: 376
118+
println("Part 1: ${answer1(input)}")
119+
120+
// Part 2:
121+
// println("Part 2: ${answer2(input)}")
122+
}

src/main/resources/day08.txt

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
..F..........L............5.......................
2+
............................L.U...................
3+
..................................................
4+
.............z.L.........5.....4........8....1.P..
5+
...F................D..4.8.............P......J...
6+
......f................8....z........U..J.........
7+
.......D..f........B..o.........m..........JX.....
8+
......o...5........F..........m.......6....X......
9+
....s........f...n.....54.U....E................3.
10+
....F.......l.......k..............6.3n...........
11+
L..........z....7..U............E...k.P..3b.......
12+
..s.......D..........h...k.....G........y..m......
13+
d..............o.........X............8...n.......
14+
...........o.......D.......J......................
15+
....................z.....1.9....G6..Y.b....y.....
16+
.d................4.........EN..G.9.b.............
17+
.......................7..........................
18+
..d................l.........pc..n................
19+
..............l........1Nm..........G..9..........
20+
.f.........s...7........1........E........X....y..
21+
.............d...................6......v.........
22+
........................h.............B...........
23+
.......l.......................h........B.....p..y
24+
........w......A................................M.
25+
.....s.................O...........p.......2......
26+
...............9.........................B.b......
27+
......................w..0..............H.........
28+
.....................w7.j..O....................e.
29+
.A......Z...................K...h...M.............
30+
.................S....KZ..........................
31+
.................V..............x.................
32+
......Z...............................N...........
33+
.......................a..........................
34+
....A..........................K.................M
35+
.......Z..................ON.KT.........c.........
36+
...........................YO....t.......x........
37+
..............g........w.T.............k...c......
38+
..........................v.......................
39+
....S..................................u..........
40+
..........0............v...............c...e..C.p.
41+
.......S............V.j........v.......x..........
42+
......S..0W.......HT....a.........................
43+
A..............H...W..a......C....................
44+
................T.2.....V......H..t...u........C..
45+
.................g.j....2.........u..t...e......C.
46+
.........W...........g.......................u....
47+
........W...0.................Y.........e.tM......
48+
................g..a.j............................
49+
..................................................
50+
.................2........Y...........x...........

src/test/kotlin/day07/day07.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import org.junit.jupiter.api.Test
77
import java.math.BigInteger
88
import kotlin.test.assertEquals
99

10-
class Day06Test {
10+
class Day07Test {
1111
private companion object {
1212
private val input =
1313
"""

src/test/kotlin/day08/day08.kt

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Advent of Code 2024, Day 08.
2+
// By Sebastian Raaphorst, 2024.
3+
4+
package day08
5+
6+
import org.junit.jupiter.api.Test
7+
import java.math.BigInteger
8+
import kotlin.test.assertEquals
9+
10+
class Day08Test {
11+
private companion object {
12+
val input =
13+
"""
14+
............
15+
........0...
16+
.....0......
17+
.......0....
18+
....0.......
19+
......A.....
20+
............
21+
............
22+
........A...
23+
.........A..
24+
............
25+
............
26+
""".trimIndent().trim()
27+
}
28+
29+
@Test
30+
fun `Problem 1 example`() =
31+
assertEquals(14, answer1(input))
32+
33+
@Test
34+
fun `Problem 2 example`() =
35+
assertEquals(34, answer2(input))
36+
}

0 commit comments

Comments
 (0)