highlights
Dec 20, 2022

The Unison Advent-of-Code mega writeup

Rebecca Mark

We've been blown away by the creativity and ingenuity of the Advent of Code 2022 solutions that have been shared by members of the community. In a surprising and unprompted gesture of generosity, many community members have taken the time to annotate their solutions with README's describing their thought processes and algorithms. We love seeing the community come together to share their work and learn from each other.

Advent of Code has brought a lot of new faces to the Unison community. Welcome! We're happy you're here! It has also brought a lot of fresh base library functions and data type libraries into being. We're grateful for the contributions of the community in helping us to fill in the gaps.

In celebration of the season, we've collected a smattering of of our favorite solutions. Here's to you! 🥂

The remainder of this post contains spoilers for the Advent of Code 2022 puzzles. We've tried to highlight unique solutions and illuminating writeups. Often, we present multiple approaches to solving the puzzles from the community so you can see the diverse and brilliant (and at times comical) minds at work in Unison. There were a lot to choose from so the selection here is somewhat arbitrary. The links and notes are hidden behind a folded doc, so you can choose whether to peek or not if you intend to catch up.

Day 1: Calorie Counting with Stew O'Connor 🔢

Day 1: Calorie Counting with Stew O'Connor 🔢

If you thought Day 1 was gonna be quick, you should know, we can turn most exercises into a chance to yak-shave.

We love Stew O'Connor's solution to Day 1 because he used the input parsing step as an opportunity to improve the Uniparsec library. As a result of this puzzle, the Uniparsec library can parse input directly into a Monoid data type. The advent of code day 1 README explains these changes in detail.

Day 2: Rock Paper Scissors with Rebecca Mark 📃

Day 2: Rock Paper Scissors with Rebecca Mark 📃

Advent of Code Day 2 is a game of Rock Paper Scissors with a twist. The twist is that the rules of the game are encoded in a text file and you're given varying strategy guides to determine your response.

Often, half of challenge of Advent of Code is parsing the input. This month offered a timely opportunity to update this abilities based parser library hosted on Unison Share. With this parser, we can do things like parse a line of input directly into datatypes that model the game play for easy scoring. That's what this solution, written by yours truly does for parts 1 and 2.

Day 3: Rucksack Reorganization with Chris Penner and company 🎒

Day 3: Rucksack Reorganization with Chris Penner and company 🎒

Day 3 we did as part of community coding livestream with Unison team member Chris Penner! We had a lot of fun solving this one together! You can watch the recording below.

Day 4: Camp Cleanup with Calvin Sauer 🏕

Day 4: Camp Cleanup with Calvin Sauer 🏕

We love this solution to Day 4 by Calvin Sauer. It's a wonderful example of how to use the newly added NatSet data type to solve the problem of identifying whether a range of values fully contains another. A NatSet is a Set which is optimized for containing Nat elements, so you might reach for this datatype instead of the generic Set next time your code requires storing Nat elements or things that can be encoded as Nat elements.

Day 5: Crates with Jemma Nelson 📦

Day 5: Crates with Jemma Nelson 📦

Advent of Code Day 5 is a puzzle about moving groups of crates around using cranes.

This solution and documentation by Jemma Nelson is one of our favorites. Highlights include finding and using the jsonschema.lib.base.data.List.transpose function for rotating the crates and a handy recursive function for moving the crates around. We love that others can follow along using the writeup, or shall we say, we are very... crateful for it! 🎁

