Skip to content

Commit a521eec

Browse files
committed
Further tidy
1 parent 05a3aab commit a521eec

File tree

1 file changed

+57
-68
lines changed

1 file changed

+57
-68
lines changed

src/main/scala/AdventOfCode2022/Day22.scala

Lines changed: 57 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -3,105 +3,94 @@ package AdventOfCode2022
33
object 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

Comments
 (0)