Skip to content
Open
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
22 changes: 13 additions & 9 deletions 2024/src/main/scala/aoc2024/Day10.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,45 @@ package aoc2024
import nmcb.*
import nmcb.pos.*

import scala.annotation.tailrec

object Day10 extends AoC:

val grid: Grid[Int] = Grid.fromLines(lines).map(_.asDigit)

val heads: Set[Pos] =
grid.filter((_, i) => i == 0).map(_.pos)

type TrailHead = Set[Vector[Pos]]

extension (trails: TrailHead)

def reachableSummits: Iterable[Int] =
trails.groupMap(_.head)(_.last).values.map(_.size)


extension (g: Grid[Int])

def startingPoints: Set[Pos] =
g.filter((_, i) => i == 0).map(_.pos)

def trailsFrom(head: Pos): TrailHead =

def step(trail: Vector[Pos]): TrailHead =
trail.last.adjoint4
.filter(n => g.within(n) && g.peek(n) == g.peek(trail.last) + 1)
.map(p => trail :+ p)

@tailrec
def loop(trails: TrailHead, current: Int): TrailHead =
val result = trails.filter(trail => g.peek(trail.last) == current)
if current >= 9 then result else loop(result.flatMap(step), current + 1)

loop(Set(Vector(head)), 0)

def score: Long =
heads.flatMap(grid.trailsFrom).reachableSummits.sum
def score(grid: Grid[Int]): Long =
grid.startingPoints.flatMap(grid.trailsFrom).reachableSummits.sum

def rating: Long =
heads.flatMap(grid.trailsFrom).size
def rating(grid: Grid[Int]): Long =
grid.startingPoints.flatMap(grid.trailsFrom).size


override lazy val answer1: Long = grid.score
override lazy val answer2: Long = grid.rating
override lazy val answer1: Long = score(grid)
override lazy val answer2: Long = rating(grid)
28 changes: 15 additions & 13 deletions 2024/src/main/scala/aoc2024/Day11.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,24 @@ object Day11 extends AoC:

type Stone = String

extension (s: Stone) def dropLeadingZeros: Stone =
val dropped = s.dropWhile(_ == '0')
if dropped.isEmpty then "0" else dropped
extension (s: Stone)

type StoneCount = (stone: Stone, count: Long)
def dropLeadingZeros: Stone =
val dropped = s.dropWhile(_ == '0')
if dropped.isEmpty then "0" else dropped

def update(ss: StoneCount): Vector[StoneCount] =
val handle = ss.stone match
case "0" =>
Vector("1")
case s if s.length % 2 == 0 =>
val (l, r) = s.splitAt(s.length / 2)
Vector(l.dropLeadingZeros, r.dropLeadingZeros)
case n =>
Vector((n.toLong * 2024).toString)
type StoneCount = (stone: Stone, count: Long)

def update(ss: StoneCount): Vector[StoneCount] =
val handle: Vector[String] =
ss.stone match
case "0" =>
Vector("1")
case s if s.length % 2 == 0 =>
val (l, r) = s.splitAt(s.length / 2)
Vector(l.dropLeadingZeros, r.dropLeadingZeros)
case n =>
Vector((n.toLong * 2024).toString)
handle.map(_ -> ss.count) :+ (ss.stone -> -ss.count)

val stones: Vector[StoneCount] = input.split(' ').toVector.map(_ -> 1L)
Expand Down
47 changes: 24 additions & 23 deletions 2024/src/main/scala/aoc2024/Day12.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import scala.annotation.*
object Day12 extends AoC:

type Tree = Char
type Fence = (Pos,Dir)
type Fence = (Pos, Dir)
type Fences = Set[Fence]

extension (f: Fence)
Expand All @@ -30,7 +30,6 @@ object Day12 extends AoC:


object Fences:

def around(pos: Pos): Fences =
Set((pos, N), (pos, E), (pos, S), (pos, W))

Expand All @@ -46,14 +45,14 @@ object Day12 extends AoC:

def countSides(positions: Set[Int]): Int =
@tailrec
def loop(l: List[Int], last: Option[Int] = None, result: Int = 0): Int =
l match
case Nil => result
case h :: t if last.contains(h - 1) => loop(t, Some(h), result)
case h :: t => loop(t, Some(h), result + 1)
loop(positions.toList.sorted)

def fencePositions(d: Dir, p: Map[Dir,Set[Pos]], g: Pos => Int, f: Pos => Int): Map[Int,Set[Int]] =
def loop(l: Vector[Int], last: Option[Int] = None, result: Int = 0): Int =
l.runtimeChecked match
case Vector() => result
case h +: t if last.contains(h - 1) => loop(t, Some(h), result)
case h +: t => loop(t, Some(h), result + 1)
loop(positions.toVector.sorted)

def fencePositions(d: Dir, p: Map[Dir, Set[Pos]], g: Pos => Int, f: Pos => Int): Map[Int, Set[Int]] =
p.get(d).map(_.groupMap(g)(f)).getOrElse(sys.error(s"no fence: $d"))

val fence = fences.groupMap(_.right)(_.left)
Expand All @@ -80,40 +79,42 @@ object Day12 extends AoC:
plots.contains(p)


extension (g: Grid[Tree])
extension (trees: Grid[Tree])

def regionOf(pos: Pos): Region =
val tree = g.peek(pos)
val tree = trees.peek(pos)

@tailrec
def loop(todo: Set[Pos], region: Region): Region =
if todo.isEmpty then
region
else
val pos = todo.head
val rest = todo.tail
if !region.contains(pos) && g.contains(pos, tree) then
loop(rest ++ pos.adjWithinGrid(g, (p,_) => !region.contains(p)), region.add(pos))
if !region.contains(pos) && trees.contains(pos, tree) then
loop(rest ++ pos.adjWithinGrid(trees, (p, _) => !region.contains(p)), region.add(pos))
else
loop(rest, region)

val r = Region(tree, Set(pos), fences = Fences.around(pos))
loop(pos.adjWithinGrid(g, _ => true), r)
val region = Region(tree, Set(pos), fences = Fences.around(pos))
loop(pos.adjWithinGrid(trees, _ => true), region)

def regions: Vector[Region] =

@tailrec
def loop(todo: Set[Pos], visited: Set[Pos] = Set.empty, result: Vector[Region] = Vector.empty): Vector[Region] =
if todo.isEmpty then
result
else
val p = todo.head
val t = todo.tail
if visited.contains(p) then
loop(t, visited, result)
val pos = todo.head
val rest = todo.tail
if visited.contains(pos) then
loop(rest, visited, result)
else
val r = g.regionOf(p)
loop(t, visited = visited ++ r.plots, result :+ r)
val region = trees.regionOf(pos)
loop(rest, visited = visited ++ region.plots, result :+ region)

loop(g.positions)
loop(trees.positions)

val garden: Grid[Tree] = Grid.fromLines(lines)

Expand Down
4 changes: 2 additions & 2 deletions 2024/src/main/scala/aoc2024/Day13.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ object Day13 extends AoC:
val ps = lines.collect:
case s"Prize: X=$x, Y=$y" => Position(x.toLong, y.toLong)
as.zip(bs).zip(ps).map:
case ((a,b),p) => Machine(a, b, p)
case ((a, b), p) => Machine(a, b, p)

override lazy val answer1: Long = machines.flatMap(_.solve(offset = 0L)).sum
override lazy val answer2: Long = machines.flatMap(_.solve(offset = 10000000000000L)).sum
override lazy val answer2: Long = machines.flatMap(_.solve(offset = 10_000_000_000_000L)).sum