Advent of Code (in MiniScript), Day 25
Tags: miniscript, adventofcode, programming
Published: 2022-12-25 21:07:57

Welcome to the last of my [series](https://dev.to/search?q=JoeStrout%20%23adventofcode&sort_by=published_at&sort_direction=asc) of 2022 [Advent of Code](https://adventofcode.com/) solutions in [MiniScript](https://miniscript.org)!  [Day 25](https://adventofcode.com/2022/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
```

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
```

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

{% spoiler 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)
```
{% endspoiler %}

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](https://miniscript.org) 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](https://github.com/JoeStrout/AoC-2022/blob/main/lib/aoc.ms) module with a variety of general utility functions that may make their way into the standard Mini Micro library; as well as a [search](https://github.com/JoeStrout/AoC-2022/blob/main/lib/search.ms) 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](https://github.com/JoeStrout/AoC-2022) 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!