@@ -3,105 +3,94 @@ package AdventOfCode2022
33object Day22 :
44 val (right, down, left, up) = (Point (1 , 0 ), Point (0 , 1 ), Point (- 1 , 0 ), Point (0 , - 1 ))
55
6+ type State = (Point , Point )
7+
68 enum Tile :
79 case Open , Solid , Wrap
8- import Tile ._
910
1011 case class Point (x : Int , y : Int ):
1112 def + (other : Point ): Point = Point (x + other.x, y + other.y)
1213 def clockwise : Point = Point (- y, x)
1314 def counterClockwise : Point = Point (y, - x)
1415
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 ) =
1817 val points = for
1918 (row, y) <- input.dropRight(2 ).zipWithIndex
2019 (cell, x) <- row.zipWithIndex
2120 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 )
2423
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 =
2625 val numbers = path.split(" \\ D+" ).map(_.toInt).toSeq
2726 val letters = path.split(" \\ d+" ).toSeq
2827 val moves = numbers.zip(letters)
2928
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)) =>
3231 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
3635
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), _) =>
3937 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)
4444 }
4545 }
4646
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)
4948 end follow
5049
5150 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)
7065 end part1
7166
7267 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 =
7774 val (cubeX, cubeY) = (position.x / 50 , position.y / 50 )
7875 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)
10594 end part2
10695
10796 def main (args : Array [String ]): Unit =
0 commit comments