We are all well aware (or should be) of the biggest problem humanity has ever faced: the global climate crisis. And it seems that Advent of Code wants to align as well: the excuse for this year’s adventure is a problem with the global snow production system. Well, what should we do?

The input is a calibration document that has been amended in a very creative way: it should contain only numbers, but some of them are spelled out with letters.

1abc2
pqr3stu8vwx
a1b2c3d4e5f
treb7uchet

The first task is relatively simple: for each row, we must reconstruct the number consisting of the first and last digits found on that row. So, in the example: 12, 38, 15, 77. The last number is repeated because the first and last digits coincide.

It’s a one-liner without too much fuss1:

#[[{1, -1}]]& /* FromDigits /@
  StringCases[StringSplit[day1, "\n"],
   x: DigitCharacter :> ToExpression@x] // Total

Steps:

  1. The StringCases[..., x: DigitCharacter :> ToExpression@x] is doing the extraction part: any digit character (0-9) is converted into an expression – that is, an integer, in this case. The result will be a list in which each element contains the digits found on a certain row.
  2. #[[{1, -1}]]& /* FromDigits /@ it’s a single function mapped onto the list of lists obtained above. The symbol /* is the right composition operator. It means that its right operand will be applied on the result obtained after applying its left operand.
    1. #[[{1, -1}]]& takes the first and last elements. If it’s a single item list, it takes the element twice.
    2. FromDigits constructs an integer from the list of its decimal digits.
    3. The last bit is the map operator /@.
  3. Lastly, we compute the total of the reconstructed numbers.

Part 2

Obviously, something is wrong; it cannot be that simple. We also have to consider the digits 0 to 9 written in letters. And we have to consider all of them. What does that mean? For example, oneight is 18. We cannot simply replace one β†’ 1, two β†’ 2, etc. because we would miss the adjacent overlapping digits.

First, we need to extract all the digits from a certain string. Only then we replace the various one with 1, two with 2, and so on.

The replacement rules are easy:

numberRules = Thread[IntegerName /@ Range[9] -> Range[9]]

Now, my function that parses a string and extracts the digits is:

ToExpression /@ (StringTake[s,
    StringPosition[s,
     Join[ToString /@ Range[9], IntegerName[Range[9]]]]] /.
   numberRules)
  1. Find the positions ({start, end}) of the digits 0-9, either as a number or in letters.
  2. Extracts all portions of the string that correspond to the positions found in step 1.
  3. At this point, it can apply numberRules and convert everything to numeric digits. ToExpression does the same thing as before: it normalizes strings representing numbers into integers.

The final solution is very similar to part 1, just with the insertion of the parsing function:

#[[{1, -1}]] &/*FromDigits /@
  findLetterDigits /@ StringSplit[day1, "\n"] // Total

findLetterDigits is the name I gave to the function.


I rated this first day 4 out of 10 in terms of difficulty. Pretty uncommon that part two of Day 1 is so difficult. Someone pointed out to me that it might have been on purpose to discourage a blatant use of AI to enter the global leaderboard.

I’ll collect my solutions in this public notebook on Wolfram Cloud.


  1. By dayN I will henceforth denote the raw input of a given day, as it can be downloaded from Advent of Code website. ↩︎