@@ -2,10 +2,137 @@ import Solver from "../../../../../website/src/components/Solver.js"
2
2
3
3
# Day 18: Lavaduct Lagoon
4
4
5
+ by [ @EugeneFlesselle ] ( https://github.com/EugeneFlesselle )
6
+
5
7
## Puzzle description
6
8
7
9
https://adventofcode.com/2023/day/18
8
10
11
+ ## Solution Summary
12
+
13
+ Assume we have a given ` digPlan: Seq[Trench] ` for which to compute the area,
14
+ and let the following classes:
15
+ ``` scala 3
16
+ enum Direction :
17
+ case Up , Down , Left , Right
18
+
19
+ case class Trench (dir : Direction , length : Int )
20
+ ```
21
+
22
+ We can go through the dig plan keeping track of the current position,
23
+ by starting from ` (x = 0, y = 0) ` , increasing ` x ` when going to ` Right ` , increasing ` y ` when going down, and so on.
24
+
25
+ Provided our current position, we can then keep track of the lagoon area as follows:
26
+ - When going ` Right ` : we count all the points in the line we cover, i.e the ` length ` of the trench.
27
+ - When going ` Down ` : we count all the points which we leave on the left (or pass over),
28
+ i.e. the ` length ` of the downwards trench times our current ` x ` coordinate,
29
+ ` +1 ` to count the current vertical trench as in the area.
30
+ Of course, we may be including too much at this point,
31
+ since we do not yet know what part of the left is actually in the lagoon,
32
+ but we will account for it later.
33
+ - When going ` Right ` : there is nothing to add,
34
+ the position could only have been reached from a downwards trench,
35
+ hence the area has already been counted.
36
+ - When going ` Up ` : we now know by how much we had over increased the area when going down,
37
+ and can remove everything strictly to the left of the current ` x ` position.
38
+
39
+ In summary, we assume we cover everything to the left when going down
40
+ and remove the uncovered part when coming back up.
41
+ Finally, we must start from an area of ` 1 ` as the starting position ` (0, 0) ` is naturally covered,
42
+ but isn't counted by the first trench whatever it may be.
43
+ All of which translates to the following foldLeft in scala 😉:
44
+
45
+ ``` scala 3
46
+ val (_, area) = digPlan.foldLeft((0 , 0 ), 1L ):
47
+ case (((x, y), area), Trench (dir, len)) => dir match
48
+ case Right => ((x + len, y), area + len)
49
+ case Down => ((x, y + len), area + (x + 1 ) * len.toLong)
50
+ case Left => ((x - len, y), area)
51
+ case Up => ((x, y - len), area - x * len.toLong)
52
+ ```
53
+
54
+ Also note we have to use ` Long ` s to avoid the computations from overflowing.
55
+
56
+
57
+ ### Part 1
58
+
59
+ We can get the ` Trench ` of each line in the ` input: String ` ,
60
+ by parsing the direction from the corresponding character
61
+ and ignoring the color of the trench.
62
+
63
+ And then proceed as above with the obtained ` digPlan ` .
64
+
65
+ ``` scala 3
66
+ object Direction :
67
+ def fromChar (c : Char ): Direction = c match
68
+ case 'U' => Up case 'D' => Down case 'L' => Left case 'R' => Right
69
+
70
+ val digPlan = for
71
+ case s " $dirC $len (# $_) " <- input.linesIterator
72
+ dir = Direction .fromChar(dirC.head)
73
+ yield Trench (dir, len.toInt)
74
+ ```
75
+
76
+ ### Part 2
77
+
78
+ We do the same for part 2, except we use the color to
79
+ get the trench fields:
80
+ the direction from the last digit,
81
+ and the length by converting from the hexadecimal encoding of remaining digits.
82
+
83
+ ``` scala 3
84
+ object Direction :
85
+ def fromInt (i : Char ): Direction = i match
86
+ case '0' => Right case '1' => Down case '2' => Left case '3' => Up
87
+
88
+ val digPlan = for
89
+ case s " $_ $_ (# $color) " <- input.linesIterator
90
+ dir = Direction .fromInt(color.last)
91
+ len = BigInt (x = color.init, radix = 16 )
92
+ yield Trench (dir, len.toInt)
93
+ ```
94
+
95
+ ## Final code
96
+
97
+ ``` scala 3
98
+ enum Direction :
99
+ case Up , Down , Left , Right
100
+ object Direction :
101
+ def fromChar (c : Char ): Direction = c match
102
+ case 'U' => Up case 'D' => Down case 'L' => Left case 'R' => Right
103
+ def fromInt (i : Char ): Direction = i match
104
+ case '0' => Right case '1' => Down case '2' => Left case '3' => Up
105
+ import Direction .*
106
+
107
+ case class Trench (dir : Direction , length : Int )
108
+
109
+ def area (digPlan : Seq [Trench ]): Long =
110
+ val (_, area) = digPlan.foldLeft((0 , 0 ), 1L ):
111
+ case (((x, y), area), Trench (dir, len)) => dir match
112
+ case Right => ((x + len, y), area + len)
113
+ case Down => ((x, y + len), area + (x + 1 ) * len.toLong)
114
+ case Left => ((x - len, y), area)
115
+ case Up => ((x, y - len), area - x * len.toLong)
116
+ area
117
+
118
+ def part1 (input : String ): String =
119
+ val digPlan = for
120
+ case s " $dirC $len (# $_) " <- input.linesIterator
121
+ dir = Direction .fromChar(dirC.head)
122
+ yield Trench (dir, len.toInt)
123
+
124
+ area(digPlan.toSeq).toString
125
+
126
+ def part2 (input : String ): String =
127
+ val digPlan = for
128
+ case s " $_ $_ (# $color) " <- input.linesIterator
129
+ dir = Direction .fromInt(color.last)
130
+ len = BigInt (x = color.init, radix = 16 )
131
+ yield Trench (dir, len.toInt)
132
+
133
+ area(digPlan.toSeq).toString
134
+ ```
135
+
9
136
## Solutions from the community
10
137
11
138
Share your solution to the Scala community by editing this page.
0 commit comments