Skip to content

Commit

Permalink
refactor(2024/13): complete rewrite
Browse files Browse the repository at this point in the history
  • Loading branch information
scarf005 committed Dec 13, 2024
1 parent 03e6b19 commit a3de7e7
Showing 1 changed file with 45 additions and 44 deletions.
89 changes: 45 additions & 44 deletions 2024/day13.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,52 @@ package `2024`.day13

import scala.io.Source.fromFile

object D:
def unapply(s: String) = s.toIntOption.map(BigDecimal(_))

case class Claw(a: BigDecimal, b: BigDecimal, target: BigDecimal)

case class Machine(l: Claw, r: Claw):
lazy val tokens = solve.map((x, y) => x * 3 + y).sum
lazy val solve: Option[(BigInt, BigInt)] =
val bmul = (l.b * r.a) - (r.b * l.a)
val tmul = (l.target * r.a) - (r.target * l.a)
val bUnit = tmul / bmul
val aUnit = (l.target - l.b * bUnit) / l.a
Option.when(aUnit.isWhole && bUnit.isWhole)(
aUnit.toBigInt -> bUnit.toBigInt,
)

given diff: BigDecimal = BigDecimal(10000000000000L)

object Machine:
def parse(xs: Vector[String]) = xs match
case Vector(
s"Button A: X+${D(a)}, Y+${D(d)}",
s"Button B: X+${D(b)}, Y+${D(e)}",
s"Prize: X=${D(c)}, Y=${D(f)}",
extension (a: Long)
infix def safeDiv(b: Long): Option[Long] =
Option.when(b != 0 && a % b == 0)(a / b)

case class Claw(ax: Long, ay: Long, bx: Long, by: Long, x: Long, y: Long):
// A⋅ax + B⋅bx = x, A⋅ay + B⋅by = y
// A = (x - B⋅bx) / ax, A = (y - B⋅by) / ay
// (x - B⋅bx) / ax = (y - B⋅by) / ay
// (x - B⋅bx)⋅ay = (y - B⋅by)⋅ax
// x⋅ay - B⋅bx⋅ay = y⋅ax - B⋅by⋅ax
// (x⋅ay - y⋅ax) = B⋅(bx⋅ay - by⋅ax)
//
// B = (x⋅ay - y⋅ax) / (bx⋅ay - by⋅ax)
// A = (x - B⋅bx) / ax
def solve: Option[Long] = for
b <- (x * ay - y * ax) safeDiv (bx * ay - by * ax)
a <- (x - b * bx) safeDiv ax
yield a * 3 + b

object L:
def unapply(s: String): Option[Long] = s.toLongOption

object Claw:
def parse(xs: Seq[String]): Option[Claw] = xs match
case Seq(
s"Button A: X+${L(ax)}, Y+${L(ay)}",
s"Button B: X+${L(bx)}, Y+${L(by)}",
s"Prize: X=${L(x)}, Y=${L(y)}",
) =>
Some(Machine(Claw(a, b, c), Claw(d, e, f)))
Some(Claw(ax, ay, bx, by, x, y))
case _ => None

def parse(input: String): Seq[Claw] =
input.split("\n+").toSeq.grouped(3).flatMap(Claw.parse).toSeq

def part1(input: String): Long =
parse(input).flatMap(_.solve).sum

def part2(input: String): Long =
val diff = 10_000_000_000_000L
parse(input)
.map(c => c.copy(x = c.x + diff, y = c.y + diff))
.flatMap(_.solve)
.sum

@main def main() =
val machines = fromFile(".cache/2024/13.txt").mkString
.split("\n+")
.toVector
.grouped(3)
.flatMap(Machine.parse)
.toVector

val part1 = machines.map(_.tokens)
println(part1.sum)

val part2 = machines
.map { m =>
m.copy(
l = m.l.copy(target = m.l.target + diff),
r = m.r.copy(target = m.r.target + diff),
)
}
.map(_.tokens)
println(part2.sum)
val input = fromFile(".cache/2024/13.txt").mkString
println(part1(input))
println(part2(input))

0 comments on commit a3de7e7

Please sign in to comment.