@@ -3,105 +3,94 @@ package AdventOfCode2022
3
3
object Day22 :
4
4
val (right, down, left, up) = (Point (1 , 0 ), Point (0 , 1 ), Point (- 1 , 0 ), Point (0 , - 1 ))
5
5
6
+ type State = (Point , Point )
7
+
6
8
enum Tile :
7
9
case Open , Solid , Wrap
8
- import Tile ._
9
10
10
11
case class Point (x : Int , y : Int ):
11
12
def + (other : Point ): Point = Point (x + other.x, y + other.y)
12
13
def clockwise : Point = Point (- y, x)
13
14
def counterClockwise : Point = Point (y, - x)
14
15
15
- case class State (position : Point , direction : Point )
16
-
17
- def parse (input : Seq [String ]): Map [Point , Tile ] =
16
+ def parse (input : Seq [String ]): (Map [Point , Tile ], String ) =
18
17
val points = for
19
18
(row, y) <- input.dropRight(2 ).zipWithIndex
20
19
(cell, x) <- row.zipWithIndex
21
20
if cell != ' '
22
- yield Point (x, y) -> (if cell == '.' then Open else Solid )
23
- points.toMap.withDefaultValue(Wrap )
21
+ yield Point (x, y) -> (if cell == '.' then Tile . Open else Tile . Solid )
22
+ ( points.toMap.withDefaultValue(Tile . Wrap ), input.last )
24
23
25
- def follow (points : Map [Point , Tile ], path : String , handleWrap : State => State ): Int =
24
+ def follow (tiles : Map [Point , Tile ], path : String , handleWrap : State => State ): Int =
26
25
val numbers = path.split(" \\ D+" ).map(_.toInt).toSeq
27
26
val letters = path.split(" \\ d+" ).toSeq
28
27
val moves = numbers.zip(letters)
29
28
30
- val initial = State (Point (50 , 0 ), Point (1 , 0 ))
31
- val result = moves.foldLeft(initial) { case (state , (number, letter)) =>
29
+ val initial = (Point (50 , 0 ), Point (1 , 0 ))
30
+ val (position, direction) = moves.foldLeft(initial) { case ((position, direction) , (number, letter)) =>
32
31
val nextDirection = letter match
33
- case " L" => state. direction.counterClockwise
34
- case " R" => state. direction.clockwise
35
- case _ => state. direction
32
+ case " L" => direction.counterClockwise
33
+ case " R" => direction.clockwise
34
+ case _ => direction
36
35
37
- (1 to number).foldLeft(State (state.position, nextDirection)) { (state, _) =>
38
- val State (position, direction) = state
36
+ (1 to number).foldLeft((position, nextDirection)) { case ((position, direction), _) =>
39
37
val next = position + direction
40
- points(next) match
41
- case Open => State (next, direction)
42
- case Solid => state
43
- case Wrap => handleWrap(state)
38
+ tiles(next) match
39
+ case Tile .Open => (next, direction)
40
+ case Tile .Solid => (position, direction)
41
+ case Tile .Wrap =>
42
+ val (wrapPosition, wrapDirection) = handleWrap(position, direction)
43
+ if tiles(wrapPosition) == Tile .Open then (wrapPosition, wrapDirection) else (position, direction)
44
44
}
45
45
}
46
46
47
- val facing = Seq (right, down, left, up)
48
- 1000 * (result.position.y + 1 ) + 4 * (result.position.x + 1 ) + facing.indexOf(result.direction)
47
+ 1000 * (position.y + 1 ) + 4 * (position.x + 1 ) + Seq (right, down, left, up).indexOf(direction)
49
48
end follow
50
49
51
50
def part1 (input : Seq [String ]): Int =
52
- val tiles = parse(input)
53
-
54
- val valid = tiles.filterNot((k, v) => v == Wrap ).keySet
55
- val minX = valid.groupMapReduce(_.y)(_.x)(_ min _)
56
- val maxX = valid.groupMapReduce(_.y)(_.x)(_ max _)
57
- val minY = valid.groupMapReduce(_.x)(_.y)(_ min _)
58
- val maxY = valid.groupMapReduce(_.x)(_.y)(_ max _)
59
-
60
- def handleWrap (state : State ): State =
61
- val State (position, direction) = state
62
- val nextPosition = direction match
63
- case `right` => Point (minX(position.y), position.y)
64
- case `left` => Point (maxX(position.y), position.y)
65
- case `down` => Point (position.x, minY(position.x))
66
- case `up` => Point (position.x, maxY(position.x))
67
- if tiles(nextPosition) == Open then State (nextPosition, direction) else state
68
-
69
- follow(tiles, input.last, handleWrap)
51
+ val (tiles, path) = parse(input)
52
+
53
+ val minX = tiles.keys.groupMapReduce(_.y)(_.x)(_ min _)
54
+ val maxX = tiles.keys.groupMapReduce(_.y)(_.x)(_ max _)
55
+ val minY = tiles.keys.groupMapReduce(_.x)(_.y)(_ min _)
56
+ val maxY = tiles.keys.groupMapReduce(_.x)(_.y)(_ max _)
57
+
58
+ def handleWrap (position : Point , direction : Point ): State = direction match
59
+ case `right` => position.copy(x = minX(position.y)) -> right
60
+ case `left` => position.copy(x = maxX(position.y)) -> left
61
+ case `down` => position.copy(y = minY(position.x)) -> down
62
+ case `up` => position.copy(y = maxY(position.x)) -> up
63
+
64
+ follow(tiles, path, handleWrap)
70
65
end part1
71
66
72
67
def part2 (input : Seq [String ]): Int =
73
- val tiles = parse(input)
74
-
75
- def handleWrap (state : State ): State =
76
- val State (position, direction) = state
68
+ // Cube faces:
69
+ // BA
70
+ // C
71
+ // ED
72
+ // F
73
+ def handleWrap (position : Point , direction : Point ): State =
77
74
val (cubeX, cubeY) = (position.x / 50 , position.y / 50 )
78
75
val (modX, modY) = (position.x % 50 , position.y % 50 )
79
-
80
- // Cube faces:
81
- // BA
82
- // C
83
- // ED
84
- // F
85
- val (nextPosition, nextDirection) = (cubeX, cubeY, direction) match
86
- case (2 , 0 , `up`) => Point (modX, 199 ) -> up // A to F
87
- case (2 , 0 , `down`) => Point (99 , 50 + modX) -> left // A to C
88
- case (2 , 0 , `right`) => Point (99 , 149 - modY) -> left // A to D
89
- case (1 , 0 , `up`) => Point (0 , 150 + modX) -> right // B to F
90
- case (1 , 0 , `left`) => Point (0 , 149 - modY) -> right // B to E
91
- case (1 , 1 , `left`) => Point (modY, 100 ) -> down // C to E
92
- case (1 , 1 , `right`) => Point (100 + modY, 49 ) -> up // C to A
93
- case (1 , 2 , `down`) => Point (49 , 150 + modX) -> left // D to F
94
- case (1 , 2 , `right`) => Point (149 , 49 - modY) -> left // D to A
95
- case (0 , 2 , `up`) => Point (50 , 50 + modX) -> right // E to C
96
- case (0 , 2 , `left`) => Point (50 , 49 - modY) -> right // E to B
97
- case (0 , 3 , `down`) => Point (100 + modX, 0 ) -> down // F to A
98
- case (0 , 3 , `left`) => Point (50 + modY, 0 ) -> down // F to B
99
- case (0 , 3 , `right`) => Point (50 + modY, 149 ) -> up // F to D
100
-
101
- if tiles(nextPosition) == Open then State (nextPosition, nextDirection) else state
102
- end handleWrap
103
-
104
- follow(tiles, input.last, handleWrap)
76
+ (cubeX, cubeY, direction) match
77
+ case (2 , 0 , `up`) => Point (modX, 199 ) -> up // A to F
78
+ case (2 , 0 , `down`) => Point (99 , 50 + modX) -> left // A to C
79
+ case (2 , 0 , `right`) => Point (99 , 149 - modY) -> left // A to D
80
+ case (1 , 0 , `up`) => Point (0 , 150 + modX) -> right // B to F
81
+ case (1 , 0 , `left`) => Point (0 , 149 - modY) -> right // B to E
82
+ case (1 , 1 , `left`) => Point (modY, 100 ) -> down // C to E
83
+ case (1 , 1 , `right`) => Point (100 + modY, 49 ) -> up // C to A
84
+ case (1 , 2 , `down`) => Point (49 , 150 + modX) -> left // D to F
85
+ case (1 , 2 , `right`) => Point (149 , 49 - modY) -> left // D to A
86
+ case (0 , 2 , `up`) => Point (50 , 50 + modX) -> right // E to C
87
+ case (0 , 2 , `left`) => Point (50 , 49 - modY) -> right // E to B
88
+ case (0 , 3 , `down`) => Point (100 + modX, 0 ) -> down // F to A
89
+ case (0 , 3 , `left`) => Point (50 + modY, 0 ) -> down // F to B
90
+ case (0 , 3 , `right`) => Point (50 + modY, 149 ) -> up // F to D
91
+
92
+ val (tiles, path) = parse(input)
93
+ follow(tiles, path, handleWrap)
105
94
end part2
106
95
107
96
def main (args : Array [String ]): Unit =
0 commit comments