/AoC-2022

My (normally refactored after I get the correct answer) answers for the 2022 Advent of Code

Primary LanguageSwift

AoC-2022

swift workflow codecov Sonarcloud Status

Advent Of Code (AoC) 2022

This are my solutions to the Advent Of Code 2022 event. This year I've been playing along with timsearle and Sfrost007, please check out their solutions if you're interested.

Project approach

This swift package manager project contains my MacOS command line tool, a framework with all of the logic to solve the puzzles and a test framework to validate against the AoC examples that are given in the puzzle descriptions.

The idea is to use the example problems/solutions provided in the puzzles to do TDD, but sometimes there are no examples that allow TDD.

This project requires a config.swift file to be created. This is the format of the file:

import Foundation

enum Config {
    static let year = 2022
    // This is the session cookie from your browser after logging in to https://adventofcode.com/
    static let session = "[TOKEN]"
}

Running

To run day 1:

  • Either create a file called day1.txt with your puzzle input, or add your AoC session cookie to the code and it'll be created automatically
  • Then run swift run AoC 1 in Terminal

Implementation notes

Day 1

Fairly trivial, the hardest part was parsing the input, but after that a few functional calls to spit the answer out.

Day 2

Todays challenge was modelling the input, I'm sure there's a simpler way, but I ended up parsing everything into enums and having functions to get a score based on comparing. I wrote the truth tables out manually though and there's a way to use the modulo operator instead I'm certain. I might come back and try agian (Narrator: He didn't).

Day 3

I had to write a few extensions to get the syntax that let me easily work out what I was doing, but after I'd done that I got some nice functional chains to work with to get the answer. I refactored many times to get types to resolve and I think there's too many force unwraps for my liking. Solutions worked first time though 🎉

Day 4

I basically exploited Swift's Ranges for this, so it was very easy once I'd parsed the input. I'd like to spend some more time parsing the input using functional chains rather than using a lot of temporary variables. Update: Simon put me onto a built in function for Part 2, and I tried to implement functional chains, but initializing the tuple was tricky. Update 2: After reading Tim's implementation I have now refactored it into barely understandable functional chains. Perfect.

Day 5

Todays was tricky parsing of the input and then the output was fairly trivial to get. Swift doesn't have the ability to split with a String, only a Character or CharacterSet so I used a temporary variable to flag if I encountered an empty line for speed. Then I reversed the stacks lines, poped the first line to get the count of stacks and initialised my 2 dimensional array, then used chunked to get each crate, checked if the Character at index 1 wasn't empty and built up an array for each stack. Moves were simply parsed into an struct so they could be accessed easily with names and a constructor to convert a string.

The first part was then creating a mutable copy of the stacks, loop to move each crate and then build the output string (just realising I should have used joined(by:)).

The second part was building an array of crates to move, reversed (so the last removed one goes back on last too) and then added back on to the appropriate stack.

This is the first question I've seen that has a String as the output so I've refactored my project to have a generic Day protocol and an associatedType for the output (which is inferred from the part1() and part2() return types).

Update: I refactored my parsing to be a lot more functional and use less temporary variables. I also removed the ducplication for the final parts and moved the core logic to a closure

Day 6

Using Swift's Ranges and Sets I was able to do this in just a few lines. Made a Range of numbers and moved through the Character array, converted the Array<Character> into a set and checked if it was still the same length. Added the length onto the current offset and returned it.

With my extra spare time I added some sanity checks to the initialization to cope with empty and input with no solution.

Day 14

Really enjoyable one today, I made a naieve solution to part 1 and it only finished in good time when I ran it as release (optimised). I refactored it so the lookups were hashed (in a Set) and it was very quick and then part 2 was as simple as adding an extra flag in my lookup function.

Day 15

Part 1 was a "ignore the visual and do the maths" question, although the visuals provided in the example really helped with solving!

Part 2 was a bit more challenging because the number of loops goes from about 10 million to many trillions. I worked out (after running my naieve solution for almost an hour) that the point we want to find will be at the manhatten distance + 1 from one of the sensors and we can just loop round each sensor to find which point isn't inside any others. Once it compiled it worked first time! 🎉