Advent of Code 2025 - Day 1
Part 1 #
Show solution
First, we define some helpful constants.
let FILE = "input.txt"
let MAX_DIAL = 100
In F# the % operator does not perform a true mathematical modulo operation where the result has the same sign as the divisor.
Therefore we will define a custom operator to perform the mathematical modulo operation. We will need this later when we define the function to calculate the final position of the dial.
let (%%) a b = (a % b + b) % b
We read all the lines from the input file and map them to an array of integers where we use the following encoding:
- a left rotation
Lwill be encoded as a negative integer - a right rotation
Rwill be encoded as a positive integer
let rotations =
File.ReadAllLines FILE
|> Array.map (fun line ->
let number =
let n = int line[1..]
match line[0] with
| 'L' -> -n
| _ -> n
number)
Finally, we define the getPassword function that takes the rotations array and returns the password.
Note the use of the %% operator. After each new dial, we verify if it points at 0. If it does, we increase countZero by one and then the fold operation continues with the next rotation.
let getPassword rotations =
((50, 0), rotations)
||> Array.fold (fun (dial, countZero) rotation ->
let newDial = (dial + rotation) %% MAX_DIAL
let atZero = if newDial = 0 then 1 else 0
newDial, countZero + atZero)
At the end just print the second element of the tuple returned by the getPassword function.
printfn "Result %d" (rotations |> getPassword |> snd)
Part 2 #
Show solution
The only thing that gets modified in the second part is the getPassword function.
This time we need to count the number of full rotations performed by the dial and then verify if there is any partial rotation that goes over 0.
We compute the partial rotation with the % operator because we don’t want to lose the sign of the rotation. Remember that we encoded the direction of the rotation in the sign of the integer.
A valid partial rotation that goes over 0 is one that does not start at 0 but ends at or goes beyond 0. In our case MAX_DIAL is equivalent to 0.
let getPassword rotations =
((50, 0), rotations)
||> Array.fold (fun (dial, countZero) rotation ->
let newDial = dial + rotation % MAX_DIAL
let overZero = if dial <> 0 && (newDial <= 0 || newDial >= MAX_DIAL) then 1 else 0
let cycles = rotation / MAX_DIAL |> System.Math.Abs
newDial %% MAX_DIAL, countZero + overZero + cycles)