-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathday16.sc
More file actions
67 lines (51 loc) 路 2.26 KB
/
Copy pathday16.sc
File metadata and controls
67 lines (51 loc) 路 2.26 KB
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
65
66
67
import common.{Grid, aStarSearch, loadPackets}
import scala.annotation.tailrec
val input = loadPackets(List("day16.txt"))
val ys = input.indices
val xs = input.head.indices
enum Direction:
case North, East, South, West
case object Directions:
def flip(direction: Direction): Direction = direction match {
case Direction.North => Direction.South
case Direction.East => Direction.West
case Direction.South => Direction.North
case Direction.West => Direction.East
}
case class Point(x: Int, y: Int):
def charAt: Char = input(y).charAt(x)
def move(d: Direction) = d match {
case Direction.North => copy(y = y - 1)
case Direction.East => copy(x = x + 1)
case Direction.South => copy(y = y + 1)
case Direction.West => copy(x = x - 1)
}
def onGrid: Boolean = xs.contains(x) && ys.contains(y)
def distanceTo(other: Point): Int = (other.x - x).abs + (other.y - y).abs
val points = for
y <- ys
x <- xs
yield Point(x, y)
val start = points.find(_.charAt == 'S').get
val end = points.find(_.charAt == 'E').get
case class State(location: Point = start, facing: Direction = Direction.East):
def isWall: Boolean = location.charAt == '#'
def neighbors: Iterable[State] = Direction.values.toSeq.map(d => State(location.move(d), d))
.filterNot(_.isWall)
def reverseNeighbors: Iterable[State] =
Direction.values.toSeq.map(d => State(location.move(Directions.flip(facing)), d))
.filterNot(_.isWall)
val grid: Grid[State] = new Grid[State] {
override def heuristicDistanceToFinish(from: State): Int = end.distanceTo(from.location)
override def getNeighbours(state: State): Iterable[State] = state.neighbors
override def moveCost(from: State, to: State): Int = 1 + (if from.facing != to.facing then 1000 else 0)
}
val (part1, distances): (Int, Map[State, Int]) = aStarSearch(State(), grid, _.location == end).get
def findSeats(state: State): Set[Point] =
if state.location == start then Set(start)
else state.reverseNeighbors
.filter(distances.contains)
.filter(neighbor => distances(neighbor) + grid.moveCost(neighbor, state) == distances(state))
.toSet.flatMap(findSeats) + state.location
val endStates = distances.filter(_._1.location == end).filter(_._2 == part1)
val part2 = endStates.keys.flatMap(findSeats).size