~macaptain/advent-of-code

28115c0858de95c2437b79e79660eb30d8ae9858 — Michael Captain 2 years ago 31a03ca
Complete 2021 Day 17
A src/main/advent2021/Day17.kt => src/main/advent2021/Day17.kt +57 -0
@@ 0,0 1,57 @@
package advent2021

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 @@
package advent2021

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