Skip to content

Instantly share code, notes, and snippets.

@runarorama
Last active December 8, 2019 12:42
Show Gist options
  • Save runarorama/21e6876bd62812b9d61a312c75ec87a3 to your computer and use it in GitHub Desktop.
Save runarorama/21e6876bd62812b9d61a312c75ec87a3 to your computer and use it in GitHub Desktop.
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.

.advent2019.day1> add

  ⍟ I've added these definitions:
  
    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)]

We can add those:

.advent2019> add

  ⍟ I've added these definitions:
  
    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

  ⍟ I've added these definitions:
  
    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

  ⍟ I've added these definitions:
  
    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

  ⍟ I've added these definitions:
  
    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

  ⍟ I've added these definitions:
  
    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

> answer

    3 | > answer
          ⧩
          3337766

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

.advent2019.day1> add

  ⍟ I've added these definitions:
  
    answer : Nat

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment