This commit is contained in:
Christian
2024-12-18 12:37:04 +01:00
parent e435a7b160
commit 71804973b0
8 changed files with 3549 additions and 13 deletions

View File

@@ -0,0 +1,27 @@
package dev.ctsk.aoc
import scala.collection.mutable
case class DisjointSets[A](members: Seq[A]):
private val parent = mutable.Map.from(members.zip(members))
private val rank = mutable.Map.from(members.map(_ -> 1))
def joint(m1: A, m2: A): Boolean = find(m1) == find(m2)
def find(member: A): A =
val up = parent(member)
if up == member then up
else {
val root = find(up); parent(member) = root; root
}
def union(m1: A, m2: A): Unit =
val p1 = find(m1);
val p2 = find(m2)
if p1 == p2 then return
val r1 = rank(p1);
val r2 = rank(p2)
r1.compare(r2) match
case k if k < 0 => parent(p1) = p2
case 0 => parent(p1) = p2; rank(p2) += 1
case k if k > 0 => parent(p2) = p1

View File

@@ -11,8 +11,7 @@ case class Point(x: Int, y: Int):
def *(n: Int): Point = Point(n * x, n * y) def *(n: Int): Point = Point(n * x, n * y)
def reduce: Point = { val g = gcd(x.abs, y.abs); Point(x / g, y / g) } def reduce: Point = { val g = gcd(x.abs, y.abs); Point(x / g, y / g) }
val directions = val DIRS = Seq(Direction.Up, Direction.Right, Direction.Down, Direction.Left)
Seq(Direction.Up, Direction.Right, Direction.Down, Direction.Left)
object Direction: object Direction:
def from(c: Char): Direction = def from(c: Char): Direction =

View File

@@ -19,7 +19,8 @@ val solvers = Map[Int, Solver](
14 -> Day14, 14 -> Day14,
15 -> Day15, 15 -> Day15,
16 -> Day16, 16 -> Day16,
17 -> Day17 17 -> Day17,
18 -> Day18
) )
def runSolver(solver: Solver, input: os.Path): Unit = def runSolver(solver: Solver, input: os.Path): Unit =

View File

@@ -43,7 +43,7 @@ object Day16 extends Solver(16):
search(Pose(start, Direction.Right)) search(Pose(start, Direction.Right))
} }
val endPose = directions.map(Pose(end, _)).minBy(distance(_)) val endPose = DIRS.map(Pose(end, _)).minBy(distance(_))
val p1 = distance(endPose) val p1 = distance(endPose)

View File

@@ -45,10 +45,10 @@ object Day17 extends Solver(17):
def rec(pos: Int = 0, acc: Long = 0): Option[Long] = def rec(pos: Int = 0, acc: Long = 0): Option[Long] =
if pos >= target.length then return Some(acc) if pos >= target.length then return Some(acc)
def check(aVal: Long): Boolean = def check(aVal: Long): Boolean =
machine.execute(initialRegs.updated('A', aVal), Some(1)).head == target( machine.execute(initialRegs.updated('A', aVal), Some(1)).head
pos == target(pos)
)
(0 until 8) (0 until 8)
.map((acc << 3) + _) .map((acc << 3) + _)
@@ -61,13 +61,10 @@ object Day17 extends Solver(17):
override def run(input: os.ReadablePath): (Timings, Solution) = override def run(input: os.ReadablePath): (Timings, Solution) =
val Array(initial_, code_) = os.read(input).split("\n\n") val Array(initial_, code_) = os.read(input).split("\n\n")
val initialRegs = initial_.linesIterator val initialRegs = initial_.linesIterator
.map(line => { .map(_.split(" "))
val spl = line.split(" "); .map(a => a(1)(0) -> a(2).toLong)
(spl(1)(0) -> spl(2).toLong)
})
.toMap .toMap
val code = longs(code_) val machine = Machine(longs(code_).toArray)
val machine = Machine(code)
val (p1_time, p1_solution) = timed { part1(machine, initialRegs) } val (p1_time, p1_solution) = timed { part1(machine, initialRegs) }
val (p2_time, p2_solution) = timed { part2(machine, initialRegs) } val (p2_time, p2_solution) = timed { part2(machine, initialRegs) }

View File

@@ -0,0 +1,60 @@
package dev.ctsk.aoc.days
import dev.ctsk.aoc.*
import scala.collection.mutable
import scala.util.boundary
import scala.util.boundary.break
object Day18 extends Solver(18):
val SIZE = 70; val P1_COUNT = 1024
def part1(grid: Grid[Char], coords: Seq[Point]): Int =
for coord <- coords.take(P1_COUNT) do grid(coord) = '#'
val dist = Grid(Array.fill(SIZE + 1, SIZE + 1)(-1))
val dq = mutable.ArrayDeque((0, Point(0, 0)))
while dq.nonEmpty do
val (distance, pt) = dq.removeHead()
for
adj <- DIRS.map(_(pt))
if grid(adj).contains('.')
if dist(adj).contains(-1)
do
dist(adj) = (distance + 1)
dq += ((distance + 1, adj))
dist(Point(SIZE, SIZE)).get
def part2(grid: Grid[Char], coords: Seq[Point]): Point =
for coord <- coords do grid(coord) = '#'
val sets = DisjointSets(grid.points)
for
point <- grid.points
adj <- DIRS.map(_(point))
if grid(point).contains('.')
if grid(adj).contains('.')
do sets.union(point, adj)
boundary:
for coord <- coords.reverse do
grid(coord) = '.'
for pt <- DIRS.map(_(coord)) if grid(pt).contains('.') do
sets.union(coord, pt)
if sets.joint(Point(0, 0), Point(SIZE, SIZE)) then break(coord)
coords.head
override def run(input: os.ReadablePath): (Timings, Solution) =
val grid = Grid(Array.fill(SIZE + 1, SIZE + 1)('.'))
val (pre_time, coords) = timed {
os.read.lines(input).map(longs).map(v => Point.of(v(0), v(1)))
}
val (p1_time, p1) = timed { part1(grid, coords) }
val (p2_time, p2) = timed { part2(grid, coords) }
(
Timings(pre_time, p1_time, p2_time),
Solution(Int.box(p1), f"${p2.x},${p2.y}")
)

2
data/18.ans Normal file
View File

@@ -0,0 +1,2 @@
262
22,20

3450
data/18.in Normal file

File diff suppressed because it is too large Load Diff