day(17): refactor
Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
parent
56de6f7110
commit
e0d7e4de13
1 changed files with 34 additions and 23 deletions
|
@ -1,17 +1,36 @@
|
||||||
package year2021.day17
|
package year2021.day17
|
||||||
|
|
||||||
import readInput
|
import readInput
|
||||||
|
import kotlin.math.absoluteValue
|
||||||
|
import kotlin.math.min
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.sign
|
import kotlin.math.sign
|
||||||
|
|
||||||
data class Vector(val x: Int, val y: Int) {
|
data class Vector(val x: Int, val y: Int) {
|
||||||
operator fun plus(other: Vector): Vector = Vector(x + other.x, y + other.y)
|
operator fun plus(other: Vector): Vector = Vector(x + other.x, y + other.y)
|
||||||
|
|
||||||
|
fun updateVelocity(): Vector = Vector(x - x.sign, y - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Area(val min: Vector, val max: Vector) {
|
data class Area(val min: Vector, val max: Vector) {
|
||||||
fun has(z: Vector): Boolean = (z.x in min.x..max.x) && (z.y in min.y..max.y)
|
fun has(z: Vector): Boolean = (z.x in min.x..max.x) && (z.y in min.y..max.y)
|
||||||
|
|
||||||
|
private fun speeds(getter: (Vector) -> Int): IntRange =
|
||||||
|
max(getter(min).absoluteValue, getter(max).absoluteValue).let { absMax ->
|
||||||
|
(min(absMax * getter(min).sign, 0)..absMax)
|
||||||
|
}
|
||||||
|
|
||||||
|
val xSpeeds: IntRange
|
||||||
|
get() = speeds { it.x }
|
||||||
|
|
||||||
|
val ySpeeds: IntRange
|
||||||
|
get() = speeds { it.y }
|
||||||
|
|
||||||
|
val possibleVectors: Iterable<Vector>
|
||||||
|
get() = xSpeeds.flatMap { vx -> ySpeeds.map { vy -> Vector(vx, vy) } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// region parsing
|
||||||
fun getRange(range: String): Pair<Int, Int> = range.split("=")[1].let {
|
fun getRange(range: String): Pair<Int, Int> = range.split("=")[1].let {
|
||||||
val (minValue, maxValue) = it.split("..").map(String::toInt)
|
val (minValue, maxValue) = it.split("..").map(String::toInt)
|
||||||
minValue to maxValue
|
minValue to maxValue
|
||||||
|
@ -26,42 +45,34 @@ fun String.toArea(): Area {
|
||||||
|
|
||||||
return Area(Vector(minX, minY), Vector(maxX, maxY))
|
return Area(Vector(minX, minY), Vector(maxX, maxY))
|
||||||
}
|
}
|
||||||
|
// endregion parsing
|
||||||
|
|
||||||
|
|
||||||
fun findPeak(input: Area, v0: Vector): Int? {
|
fun findPeak(input: Area, v0: Vector): Int? {
|
||||||
fun updateVelocity(v: Vector): Vector = Vector(v.x - v.x.sign, v.y - 1)
|
|
||||||
|
|
||||||
var v = v0
|
var v = v0
|
||||||
var p = Vector(0, 0)
|
var p = Vector(0, 0)
|
||||||
|
|
||||||
var maxY = 0
|
var maxY = 0
|
||||||
var hitTarget = false
|
|
||||||
|
|
||||||
while (p.x <= input.max.x && p.y >= input.min.y) {
|
while (p.x <= input.max.x && p.y >= input.min.y) {
|
||||||
p += v
|
p += v
|
||||||
v = updateVelocity(v)
|
v = v.updateVelocity()
|
||||||
|
|
||||||
hitTarget = hitTarget || input.has(p)
|
|
||||||
maxY = max(p.y, maxY)
|
maxY = max(p.y, maxY)
|
||||||
|
if (input.has(p)) {
|
||||||
|
return maxY
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return if (hitTarget) maxY else null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun part1(input: Area): Int =
|
fun part1(input: Area): Int =
|
||||||
(0..input.max.x)
|
input.possibleVectors.maxOf { (x, y) ->
|
||||||
.flatMap { x -> (input.min.y..-input.min.y).map { y -> x to y } }
|
|
||||||
.maxOf { (x, y) ->
|
|
||||||
findPeak(input, Vector(x, y)) ?: 0
|
findPeak(input, Vector(x, y)) ?: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// x = v_0x * t + 1/2 * a_x * t^2
|
|
||||||
// y = v_0y * t + 1/2 * -1 * t^2
|
|
||||||
// v_fy = v_0y + a_y * t => t_up = v_0y / a_y
|
|
||||||
|
|
||||||
fun part2(input: Area): Int =
|
fun part2(input: Area): Int =
|
||||||
(0..input.max.x)
|
input.possibleVectors.count { (x, y) ->
|
||||||
.flatMap { x -> (input.min.y..-input.min.y).map { y -> x to y } }
|
|
||||||
.count { (x, y) ->
|
|
||||||
findPeak(input, Vector(x, y)) != null
|
findPeak(input, Vector(x, y)) != null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,8 +80,8 @@ fun main() {
|
||||||
val sample = readInput(17, "sample").first().toArea()
|
val sample = readInput(17, "sample").first().toArea()
|
||||||
val input = readInput(17, "input").first().toArea()
|
val input = readInput(17, "input").first().toArea()
|
||||||
|
|
||||||
println("x: 0..${sample.max.x}, y: ${sample.min.y}..${-sample.min.y}")
|
println("x: ${sample.xSpeeds}, y: ${sample.ySpeeds}")
|
||||||
println("x: 0..${input.max.x}, y: ${input.min.y}..${-input.min.y}")
|
println("x: ${input.xSpeeds}, y: ${input.ySpeeds}")
|
||||||
|
|
||||||
check(part1(sample) == 45)
|
check(part1(sample) == 45)
|
||||||
println(part1(input))
|
println(part1(input))
|
||||||
|
|
Loading…
Reference in a new issue