01020304050607080910111213141516171819202122232425

Advent of Code

2023/15

Lens Library

in C#

by encse

Let's revisit the problem description here.

Part 1 was super simple. What's funny is that I saw a similar hash algorithm yesterday in someone else's solution, where he stored the hashes of the visited states instead of serializing it as a whole.

For the second part, I created a function that applies one statement to an array of boxes at hand. The signature is set up so that I can use it to Aggregate all steps seeded with an initial set of 256 empty boxes. We are transforming boxes to boxes while applying the steps in a row. The function passed as the third argument is used to extract the computing power from the final state of the box array.

I'm describing it in a functional way, but there is no purity under the hood. We are working with and modifying the same box objects during the process.

namespace AdventOfCode.Y2023.Day15;

using System.Collections.Generic;
using System.Linq;
using Boxes = System.Collections.Generic.List<Lens>[];

record Lens(string label, int focalLength);
record Step(string label, int? focalLength);

[ProblemName("Lens Library")]
class Solution : Solver {

    public object PartOne(string input) => input.Split(',').Select(Hash).Sum();

    // "funcionally imperative of imperatively functional", only for 🎄
    public object PartTwo(string input) =>
        ParseSteps(input).Aggregate(MakeBoxes(256), UpdateBoxes, GetFocusingPower);

    Boxes UpdateBoxes(Boxes boxes, Step step) {
        var box = boxes[Hash(step.label)];
        var ilens = box.FindIndex(lens => lens.label == step.label);

        if (!step.focalLength.HasValue && ilens >= 0) {
            box.RemoveAt(ilens);
        } else if (step.focalLength.HasValue && ilens >= 0) {
            box[ilens] = new Lens(step.label, step.focalLength.Value);
        } else if (step.focalLength.HasValue && ilens < 0) {
            box.Add(new Lens(step.label, step.focalLength.Value));
        }
        return boxes;
    }

    IEnumerable<Step> ParseSteps(string input) =>
        from item in input.Split(',')
        let parts = item.Split('-', '=')
        select new Step(parts[0], parts[1] == "" ? null : int.Parse(parts[1]));

    Boxes MakeBoxes(int count) =>
        Enumerable.Range(0, count).Select(_ => new List<Lens>()).ToArray();

    int GetFocusingPower(Boxes boxes) => (
        from ibox in Enumerable.Range(0, boxes.Length)
        from ilens in Enumerable.Range(0, boxes[ibox].Count)
        select (ibox + 1) * (ilens + 1) * boxes[ibox][ilens].focalLength
    ).Sum();

    int Hash(string st) => st.Aggregate(0, (ch, a) => (ch + a) * 17 % 256);
}

Please ☆ my repo if you like it!

© 2025 Advent of Code is a registered trademark in the US Images provided by Bing image creator