Day 18
This commit is contained in:
27
aoc/src/dev/ctsk/aoc/DisjointSets.scala
Normal file
27
aoc/src/dev/ctsk/aoc/DisjointSets.scala
Normal 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
|
||||
@@ -11,8 +11,7 @@ case class Point(x: Int, y: Int):
|
||||
def *(n: Int): Point = Point(n * x, n * y)
|
||||
def reduce: Point = { val g = gcd(x.abs, y.abs); Point(x / g, y / g) }
|
||||
|
||||
val directions =
|
||||
Seq(Direction.Up, Direction.Right, Direction.Down, Direction.Left)
|
||||
val DIRS = Seq(Direction.Up, Direction.Right, Direction.Down, Direction.Left)
|
||||
|
||||
object Direction:
|
||||
def from(c: Char): Direction =
|
||||
|
||||
@@ -19,7 +19,8 @@ val solvers = Map[Int, Solver](
|
||||
14 -> Day14,
|
||||
15 -> Day15,
|
||||
16 -> Day16,
|
||||
17 -> Day17
|
||||
17 -> Day17,
|
||||
18 -> Day18
|
||||
)
|
||||
|
||||
def runSolver(solver: Solver, input: os.Path): Unit =
|
||||
|
||||
@@ -43,7 +43,7 @@ object Day16 extends Solver(16):
|
||||
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)
|
||||
|
||||
|
||||
@@ -45,10 +45,10 @@ object Day17 extends Solver(17):
|
||||
|
||||
def rec(pos: Int = 0, acc: Long = 0): Option[Long] =
|
||||
if pos >= target.length then return Some(acc)
|
||||
|
||||
def check(aVal: Long): Boolean =
|
||||
machine.execute(initialRegs.updated('A', aVal), Some(1)).head == target(
|
||||
pos
|
||||
)
|
||||
machine.execute(initialRegs.updated('A', aVal), Some(1)).head
|
||||
== target(pos)
|
||||
|
||||
(0 until 8)
|
||||
.map((acc << 3) + _)
|
||||
@@ -61,13 +61,10 @@ object Day17 extends Solver(17):
|
||||
override def run(input: os.ReadablePath): (Timings, Solution) =
|
||||
val Array(initial_, code_) = os.read(input).split("\n\n")
|
||||
val initialRegs = initial_.linesIterator
|
||||
.map(line => {
|
||||
val spl = line.split(" ");
|
||||
(spl(1)(0) -> spl(2).toLong)
|
||||
})
|
||||
.map(_.split(" "))
|
||||
.map(a => a(1)(0) -> a(2).toLong)
|
||||
.toMap
|
||||
val code = longs(code_)
|
||||
val machine = Machine(code)
|
||||
val machine = Machine(longs(code_).toArray)
|
||||
|
||||
val (p1_time, p1_solution) = timed { part1(machine, initialRegs) }
|
||||
val (p2_time, p2_solution) = timed { part2(machine, initialRegs) }
|
||||
|
||||
60
aoc/src/dev/ctsk/aoc/days/Day18.scala
Normal file
60
aoc/src/dev/ctsk/aoc/days/Day18.scala
Normal 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
2
data/18.ans
Normal file
@@ -0,0 +1,2 @@
|
||||
262
|
||||
22,20
|
||||
3450
data/18.in
Normal file
3450
data/18.in
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user