Skip to main content

Advent of Code with Azure Bicep

·765 words·4 mins
Azure Bicep Advent-of-Code

Last year I made an attempt to solve Advent of Code problems using Azure Bicep. To start off, I want to say that this is not the correct tool to use for these kinds of problems. But it is fun!

A lot has happened with Azure Bicep during the past year. Most notably the introduction of lambda functions. Specifically this change introduced four new functions in Bicep: filter(), map(), reduce(), and sort(). I believe these functions makes it possible to solve a lot more problems in this years Advent of Code compared to last year.

I am not planning on actually attempting to solve all the problems using Azure Bicep. But to illustrate what it actually means to solve a problem using Azure Bicep I will pick the first part of the first problem and solve it right here and now.

Problem to solve
#

I won’t repeat the exact formulation of the problem here, you can go to Advent of Code to read the full story. What it comes down to is that you are given an input of the following format:

<number>
<number>
<number>

<number>
<number>

<number>
...

There are multiple groups of numbers, where each group contains an arbitrary number of numbers, and each group of numbers are separated from the next group by a blank line. What you want to do is to sum the numbers in each group, and then find the group with the highest sum.

Inputs
#

How to handle the puzzle inputs in Azure Bicep? Luckily Bicep provides a function called loadTextContent() that I use for this purpose:

var input = loadTextContent('input.txt')

Next I clean the input a bit because it contains trailing whitespace which would cause problems later:

var cleanInput = trim(input)

Next I split the input into groups of numbers by using the split() function with a \n\n delimiter (i.e. two newline characters in a row).

var splitInput = split(cleanInput, '\n\n')

Now I am satisfied with how the input looks. What does it look like by the way? It is one long array of strings that looks something like this:

['1\n2\n3', '43\n14\n2\n77\n1', ...]

Computing the answer
#

Now I need to compute the answer. I will use map(), reduce(), split(), and int() to find the answer. First of all I will map() through each element in my splitInput array. For each element I will run a reduce() function that first of all split()s the array element on the \n character to get the actual integers (as strings), it will go through each integer and add it to a starting sum of 0, converting the string representation of the integer to an actual integer using int(). What this looks like in full is this:

var sumOfGroups = map(
    splitInput,
    i => reduce(
        split(i, '\n'),                // input array
        0,                             // initial value
        (cur, next) => cur + int(next) // reducer function
    )
)

What I now have is a variable called sumOfGroups that is a simple array of integers. Finding the right answer is now simply to find the largest number in the array.

Producing an output
#

How to get an output from Bicep? If you solved Advent of Code problems using any other programming language you would simply log the answer to standard output at the end and that would be that. In Azure Bicep you have to deploy your Bicep template to Azure to actually get the answer. But before you do that, you have to define what your output is.

I add an output where I find the answer with the max() function:

output answer int = max(sumOfGroups)

The complete solution
#

Putting it all together, and combining a few lines, I have the following Bicep template that solves the first part of the first problem of Advent of Code 2022:

var input = split(trim(loadTextContent('input.txt')), '\n\n')
output maxValue int = max(
  map(
    input,
    i => reduce(
      split(i, '\n'),                 // input array
      0,                              // initial value
      (cur, next) => cur + int(next)) // reducer function
  )
)

It’s not pretty, it is a bit low-level, but it is a clear improvement from last year.

Caveats
#

Last year I discovered a major problem that was a bit annoying. If the input is too large then Bicep will complain. How can you solve that? With a combination of splitting the input into several smaller parts, using modules in Bicep, and perhaps event doing a multi-step deployment of some sort. It is not pretty, it might require some manual intervention.

All other caveats I discovered last year have been removed with the introduction of lambda functions.

Mattias Fjellström
Author
Mattias Fjellström
Cloud architect · Author · HashiCorp Ambassador