Skip to content

Commit 6da6572

Browse files
committed
Solution 2018-10 (The Stars Align)
1 parent 5814229 commit 6da6572

File tree

2 files changed

+195
-0
lines changed

2 files changed

+195
-0
lines changed
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package de.ronny_h.aoc.year2018.day10
2+
3+
import de.ronny_h.aoc.AdventOfCode
4+
import de.ronny_h.aoc.extensions.grids.Coordinates
5+
6+
// the text of part one: GFANEHKJ
7+
fun main() = TheStarsAlign().run(10086, 10086)
8+
9+
class TheStarsAlign : AdventOfCode<Int>(2018, 10) {
10+
override fun part1(input: List<String>): Int {
11+
val starAlignmentGrid = StarAlignmentGrid.of(input)
12+
val iterations = starAlignmentGrid.moveUntilMessageIsClear()
13+
starAlignmentGrid.printStars()
14+
return iterations
15+
}
16+
17+
override fun part2(input: List<String>): Int {
18+
return part1(input)
19+
}
20+
}
21+
22+
data class Star(val position: Coordinates, val velocity: Coordinates)
23+
24+
class StarAlignmentGrid(initStars: List<Star>) {
25+
var stars: List<Star>
26+
private set
27+
28+
init {
29+
stars = initStars
30+
}
31+
32+
fun move(): StarAlignmentGrid {
33+
stars = stars.map { Star(it.position + it.velocity, it.velocity) }
34+
return this
35+
}
36+
37+
fun moveUntilMessageIsClear(): Int {
38+
var count = 0
39+
do {
40+
move()
41+
count++
42+
} while (!aMessageCanBeSeen())
43+
return count
44+
}
45+
46+
fun printStars() {
47+
val (min, max) = findBorders()
48+
for (row in min.row..max.row) {
49+
for (col in min.col..max.col) {
50+
if (Coordinates(row, col) in starPositions()) {
51+
print('#')
52+
} else {
53+
print(' ')
54+
}
55+
}
56+
println()
57+
}
58+
}
59+
60+
private fun starPositions(): Set<Coordinates> = stars.map { it.position }.toSet()
61+
62+
private fun aMessageCanBeSeen(): Boolean {
63+
val (min, max) = findBorders()
64+
if (max.row - min.row > 50 || max.col - min.col > 100) {
65+
// if the stars are too far away from each other, we don't need to check
66+
return false
67+
}
68+
// a message can be seen if there are at least 5 stars are in a row AND 7 stars in a column
69+
return hasAtLeastStarsInSequence(7, coordinatesColumnWise(min, max))
70+
&& hasAtLeastStarsInSequence(5, coordinatesRowWise(min, max))
71+
}
72+
73+
private fun hasAtLeastStarsInSequence(minInSequence: Int, sequence: Sequence<Coordinates>): Boolean {
74+
var count = 0
75+
sequence.forEach {
76+
if (it in starPositions()) {
77+
count++
78+
if (count >= minInSequence) {
79+
return true
80+
}
81+
} else {
82+
count = 0
83+
}
84+
}
85+
return false
86+
}
87+
88+
private fun coordinatesColumnWise(min: Coordinates, max: Coordinates) = sequence {
89+
for (col in min.col..max.col) {
90+
for (row in min.row..max.row) {
91+
yield(Coordinates(row, col))
92+
}
93+
}
94+
}
95+
96+
private fun coordinatesRowWise(min: Coordinates, max: Coordinates) = sequence {
97+
for (row in min.row..max.row) {
98+
for (col in min.col..max.col) {
99+
yield(Coordinates(row, col))
100+
}
101+
}
102+
}
103+
104+
private fun findBorders(): Pair<Coordinates, Coordinates> {
105+
val minRow = stars.minOf { it.position.row }
106+
val minCol = stars.minOf { it.position.col }
107+
val maxRow = stars.maxOf { it.position.row }
108+
val maxCol = stars.maxOf { it.position.col }
109+
return Coordinates(minRow, minCol) to Coordinates(maxRow, maxCol)
110+
}
111+
112+
companion object {
113+
fun of(input: List<String>): StarAlignmentGrid = StarAlignmentGrid(input.parsePoints())
114+
115+
private val inputPattern = "position=<([- 0-9]+),([- 0-9]+)> velocity=<([- 0-9]+),([- 0-9]+)>".toPattern()
116+
private fun List<String>.parsePoints(): List<Star> = map { line ->
117+
val matcher = inputPattern.matcher(line)
118+
require(matcher.matches())
119+
val (pCol, pRow, vCol, vRow) = (1..4).map {
120+
matcher.group(it).trim().toInt()
121+
}
122+
Star(Coordinates(pRow, pCol), Coordinates(vRow, vCol))
123+
}
124+
}
125+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package de.ronny_h.aoc.year2018.day10
2+
3+
import de.ronny_h.aoc.extensions.asList
4+
import de.ronny_h.aoc.extensions.grids.Coordinates
5+
import io.kotest.core.spec.style.StringSpec
6+
import io.kotest.matchers.shouldBe
7+
8+
class TheStarsAlignTest : StringSpec({
9+
10+
val input = """
11+
position=< 9, 1> velocity=< 0, 2>
12+
position=< 7, 0> velocity=<-1, 0>
13+
position=< 3, -2> velocity=<-1, 1>
14+
position=< 6, 10> velocity=<-2, -1>
15+
position=< 2, -4> velocity=< 2, 2>
16+
position=<-6, 10> velocity=< 2, -2>
17+
position=< 1, 8> velocity=< 1, -1>
18+
position=< 1, 7> velocity=< 1, 0>
19+
position=<-3, 11> velocity=< 1, -2>
20+
position=< 7, 6> velocity=<-1, -1>
21+
position=<-2, 3> velocity=< 1, 0>
22+
position=<-4, 3> velocity=< 2, 0>
23+
position=<10, -3> velocity=<-1, 1>
24+
position=< 5, 11> velocity=< 1, -2>
25+
position=< 4, 7> velocity=< 0, -1>
26+
position=< 8, -2> velocity=< 0, 1>
27+
position=<15, 0> velocity=<-2, 0>
28+
position=< 1, 6> velocity=< 1, 0>
29+
position=< 8, 9> velocity=< 0, -1>
30+
position=< 3, 3> velocity=<-1, 1>
31+
position=< 0, 5> velocity=< 0, -1>
32+
position=<-2, 2> velocity=< 2, 0>
33+
position=< 5, -2> velocity=< 1, 2>
34+
position=< 1, 4> velocity=< 2, 1>
35+
position=<-2, 7> velocity=< 2, -2>
36+
position=< 3, 6> velocity=<-1, -1>
37+
position=< 5, 0> velocity=< 1, 0>
38+
position=<-6, 0> velocity=< 2, 0>
39+
position=< 5, 9> velocity=< 1, -2>
40+
position=<14, 7> velocity=<-2, 0>
41+
position=<-3, 6> velocity=< 2, -1>
42+
""".asList()
43+
44+
val smallInput = """
45+
position=< 9, 1> velocity=< 0, 2>
46+
position=< 7, 0> velocity=<-1, 0>
47+
""".asList()
48+
49+
"Input can be parsed" {
50+
StarAlignmentGrid.of(smallInput).stars shouldBe listOf(
51+
Star(Coordinates(1, 9), Coordinates(2, 0)),
52+
Star(Coordinates(0, 7), Coordinates(0, -1)),
53+
)
54+
}
55+
56+
"Star movements can be calculated" {
57+
StarAlignmentGrid.of(smallInput).move().stars shouldBe listOf(
58+
Star(Coordinates(3, 9), Coordinates(2, 0)),
59+
Star(Coordinates(0, 6), Coordinates(0, -1)),
60+
)
61+
}
62+
63+
"part 1: For the sample input, a message can be seen after 3 iterations" {
64+
TheStarsAlign().part1(input) shouldBe 3
65+
}
66+
67+
"part 2: For the sample input, the Elves have to wait 3 seconds" {
68+
TheStarsAlign().part2(input) shouldBe 3
69+
}
70+
})

0 commit comments

Comments
 (0)