Learning Python with Advent of Code Walkthroughs

Dazbo's Advent of Code solutions, written in Python

Wrapping Presents

Advent of Code 2015 - Day 2

Day 2: I Was Told There Would Be No Math

Useful Links

Concepts and Packages Demonstrated

Regular Expressions (Regex)DataclassessortedComprehensionssum

Problem Intro

The elves need more wrapping paper.

We’re given the dimensions (length, width, height) of a list of presents, where dimensions are given in feet. E.g.


Every present is a rectangular cuboid, so we know the surface area is given by 2(lw + wh + lh). That’s because the cuboid is composed of three pairs of opposite faces. So we work out the area of each of three different faces, add them together, and then multiply by two.

Part 1

The elves need enough paper to wrap all the presents. They require some extra paper for contingency: the area of the smallest side of each present.

How many total square feet of wrapper paper should they order?

This is easy enough to work out. We need to calculate the total surface area of each present, which we already know the formula for. And then we need to add the surface area of the smallest side. This will be determined by the product of the two shortest sides.


from dataclasses import dataclass
import os
import time
import re

SCRIPT_DIR = os.path.dirname(__file__) 
INPUT_FILE = "input/input.txt"
SAMPLE_INPUT_FILE = "input/sample_input.txt"

The only thing worth mentioning here is two imports, which we didn’t use in Day 1:

The Box

First, let’s create a class to represent our present:

class Box():
    """ Cuboid """
    width: int
    height: int
    length: int
    def __init__(self, dims: list) -> None:
        sorted_dims = sorted(dims)
        self.width = sorted_dims[0]
        self.height = sorted_dims[1]
        self.length = sorted_dims[2]
    def area(self):
        return 2*(self.width*self.height + self.width*self.length + self.height*self.length)
    def contingency(self):
        """ Contigency is the same as the area of the smallest face """
        return self.width * self.height

Solving the Problem

Now we’re ready to solve the problem!

def main():
    # input_file = os.path.join(SCRIPT_DIR, SAMPLE_INPUT_FILE)
    input_file = os.path.join(SCRIPT_DIR, INPUT_FILE)
    with open(input_file, mode="rt") as f:
        data = f.readlines()

    boxes = get_boxes(data)

    paper = sum(paper_required(box) for box in boxes)
    print(f"Paper required: {paper}")

def paper_required(box: Box):
    return box.area + box.contingency

def get_boxes(data) -> list[Box]:
    boxes = []

    p = re.compile(r"(\d+)x(\d+)x(\d+)")
    for line in data:
        if match := p.match(line):
            dims = list(map(int, match.groups())) # dims as list of int

    return boxes

Part 2

We’re told we also need to order ribbon. The amount of ribbon required is given by:

How much ribbon do we need to order?

Solving the Problem

We don’t need to do much here. We just need to add a new function that:

Our new function looks like this:

def ribbon_required(box: Box):
    ribbon_length = 2*box.width + 2*box.height
    bow_length = box.volume # we're told box length will be the same as the volume

    return ribbon_length + bow_length

And we call it using a list comprehension, just as we did before:

    ribbon = sum(ribbon_required(box) for box in boxes)
    print(f"Ribbon required: {ribbon}")


Paper required: 1606483
Ribbon required: 3842356
Execution time: 0.0030 seconds