Advent of code 2021: Day 13

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.

Part 1

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));

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);

Part 2

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] = '⬜';

    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());

Solved! ⭐️⭐️


[1] Y-axis fold not in the middle of the paper

The full solution is available on GitHub.