-
Notifications
You must be signed in to change notification settings - Fork 0
/
day23.sc
64 lines (50 loc) · 2.09 KB
/
day23.sc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import common.loadPackets
import scala.annotation.tailrec
val input = loadPackets(List("day23.txt"))
val rows = input.indices
val cols = input.head.indices
case class Point(row: Int, col: Int) {
lazy val isOnMap: Boolean = rows.contains(row) && cols.contains(col)
lazy val glyph: Char = input(row).charAt(col)
lazy val isPath: Boolean = isOnMap && glyph != '#'
def neighbors(): List[Point] = List(
copy(row = row + 1),
copy(col = col + 1),
copy(row = row - 1),
copy(col = col - 1)
).filter(_.isPath)
def neighborsSlippery(): List[Point] = (glyph match {
case '.' => neighbors()
case '<' => List(copy(col = col - 1))
case '>' => List(copy(col = col + 1))
case 'v' => List(copy(row = row + 1))
case '^' => List(copy(row = row - 1))
}).filter(_.isPath)
}
val start = cols.map(Point(0, _)).find(_.isPath).get
val finish = cols.map(Point(rows.last, _)).find(_.isPath).get
def findLongestHikeSlippery(location: Point, visited: Set[Point]): Option[Int] =
if (location == finish)
Some(visited.size - 1)
else
location.neighborsSlippery().filterNot(visited)
.flatMap(next => findLongestHikeSlippery(next, visited + next))
.maxOption
val part1 = findLongestHikeSlippery(start, Set(start))
val nodes: List[Point] = start :: finish :: rows.toList.flatMap(row => cols.map(col => Point(row, col)))
.filter(_.isPath).filter(_.neighbors().size > 2)
@tailrec
def followPath(from: Point, to: Point, steps: Int = 0): (Point, Int) = to.neighbors().filterNot(_ == from) match {
case next :: Nil => followPath(to, next, steps + 1)
case _ => (to, steps + 1)
}
val routes: Map[Point, Map[Point, Int]] = nodes.map(node => node ->
node.neighbors().filter(_.isPath).map(to => followPath(node, to)).toMap).toMap
def findLongestHike(location: Point, visited: Set[Point], steps: Int = 0): Option[Int] =
if (location == finish)
Some(steps)
else
routes(location).filterNot(route => visited(route._1))
.flatMap({ case (to, extraSteps) => findLongestHike(to, visited + to, steps + extraSteps) })
.maxOption
val part2 = findLongestHike(start, Set(start))