(I'm sorry, I will see myself out.)

Day 6: Tuning Trouble with Calvin Sauer and Rúnar Bjarnason 🤳

Day 6: Tuning Trouble with Calvin Sauer and Rúnar Bjarnason 🤳

Day 6's Advent of Code puzzle involved finding characters in an input string that did not repeat in a given window.

Rúnar's solution used the Stream ability to inspect the input, also prompting some new functions in the standard library. His day 6 README goes into depth to explain the new window function.

For a creative optimized O(n) solution, Calvin Sauer's solution walks the character input with a Map, incrementing and decrementing a count of characters until a duplicate is found.

Day 7: No Space Left with Rúnar Bjarnason and Stew O'Connor 🗄

Day 7: No Space Left with Rúnar Bjarnason and Stew O'Connor 🗄

For Day 7's puzzles We needed to model a file system, with information about files, sub-directories, and file sizes provided by a log of commands as our textual input.

This solution by Rúnar Bjarnason uses a Zipper to traverse the directory tree structure as its being parsed! Zippers are data structures that consist of a focus and some surrounding context. The focus is the current node in the tree, and the context is the rest of the tree. With a zipper over the directory tree, you can do things like move up and down the file system, add information as it's revealed, and keep track of what directory nodes you've visited. Check out Rúnar's day 7 README for more about the TreeZipper data type he used.

As a result of this puzzle, we even have a new data structure library for you all to enjoy: Rose Trees and Zippers. 🌹

If zippers aren't your thing. Stew's solution uses a Map as the data backing for the directory tree structure. After the input is parsed, the Map is updated with new information about the file system. If you're ever curious about the Pattern API for parsing text, this README contains a fantastic example.

Day 8: Treetop Tree House with Cody Allen 🌲

Day 8: Treetop Tree House with Cody Allen 🌲

Day 8 gave us the hights of a forest of trees in a grid. We needed to identify which trees in the forest were visible from north south east and west given their height.

Cody's ingenious solution to Day 8 features a glorious writeup. Chief among the innovations here is that rather than writing separate functions to identify visible trees in each direction, Cody rotated the whole forest 90 degrees. Herculean! 🏆

Day 9: Rope physics with Saif, Rúnar, Cody, Calvin, Jan, and Joe 🪢

Day 9: Rope physics with Saif, Rúnar, Cody, Calvin, Jan, and Joe 🪢

A number of folks came up with similar solutions to Day 9's puzzles by writing functions that move the head of the rope one step and subsequently update the tail, you can read Rúnar's solution writeup, Cody's solution writeup, Saif's solution writeup, Jan's solution writeup and Joe's solution writeup for their generous explanations. For a slight variation, Calvin's solution to the rope physics puzzle simplifies the calculation of the location of the rope by parsing the input as a delta representing the direction of the rope's movement.

😆 This puzzle inspired some real gems:

  • "Assume a spherical rope in an ideal vacuum" - Joe Harrison
  • "I'm revising history and writing this as though I used Int from the beginning" - Cody Allen
  • "The only difference with part 2 is that we need to calculate the tail of the tail of the tail... ten times" - Saif Elokour
  • "Rope physics. Yay." - Calvin Sauer

Day 10: Cathode-ray tube featuring Joe Harrison and Calvin Sauer 📺

Day 10: Cathode-ray tube featuring Joe Harrison and Calvin Sauer 📺

🐣 What's a cathode ray tube? Just kidding, Unison is a young language but we remember the cathode ray tube's familiar buzz.

This puzzle involved calculating the value of a signal at specific intervals in a sequence of clock "ticks" or cycles.

Both This solution by Joe Harrison and this solution by Calvin Sauer are great examples of understanding the constraints of the domain being modeled and simplifying it to make subsequent computations more straightforward. Check them out, they are very clever!

Day 11: Monkey in the Middle with ChatGPT 🐵

Day 11: Monkey in the Middle with ChatGPT 🐵

What were these monkeys doing? Day 11's instructions were wild.

The real galaxy-brained problem solving innovation from the Unison community is that Rúnar fed the instructions into ChatGPT. 🤖 The puzzles for Day 11 became much more intelligible afterwards.

Here's what part 1 of the problem is in plain English:

"Four lists are given, each with a set of starting items and an operation that changes the item’s value. After the operation is applied, the item is tested based on a specified value. If the test is true, the item is appended to a specified list. If the test is false, the item is appended to a different specified list. The process repeats until all lists have had an iteration. Each time an item is inspected, its value is divided by three and rounded down before the next operation is applied.

The above process repeats for 20 iterations. After 20 iterations, the total number of items that were processed by each list are tallied. The number of items processed by the two most active lists are multiplied together, and this number is the answer."

Thank you, ChatGPT. 🙏

Day 12: Hill climbing with Dijkstra and company 🌄

Day 12: Hill climbing with Dijkstra and company 🌄

We did not expect anyone to implement graph traversal algorithms for us as a result of Advent of Code! (Or maybe we did, and Advent of Code is a ruse to generate more useful code examples for everyone. 🥸)

Day 12 involved finding the shortest path between two points on a hilly terrain.

This set of puzzles inspired a variety of approaches, some of which we've highlighted below.

This solution by Calvin Sauer is an implementation of the A* search algorithm. Thanks Calvin! That's sure to come in handy in the future!

Another solution used Breadth First Search to solve the problem. You can read a fantastic walk through of the algorithm and solution here in Joe Harrison's day 12 README.

Saif Elokour wrote a brain melting hill-climbing approach that you should check out as well.

And finally, what would Advent of Code be without a solution that uses Dijkstra's algorithm? Check out this implementation by Rúnar Bjarnason to see what that looks like in Unison.

Day 13: Distress signal with Eduard Nicodei 🗼

Day 13: Distress signal with Eduard Nicodei 🗼

We really enjoyed this solution by Eduard Nicodei to Day 13's puzzles because it truly embodies the spirit of Unison's Advent of Code. To learn more about Unison ability-based parsers, Eduard wrote a whole mini parser combinator library based on an existing library in Unison. In addition to explaining the puzzle solutions, the README contains a full explanation of how the Parse ability works so that others can learn about it. Amazing! 🥲

Day 14: In the Regolith Reservoir with the Unison community ⏳

Day 14: In the Regolith Reservoir with the Unison community ⏳

Day 14 of Advent of Code involved calculating the number of falling sand units in a cave filled with rocky obstacles.

A number of solutions modeled the cave with a Map (Nat, Nat) Cell data structure where the Cell was either a Rock, Sand, or Empty. Check out this amazing writeup for a map-backed implementation by Unison community member Eduard who also wrote a custom "cave viewer" function.

We also live-coded this one together in a Community day stream.

A notably different implementation was Rúnar's cave algorithm, which used a mutable ByteArray data type and a runloop to track the units of fallen sand.

This implementation has a number of performance optimizations. First, storage of the "cell" value is made more compact by using a ByteArray rather than a data type like List a where it's possible to store any type. Second, usage of a flat array allows for fast random access and array element updates. It might seem non-intuitive to map a 2D grid into a list-like data structure, but to do this you can use an indexing scheme based on the row length and the desired (x,y) coordinates. Your array index from coordinates can be calculated as index = x * rowLength + y. Very cool, Rúnar! 🤩

Day 15: Advent of Code Day 15: Beacon Exclusion Zone with Joe Harrison

Day 15: Advent of Code Day 15: Beacon Exclusion Zone with Joe Harrison

For Day 15 we were given a grid of beacons and signals and tasked to find the locations where the beacons could not be located for a certain row.

We are in awe of the curiosity and care evident in these explanations of your work. Take a look at Joe Harrison's day 15 README it's replete with diagrams, examples, and links to other resources.

Day 17: Pyroclastic Flow - Rúnar shares some bitwisdom 🪨

Day 17: Pyroclastic Flow - Rúnar shares some bitwisdom 🪨

Day 17's puzzle looked a bit like Tetris; rocks were stacking on top of one another in a long tunnel whilst being buffeted back and forth by jet streams.

It sounds like Rúnar worked hard to develop his solution solution and offered this hint: "this solution is completely insane, I decided to represent each 8x8 block of the tunnel as a Nat. This was my first mistake"

Duly noted, Rúnar.

Day 18: Boiling Boulders with Joe Harrison 🌋

Day 18: Boiling Boulders with Joe Harrison 🌋

For Day 18, we needed to calculate the surface area of lava cubes in a 3D grid given x, y, and z coordinates. If, like me, you think imagining lava voids in three dimensional space is a little mind melting, you might find this solution and thorough write-up by Unison community member Joe Harrison especially refreshing.

This solution collects the coordinates of the lava cubes in a Set and then finds their Von Neumann neighborhood along the three axes. We won't spoil everything here, This solution writeup is 🤌. Really, you should read it, but suffice to say we're impressed with the elegance of this solution.