This article is part of a series where I'll be diving head first into the Advent of code 2021. I'll be documenting the challenge of solving such a puzzle and how I got to the answer. I want to prefix this by stating that I can't cheat for any of these challenges; with that, I mean I can't look up any other implementations online.
In this article I'll be solving: Advent of code 2021: Day #13.
The puzzle input this time around is a list of points, visualize the points on a piece of transparent paper and use the fold instructions. The first question is: how many points are left visible after the first fold?
I didn’t think this challenge was especially hard, after writing my initial code and after some refactoring I got to the resulting code down below:
use std::fs;
use std::collections::HashSet;
type Points = HashSet<(usize, usize)>;
type Folds<'a> = Vec<(&'a str, usize)>;
fn fold_paper(points: &mut Points, folds: &Folds, times: usize) {
for i in 0..times {
let (axis, value) = folds[i];
let height = points.iter().map(|n| n.1).max().unwrap();
let width = points.iter().map(|n| n.0).max().unwrap();
let mut folds: Points = HashSet::new();
let mut unfolds: Points = HashSet::new();
for (x, y) in points.iter() {
let val = if axis == "y" { *y } else { *x };
if val > value {
folds.insert((*x, *y));
} else if val < value {
unfolds.insert((*x, *y));
}
}
for (x, y) in folds {
let folded_point = if axis == "y" {
(x, height - y)
} else {
(width - x, y)
};
points.remove(&(x, y));
points.insert(folded_point);
}
}
}
The fold_paper
-method changes whatever HashSet
you pass to points
inline. It takes a set of folds
and the amount of fold instructions you want to execute on the points
set. It first determines the maximum x-value and maximum y-value. Next up, it makes two lists, a list of points above (or left of) the fold and a list of points below (or right of) the fold. The next step is to move over all the points below (or right of) the fold and move it’s y-value or x-value, depending on which axis the fold occurs. The points list needs to remove the initial point below (or right of) the fold and insert instead the new folded_point
. It can happen that folded_point
already exists in the list of points, but considering I’m using a HashSet, this duplicate will not get added to the set.
To resolve the first part all I had to write is:
let mut points_clone = points.clone();
fold_paper(&mut points_clone, &folds, 1);
assert_eq!(points_clone.len(), 17);
In the second part - and no surprises here - it asks to execute all the fold instructions. After doing so, an 8-letter code should appear when plotting the dots. This was a bit more tricky, but not because the code was hard, but more because the folds didn’t work. There was no other example in the puzzle, so I made my way to Reddit. It has a bug in the input, as this Reddit user points out [1]. I tricked the input, but you can also do it with a mod-check according to the thread.
Another funny thing happened where the code contained a letter V
in my case, which turned out to be a U
. To make it more clear, I used the black and white square-emoji’s to display the letter, but it made it even less clear. I’ll blame this on the limitations of using a 4x6 raster to display a letter in.
fn display_paper(points: &Points) {
let height = points.iter().map(|n| n.1).max().unwrap() + 1;
let width = points.iter().map(|n| n.0).max().unwrap() + 1;
let mut paper = vec![vec!['⬛'; width]; height];
for (x, y) in points {
paper[*y][*x] = '⬜';
}
println!("");
for line in paper {
let s: String = line.into_iter().collect();
println!("{}", s);
}
}
Code I wrote to execute the second part:
let mut points_clone = points.clone();
fold_paper(&mut points_clone, &folds, folds.len());
display_paper(&points_clone);
Solved! ⭐️⭐️
[1] Y-axis fold not in the middle of the paper
The full solution is available on GitHub.