Skip to main content

Advent of Code 2025 - Day 2

·2 mins
Before reading the solution, attempt to solve the problem on your own.

Part 1 #

Show solution

The core of the problem is to correctly identify the invalid ids. Once we have this, we can iterate over the list of ids and sum the invalid ones.

In part 1, an id is invalid if its first half is equal to its second half.
Here is the full solution:

open System.IO
open System

[<Literal>]
let INPUT = "input.txt"

let isInvalidId (id: bigint) =
    let idStr = id.ToString()
    if idStr.Length % 2 <> 0 then
        false
    else
        let halfLen = idStr.Length / 2
        idStr[..(halfLen-1)] = idStr[halfLen..]

let arrayOfRanges =
    (File.ReadAllLines INPUT |> Array.head).Split [|','|]
    |> Array.map (fun range -> range.Split [|'-'|] |> Array.map bigint.Parse)

let computeSum (ranges: bigint array array) =
    ranges 
    |> Array.map (fun range -> 
        seq { range[0] .. range[1] }
        |> Seq.filter isInvalidId
        |> Seq.sum)
    |> Array.sum

arrayOfRanges |> computeSum |> printfn "%A"

Part 2 #

Show solution

In part 2, the definition of an invalid id is different. An id is invalid if it’s only made of at least 2 repeated sequences of digits.

We’ll define two new helper functions:

let chunkByLen k (s:string) =
    s
    |> Seq.chunkBySize k 
    |> Seq.map (fun chars -> String chars)

let allEqual (chunks:seq<string>) =
    let head = Seq.head chunks
    Seq.forall ((=) head) chunks

chunkByLen splits the string into chunks of length k and allEqual checks if a sequence of strings are all equal. Then the new definition of isInvalidId becomes:

let isInvalidId (id: bigint) =
    let idStr = id.ToString()
    let halfLen = idStr.Length / 2
    seq {1..halfLen}
    |> Seq.exists (fun k -> chunkByLen k idStr |> allEqual)

We iterate over the possible chunk sizes and check if any of them splits the id into equal chunks. If so, the id is invalid. The rest of the implementation remains the same.