28115c0858de95c2437b79e79660eb30d8ae9858 — Michael Captain 2 years ago
```Complete 2021 Day 17
```
```3 files changed, 78 insertions(+), 0 deletions(-)

```
`A src/main/advent2021/Day17.kt => src/main/advent2021/Day17.kt +57 -0`
```@@ 0,0 1,57 @@
+
+import common.Point
+import common.countFrom
+import common.triangle
+import kotlin.math.abs
+
+private fun shootProbe(velocity: Point): Sequence<Point> {
+    return generateSequence(Pair(Point(0, 0), Point(velocity.x, velocity.y))) { (p, v) ->
+        val newXVel = when {
+            v.x > 0 -> v.x - 1
+            v.x < 0 -> v.x + 1
+            else -> 0
+        }
+        Pair(Point(p.x + v.x, p.y + v.y), Point(newXVel, v.y - 1))
+    }.map { it.first }
+}
+
+private fun hitsTargetArea(trajectory: Sequence<Point>, xRange: IntRange, yRange: IntRange): Boolean {
+    val truncatedTrajectory = trajectory.takeWhile { p -> p.y >= yRange.minOf { it } }
+    return truncatedTrajectory.any { p -> p.x in xRange && p.y in yRange }
+}
+
+private fun targetArea(s: String): Pair<IntRange, IntRange> {
+    val (xs, ys) = s.substringAfter("target area: ").split(", ")
+    val (minX, maxX) = xs.substringAfter("x=").split("..").map { it.toInt() }
+    val xRange = minX..maxX
+    val (minY, maxY) = ys.substringAfter("y=").split("..").map { it.toInt() }
+    val yRange = minY..maxY
+    return Pair(xRange, yRange)
+}
+
+fun solve17a(s: String): Int {
+    val (xRange, yRange) = targetArea(s)
+    val mostStylishVelocity = (-xRange.maxOf { abs(it) }..xRange.maxOf { abs(it) }).flatMap { x ->
+        (-yRange.maxOf { abs(it) }..yRange.maxOf { abs(it) }).map { y ->
+            Point(x, y)
+        }
+    }.filter { v -> hitsTargetArea(shootProbe(v), xRange, yRange) }.maxByOrNull { it.y }!!
+    return shootProbe(mostStylishVelocity).takeWhile { p -> p.y >= yRange.minOf { it } }.maxOf { it.y }
+}
+
+fun solve17b(s: String): Int {
+    val (xRange, yRange) = targetArea(s)
+    // Brute force - go!
+    return (-xRange.maxOf { abs(it) }..xRange.maxOf { abs(it) }).sumOf { x ->
+        (-yRange.maxOf { abs(it) }..yRange.maxOf { abs(it) }).count { y ->
+            hitsTargetArea(shootProbe(Point(x, y)), xRange, yRange)
+        }
+    }
+}
+
+fun main() {
+    val targetArea = input("day17").first()
+    println(solve17a(targetArea)) // 5151
+    println(solve17b(targetArea)) // 968
+}<
\ No newline at end of file

```
`A src/main/resources/advent2021/day17_input.txt => src/main/resources/advent2021/day17_input.txt +1 -0`
```@@ 0,0 1,1 @@
+target area: x=135..155, y=-102..-78

```
`A src/test/advent2021/Day17KtTest.kt => src/test/advent2021/Day17KtTest.kt +20 -0`
```@@ 0,0 1,20 @@
+
+import org.junit.jupiter.api.Test
+
+import org.junit.jupiter.api.Assertions.*
+
+internal class Day17KtTest {
+
+    val example = "target area: x=20..30, y=-10..-5"
+
+    @Test
+    fun example17a() {
+        assertEquals(45, solve17a(example))
+    }
+
+    @Test
+    fun example17b() {
+        assertEquals(112, solve17b(example))
+    }
+}<
\ No newline at end of file

```