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!