Problem description
The goal is to find a password that opens a safe, by following a list of instructions. The safe has a circular dial, with 100 positions, from 0 to 99. The instructions are rotations to the left (toward lower numbers, beginning with a L), or to the right (toward higher numbers, beginning with a R).
Part 1
In this part, the password is the number of times the dial points to 0 after a rotation.
I was a bit slow to solve this part, as I had not completely finished my preparation when the problem was unlocked.
Instruction parsing was very simple, thanks to pattern matching.
The “mathematical” part was a bit tricky, as the modulo (%) operator in Scala returns a negative number when the first argument is negative (this can happen for rotations to the left). For example, -25 % 100 returns -25 in Scala, and 75 in Python. I could have used the method Math.floorMod, but I was not aware of its existence, and I knew another way to get the desired result.
def solvePart1(input: List[String]): Int =
var dial = 50
var count = 0
for instruction <- input do
instruction match
case s"L$clicks" => dial = (dial - clicks.toInt + 100) % 100
case s"R$clicks" => dial = (dial + clicks.toInt) % 100
if dial == 0 then count += 1
count
Part 2
In this second part, the password is the number of times any click causes the dial to point at zero.
Fortunately, I understood the warning (“Be careful: if the dial were pointing at 50, a single rotation like R1000 would cause the dial to point at 0 ten times before returning back to 50!”) in the problem description.
My code was a bit more complex in the “left rotation” case, as I had to keep in memory the starting position, to avoid double counting.
def solvePart2(input: List[String]): Int =
var dial = 50
var count = 0
for instruction <- input do
instruction match
case s"L$clicks" =>
var nextDial = dial
nextDial -= clicks.toInt
if nextDial <= 0 then count -= (nextDial / 100 - 1)
if dial == 0 then count -= 1
dial = nextDial % 100
if dial < 0 then dial += 100
case s"R$clicks" =>
dial += clicks.toInt
count += dial / 100
dial %= 100
count
About the unit test.
I used the test case given in the problem description to build my unit test. But, in this test case, the number of clicks to the left or to the right is always inferior to 100. This is insufficient to prove the correction of the Part 2 code.
In a professional context, I would have added another test case, with clicks numbers greater than 100.
Scala leaderboard
This year, as there is no global leaderboard, so I decided to enter a private Scala leaderboard. After this first day, I am ranked fifth, out of 19 solvers.