commit ba46c4a60107dfc1d3e1a741f97f4a43f3521aeb
parent 0609c12d75d3f721012696f2b3197b521e60e7b1
Author: Luís Ferreira <contact@lsferreira.net>
Date: Thu, 2 Dec 2021 20:23:06 +0000
posts: Add 'Zettelkasten #3: Solution in D for Advent of Code 2021, Day 2'
Signed-off-by: Luís Ferreira <contact@lsferreira.net>
Diffstat:
1 file changed, 109 insertions(+), 0 deletions(-)
diff --git a/content/posts/zet-3-aoc-2021-02.md b/content/posts/zet-3-aoc-2021-02.md
@@ -0,0 +1,109 @@
+---
+title: 'Zettelkasten #3: Solution in D for Advent of Code 2021, Day 2'
+date: '2021-12-02T19:02:00+01:00'
+tags: ['zettelkasten', 'zet', 'dlang', 'aoc', 'aoc2021', 'adventofcode']
+description: "This post describes, in detail, my solution in the D programming
+language for the 2nd puzzle of the Advent of Code 2021."
+---
+
+## The challenge
+
+> It seems like the submarine can take a series of commands like forward 1,
+> down 2, or up 3:
+>
+> - forward X increases the horizontal position by X units.
+> - down X increases the depth by X units.
+> - up X decreases the depth by X units.
+>
+> Note that since you're on a submarine, down and up affect your depth, and so
+> they have the opposite result of what you might expect.
+>
+> [...]
+>
+> Calculate the horizontal position and depth you would have after following
+> the planned course. What do you get if you multiply your final horizontal
+> position by your final depth?
+
+You can read the challenge more in depth,
+[here](https://adventofcode.com/2021/day/2).
+
+## Part 1
+
+The idea here is to fold the values and increment or decrement fields,
+depending on the given operations. First, to efficiently recognize the
+operations, we can just compare the first byte, since they are unique (`f` for
+forward, `d` for down and `u` for up). A simple split and map can do the trick,
+easily:
+
+```d
+auto parsed = input.map!split.map!"tuple(a.front[0], a.back.to!long)";
+```
+
+To fold the values in D we can use `fold` template. We need seed the fold with a
+tuple or a static array, starting at zero. Inside the fold we write the logic
+to increment or decrement the accumulator, according to the given rules:
+
+```d
+auto folded = parsed.fold!((a,b) { // fold the parsed input
+ b[0] == 'f' ? a[0] += b[1] // increment on forward
+ : b[0] == 'd' ? a[1] += b[1] // increment on down
+ : b[0] == 'u' ? a[1] -= b[1] : 0; // decrement on up
+ return a; })(tuple(0L,0L)); // seed it with zeros
+```
+
+And that's it, now you just need to multiply the result of the fold:
+
+```d
+auto res = folded[0] * folded[1];
+```
+
+### Full solution
+
+```d
+[stdin.byLine().map!split.map!"tuple(a.front[0], a.back.to!long)" // parse input
+ .fold!((a,b) { // fold the input
+ b[0] == 'f' ? a[0] += b[1] // increment on forward
+ : b[0] == 'd' ? a[1] += b[1] // increment on down
+ : b[0] == 'u' ? a[1] -= b[1] : 0; // decrement on up
+ return a; })(tuple(0L,0L))] // seed with zeros
+ .map!"a[0] * a[1]".front.writeln; // multiply result
+```
+
+## Part 2
+
+> Based on your calculations, the planned course doesn't seem to make any
+> sense. You find the submarine manual and discover that the process is
+> actually slightly more complicated.
+>
+> In addition to horizontal position and depth, you'll also need to track a
+> third value, aim, which also starts at 0. The commands also mean something
+> entirely different than you first thought:
+>
+> - down X increases your aim by X units.
+> - up X decreases your aim by X units.
+> - forward X does two things:
+> * It increases your horizontal position by X units.
+> * It increases your depth by your aim multiplied by X.
+>
+> [...]
+>
+> Using this new interpretation of the commands, calculate the horizontal
+> position and depth you would have after following the planned course. What do
+> you get if you multiply your final horizontal position by your final depth?
+
+
+The second part is pretty much the same as part one, except it uses an
+additional value in the fold and diffferent rules.
+
+### Full solution
+
+```d
+[stdin.byLine().map!split.map!"tuple(a.front[0], a.back.to!long)" // parse input
+ .fold!((a,b) { // fold the input
+ b[0] == 'f' ? a[0] += b[1] : 0; // increment on forward
+ b[0] == 'f' ? a[1] += a[2] * b[1] // multiply w/ aim on forward
+ : b[0] == 'd' ? a[2] += b[1] // increment aim on down
+ : b[0] == 'u' ? a[2] -= b[1] : 0; // decrement aim on up
+ return a; })(tuple(0L,0L,0L))] // seed with zeros
+ .map!"a[0] * a[1]".front.writeln; // multiply result
+```