Advent of Code Day 14–Reindeer Races
Day 14 of the Advent of Code challenge saw us racing reindeer. Here’s my solution video as usual in C# and F#.
Here’s my C# code, after a bit of refactoring. I’m actually quite pleased with the way this came out in the end, and it was one of the more compact solutions for any of the languages on the advent of code subreddit, which is quite rare for C#. To help us solve part b, we need to track the progress of each reindeer in each second, and yet again MoreLINQ to the rescue with the Scan
method which is ideal for calculating running totals.
var lookup = File.ReadAllLines("day14.txt").Select(s => s.Split(' '))
.Select(g => new { Speed = int.Parse(g[3]), Duration = int.Parse(g[6]), Rest = int.Parse(g[13]) })
.Select(r =>
Enumerable.Range(0, 2503)
.Select(t => t % (r.Duration + r.Rest) < r.Duration ? r.Speed : 0)
.Scan(0, (a, b) => a + b).Skip(1).ToArray())
.ToArray();
lookup.Max(v => v[v.Length-1]).Dump("a"); // 2640
lookup.Max(v => v.Select((n,t) => n == lookup.Max(q => q[t]) ? 1 : 0).Sum()).Dump("b"); // 1102
And in F# I take the same approach. One slight niggle I have with F# is that the Seq.max
function doesn’t let you pass in a selector like LINQ’s equivalent, so I had to make my own (called smax
). In this example, it seems C# may just beat F# for conciseness (although of course I may be missing a few tricks).
let dist (speed,dur,rest) t = if t % (dur + rest) < dur then speed else 0
let progress n x = [0..n-1] |> Seq.map (dist x) |> Seq.scan (+) 0 |> Seq.skip 1 |> Seq.toArray
let lookup = "day14.txt" |> File.ReadAllLines |> Array.map (fun s -> s.Split(' '))
|> Array.map (fun a -> (int a.[3], int a.[6], int a.[13]))
|> Array.map (progress 2503)
let smax f = Seq.map f >> Seq.max
lookup |> smax (fun v -> v.[v.Length - 1]) |> printfn "a: %d" // 2640
let getPoints = Seq.mapi (fun t n -> if n = (lookup |> smax (fun f->f.[t])) then 1 else 0) >> Seq.sum
lookup |> smax getPoints |> printfn "b: %d" // 1102