Skip to content

feat: prepare for interactive 2024 solution #729

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions 2024/src/day13.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package day13

import locations.Directory.currentDir
import inputs.Input.loadFileSync

@main def part1: Unit =
println(s"The solution is ${part1(loadInput())}")

@main def part2: Unit =
println(s"The solution is ${part2(loadInput())}")

def loadInput(): String = loadFileSync(s"$currentDir/../input/day13")

case class Claw(ax: Long, ay: Long, bx: Long, by: Long, x: Long, y: Long):
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 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(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

extension (a: Long)
infix def safeDiv(b: Long): Option[Long] =
Option.when(b != 0 && a % b == 0)(a / b)

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

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
9 changes: 9 additions & 0 deletions 2024/src/inputs.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package inputs

import scala.util.Using
import scala.io.Source

object Input:

def loadFileSync(path: String): String =
Using.resource(Source.fromFile(path))(_.mkString)
19 changes: 19 additions & 0 deletions 2024/src/locations.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package locations

import scala.quoted.*

object Directory:

/** The absolute path of the parent directory of the file that calls this method
* This is stable no matter which directory runs the program.
*/
inline def currentDir: String = ${ parentDirImpl }

private def parentDirImpl(using Quotes): Expr[String] =
// position of the call to `currentDir` in the source code
val position = quotes.reflect.Position.ofMacroExpansion
// get the path of the file calling this macro
val srcFilePath = position.sourceFile.getJPath.get
// get the parent of the path, which is the directory containing the file
val parentDir = srcFilePath.getParent().toAbsolutePath
Expr(parentDir.toString) // convert the String to Expr[String]