Advent of Code (in MiniScript), Day 25

JoeStrout - Dec 25 '22 - - Dev Community

Welcome to the last of my series of 2022 Advent of Code solutions in MiniScript! Day 25, the final challenge for this year, was (as usual) delightfully whimsical and (very much not as usual) blissfully simple.

All we need to do is convert integer numbers between normal decimal format, and a format called "SNAFU". SNAFU is a base-5 format, but instead of using digits that represent the values 0 through 4, there are digits that represent 0, 1, 2, -1 (-), and -2 (=).

I started with the snafuToDec function, which converts a SNAFU number like 1=11-2 to its decimal equivalent, 2022 in this case.

values = {"2":2, "1":1, "0":0, "-":-1, "=":-2}

snafuToDec = function(s)
    power = 1
    result = 0
    for i in range(s.len - 1)
        result = result + values[s[i]] * power
        power = power * 5
    end for
    return result
end function
Enter fullscreen mode Exit fullscreen mode

This code works just like any other base conversion: you go digit by digit, starting with a place value of 1 for the rightmost digit, and increasing that by a factor of (in this case) 5 for place to the left. We just multiply each digit value by the place value, and add them up.

To convert the other way is a little more unusual. The standard conversion would be to take the number mod 5, write that down as a digit, then divide the number by 5 (rounding down) for the next digit. But in the case of SNAFU, if our number mod 5 is 3 or 4... we don't have digits for that.

The key is to think about that little "(rounding down)" detail I slipped in there. What's that actually doing? In reality it means we're subtracting the digit we just wrote down from the number. If we're converting 12, then we write down 2 (because 12 mod 5 is 2), and we subtract 12 - 2 to get a nice round 10. Then we can divide that 10 by 5 to get the next digit; no rounding required.

Put this way, we can do the same thing with SNAFU's weird negative digits. If our number mod 5 is 4, well then we'll write down - (i.e. -1) for this digit, but now we need to subtract -1 from our number — which is the same as adding one — before we divide by 5 for the next digit. Similarly, if our number mod 5 is 3, we'll write down = (-2), and then add 2 to our number.

The code came out like this.

decToSnafu = function(d)
    digits = []
    while d
        x = d % 5
        if x == 4 then
            digits.insert 0, "-"
            d = d + 1
        else if x == 3 then
            digits.insert 0, "="
            d = d + 2
        else
            digits.insert 0, str(x)
        end if
        d = floor(d / 5)
    end while
    return digits.join("")
end function
Enter fullscreen mode Exit fullscreen mode

The rest of the program is just reading the SNAFU inputs, converting them to decimal, and then converting the sum back to SNAFU.

Here's the complete program for Day 25.
if 1 then fname = "input.txt" else fname = "example.txt"
lines = file.readLines(fname)
if lines == null then
    print "Unable to read: " + fname
    exit
end if
if not lines[-1] then lines.pop

values = {"2":2, "1":1, "0":0, "-":-1, "=":-2}

snafuToDec = function(s)
    power = 1
    result = 0
    for i in range(s.len - 1)
        result = result + values[s[i]] * power
        power = power * 5
    end for
    return result
end function

decToSnafu = function(d)
    digits = []
    while d
        x = d % 5
        if x == 4 then
            digits.insert 0, "-"
            d = d + 1
        else if x == 3 then
            digits.insert 0, "="
            d = d + 2
        else
            digits.insert 0, str(x)
        end if
        d = floor(d / 5)
    end while
    return digits.join("")
end function

resultA = []

for line in lines
    dec = snafuToDec(line)
    print line + " → " + dec + " → " + decToSnafu(dec)

    resultA.push dec
end for

sum = resultA.sum
print "final answer (part A): " + sum + " → " + decToSnafu(sum)
Enter fullscreen mode Exit fullscreen mode

I came in 168th on this challenge. Almost top 100! But not quite.

Final Thoughts

This year was my first time participating in the Advent of Code challenge, and I really enjoyed it! My only regret is that the challenges drop late at night (10pm for me); I'm a morning person, and my brain is definitely not at its best at that time. But probably that means it's good exercise; we always grow the most when we stretch a little.

I decided to do this, in large part, to see how MiniScript would hold up to these varied challenges. I'm pleased to report that it did very well! In the handful of challenges that gave me a hard time, it was squarely my own fault, not any fault of the environment. I didn't run into any issues with numeric precision (all numbers in MiniScript are 64-bit floats), nor did I find any bugs or annoying limitations in MiniScript itself. MiniScript's high-level, syntax-light coding were a great tool for quickly banging out a solution.

The challenge did inspire some ideas for new libraries and library functions. Over the course of the month, I created an aoc module with a variety of general utility functions that may make their way into the standard Mini Micro library; as well as a search module, which will probably end up as its own repo.

Working in Mini Micro also made it easy to produce graphical, often animated visualizations of what's going on. I didn't generally do this while competing for time, but added them the next day. These visualizations are as fun to code as they are to watch.

You can find all my code — including solutions to all 25 challenges, and the visualization code where applicable — in my AoC-2022 repo on GitHub.

I really hope you've found this series useful, or at least interesting! And next year, if you decide to give Advent of Code 2023 a try, perhaps you'll use MiniScript too. You won't be disappointed!

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .