|
| 1 | +package AdventOfCode2019 |
| 2 | + |
| 3 | +import scala.annotation.tailrec |
| 4 | + |
| 5 | +object Day12: |
| 6 | + case class Point(x: Int, y: Int, z: Int): |
| 7 | + def +(other: Point): Point = Point(x + other.x, y + other.y, z + other.z) |
| 8 | + def -(other: Point): Point = Point(x - other.x, y - other.y, z - other.z) |
| 9 | + def sign: Point = Point(x.sign, y.sign, z.sign) |
| 10 | + def manhattan: Int = x.abs + y.abs + z.abs |
| 11 | + |
| 12 | + case class Moon(position: Point, velocity: Point): |
| 13 | + def energy: Int = position.manhattan * velocity.manhattan |
| 14 | + |
| 15 | + def parse(input: Seq[String]): Seq[Moon] = |
| 16 | + val regex = """<x=(-?\d+), y=(-?\d+), z=(-?\d+)>""".r |
| 17 | + input.map { case regex(x, y, z) => Moon(Point(x.toInt, y.toInt, z.toInt), Point(0, 0, 0)) } |
| 18 | + |
| 19 | + def step(moons: Seq[Moon]): Seq[Moon] = moons.map { moon => |
| 20 | + val velocity = moons.foldLeft(moon.velocity)((total, next) => total + (next.position - moon.position).sign) |
| 21 | + Moon(moon.position + velocity, velocity) |
| 22 | + } |
| 23 | + |
| 24 | + def gcd(a: Long, b: Long): Long = if a % b == 0 then b else gcd(b, a % b) |
| 25 | + |
| 26 | + def lcm(a: Long, b: Long): Long = a * b / gcd(a, b) |
| 27 | + |
| 28 | + def part1(input: Seq[String]): Int = Iterator.iterate(parse(input))(step).drop(1000).next().map(_.energy).sum |
| 29 | + |
| 30 | + def part2(input: Seq[String]): Long = |
| 31 | + @tailrec |
| 32 | + def halfPeriod(moons: Seq[Moon], dimension: Point => Int, count: Int = 1): Long = |
| 33 | + val next = step(moons) |
| 34 | + if next.map(_.velocity).map(dimension).forall(_ == 0) then count else halfPeriod(next, dimension, count + 1) |
| 35 | + |
| 36 | + val initial = parse(input) |
| 37 | + val halfPeriodX = halfPeriod(initial, (p: Point) => p.x) |
| 38 | + val halfPeriodY = halfPeriod(initial, (p: Point) => p.y) |
| 39 | + val halfPeriodZ = halfPeriod(initial, (p: Point) => p.z) |
| 40 | + |
| 41 | + 2 * lcm(lcm(halfPeriodX, halfPeriodY), halfPeriodZ) |
| 42 | + end part2 |
| 43 | + |
| 44 | + def main(args: Array[String]): Unit = |
| 45 | + val data = io.Source.fromResource("AdventOfCode2019/Day12.txt").getLines().toSeq |
| 46 | + println(part1(data)) |
| 47 | + println(part2(data)) |
0 commit comments