AoC '20: Let's Get Swifty

AoC '20: Let's Get Swifty

Today's the day! The sun is shining, and the repository is clean! It's that time of year where we enjoy good food, share gifts, spread joy, and solve tough programming challenges. That's right, ladies and gents, it's time for Advent of Code 2020!

The Advent of Code is a yearly programming competition organised by Eric Wastl, the aim of which is to earn stars and save Christmas by solving a series of increasingly challenging problems. It often requires the player to think carefully about the requirements presented to them and to get creative with their solutions. Each challenge comes in two parts: The first introduces the problem, and the second adds a twist. Each year, I use the Advent of Code as an opportunity to learn a new programming language using practical exercises. Last year, I implemented my solutions in Kotlin.

This year, we're getting swifty. That is to say; I'll be using Apple's Swift programming language!

Day 1: Report Repair

As has been the case in years gone by, Eric eloquently sets the scene for us. After saving Christmas five years in a row, it's about time we took a well-earnt vacation. Christmas couldn't possibly fall apart without us, no sir. Our tropical destination uses a currency adorned with a starfish emblem, which we'll call stars.

Before we leave, however, the accounting Elves need our help fixing up the expense reports. We'll have to put that vacation on hold for a moment.

Part 1

The first thing the accounting Elves need us to do is find the two entries that sum to 2020 (fitting!) and multiply those numbers together to find our solution.

For example, given the following numbers:

1721
979
366
299
675
1456

We can see that the sum of 1721 and 299 is 2020, and therefore our answer would be 514579. Of course, our puzzle input is much longer.

An immediately obvious solution is to go over the list and, for each number, go over the list again. Doing so lets us find the sum of each pair and, once we've seen the correct couple, break out of the loop.

Another solution, and the one I favoured, is to sort our input in ascending order (that is, low to high), and sum the first and last numbers in the list like so.

var temp = expenses.sorted()
while (temp.first! + temp.last! != target) {
    /* ... */
}

Each time we sum the 'heads' of the list, we eliminate one of them: If the sum was above our target, we remove the last number, and if it was below, the first.

if temp.first! + temp.last! > target {
    temp.removeLast()
} else {
    temp.removeFirst()
}

Then, once we've found our candidates, we multiply them together to find our answer: 713184.

temp.first! * temp.last!

There we have it: An excellent, gentle start to this year's shenanigans.

Another solution would be to go over the list, subtracting each number from 2020. If the result is zero, we have our pairing: The number we tested, and the difference between it and 2020.

Part 2

Of course, it wouldn't be Advent of Code if the day's challenge didn't become needlessly complicated by the second half. Satisfied with our results, an Elf tosses us a star. The same Elf offers to reward us with a second star if we can find the three numbers in the report that meet the earlier criteria.

Tired and groggy, on an early December morning in cold Cambridge, UK, I decided to do this the quick — yet, conversely, slow — way.

We can start by making an assumption. Given that our target remains 2020, and we must use three numbers to reach it, we can eliminate all numbers greater than 1000.

let temp = expenses.filter { $0 < 1000 }

Here, we use Swift's built-in filter function to remove all values ($0) less than 1000. Additionally, we use let, rather than var. Variables set as let are immutable, whilst those set with var are mutable.

We now want to go over the list thrice. The first time, we'll start at the beginning and continue until the end. The second, we will begin with the number immediately following it and likewise run to the last. The third loop will mirror the second. Consider our earlier example.

1721
979
366
299
675
1456

The first loop will start with 1721, the second with 979 and the third with 366. Then, the third will loop over 299, 675 and 1456. Once it has finished, the second loop will move on to 366, and the third will repeat using the values 299, 675 and 1456. We can tabulate this for a visual.

A.  |B.  |C.
----+----+----+
1721|    |
    |979 |
    |    |366
    |    |299
    |    |675
    |    |1456
    |366 |
    |    |299
    |    |675
    |    |1456
     ...

We rinse and repeat this until we have either found the solution or computed each unique, ordered combination.

var result: Int? = nil
loop: for a in 0..<temp.count {
    for b in (a + 1)..<temp.count {
        for c in (b + 1)..<temp.count {
            let ea = temp[a],
                eb = temp[b],
                ec = temp[c]
            if (ea + eb + ec == target) {
                result = ea * eb * ec
                break loop
            }
        }
    }
}

Note the prefix to the first loop. This label enables us to break out from the inner-most loop once we have found our answer.

After some intense accounting, we find that the product of our values adding up to 2020 is 261244452. Put your feet up, whip out that sun hat and enjoy a mince pie. It's time for a vacation.

Complete code

For me, Advent of Code is a learning experience. A new language and, often, new techniques and concepts are absorbed each day. I'll make my code for each solution available each day, for your leisurely perusal. Hopefully, you can learn something too! You can find the code for todays solution here.

Show Comments