{{ message }}

Instantly share code, notes, and snippets.

# runarorama/day1.markdown

Last active Dec 8, 2019
Advent of Code (Unison Edition), day 1

# Advent of Code 2019, in Unison

Spoilers for Advent of Code 2019 follow.

## Day 1: The Tyranny of the Rocket Equation

Fuel required to launch a given module is based on its mass. Specifically, to find the fuel required for a module, take its mass, divide by three, round down, and subtract 2.

This describes a simple function. There seems to be an oversight in the problem statement that modules with very low mass have a negative fuel requirement. I'm going to assume that's not right, and that instead of integer subtraction, we want natural number subtraction (sometimes called "monus"). In Unison, we can use the `Nat` type instead of integers, so we don't have to consider negatives. The subtraction operation is called `drop`:

``````fuelRequirement : Nat -> Nat
fuelRequirement mass = mass / 3 `drop` 2
``````

Let's add that to the codebase:

``````  ☝️  The namespace .advent2019.day1 is empty.

fuelRequirement : Nat -> Nat

``````

We're given some test cases. I'm just going to represent these as pairs where the first element is the input and the second is the expected output.

``````day1.testCases = [(12, 2), (14, 2), (1969, 654), (100756, 33583)]
``````

``````.advent2019> add

day1.testCases : [(Nat, Nat)]

``````

Let's add a test that checks that our `fuelRequirement` function passes these cases. First, I want to add a helper function that checks a given test case, turning it into a Boolean:

``````checkCase f tc = case tc of (i, o) -> f i == o
``````
``````.advent2019> add

checkCase : (i ->{𝕖} o) -> (i, o) ->{𝕖} Boolean

``````

And then a function that checks a whole list of cases. To do this, I use the `forAll` function from `base.test`. This takes a `Nat`, which is the maximum number of test cases to run, and a `Domain`, which is the set of values from which to generate test cases. A domain can be `Small`, in which case it's just an exhaustive list of cases. So I just make a `Small` domain from the cases we were given:

``````use .base.test.internals.v1.Test forAll

checkAll : (a -> b) -> [(a, b)] -> [Result]
checkAll f cases = forAll (List.size cases) (Small cases) (checkCase f)
``````
``````.advent2019> add

checkAll : (a ->{𝕖} b) -> [(a, b)] ->{𝕖} [Result]

``````

Now we can write the actual test very simply:

``````test> day1.test = checkAll fuelRequirement testCases
``````
``````
1 | test> day1.test = checkAll fuelRequirement testCases

✅ Passed : Proved.

``````

The test seems to pass. Let's add it:

``````.advent2019> add

day1.test : [Result]

``````

Now that we have a working `fuelRequirement` function, we can add together the results of applying it to every value in the test input. First let's add that test input (I just pasted it into my text editor and added commas):

``````day1.data =
[ 68958,
82218,
54333,
59177,
51874,
100259,
95468,
124006,
75078,
113631,
90315,
147580,
68233,
81025,
133084,
90959,
81196,
92443,
124832,
65871,
57704,
140203,
113053,
76337,
72195,
115917,
87843,
131768,
105816,
131153,
59714,
94107,
50933,
139545,
94969,
149463,
60042,
66028,
111190,
63257,
50020,
88783,
81428,
73977,
149240,
137152,
74738,
55067,
128829,
56465,
81962,
67242,
94121,
92303,
68477,
88595,
64324,
82527,
134717,
140344,
132026,
137558,
95643,
79010,
146346,
86246,
52341,
147564,
89159,
66456,
83190,
128675,
130658,
122857,
134538,
122151,
133900,
117462,
117791,
139254,
86366,
66165,
92897,
121218,
135962,
143061,
129220,
114623,
98257,
76722,
121014,
77713,
137858,
133282,
103595,
118981,
149137,
101141,
70765,
141113 ]
``````
``````.advent2019> add

day1.data : [Nat]

``````

The puzzle asks for the sum of the `fuelRequirement` for all these inputs. That's easy:

``````answer = foldl (acc x -> fuelRequirement x + acc) 0 data

``````
``````
⧩
3337766

``````

We can store the answer in the codebsase if we like:

``````.advent2019.day1> add