# Advent of Code Day 6 Solved in C# and F#

December 10. 2015 0 Comments

- Posted in:
- Advent of Code
- C#
- F#
- LINQ

So I’m still just about managing to keep up with the Advent of Code challenges. Here’s me talking through my solution to day 6’s problem:

Here’s my solution to part a done in three stages in C#

var instructions = File.ReadAllLines("day6.txt"); var pattern = @"(turn on|toggle|turn off)\ (\d+)\,(\d+)\ through\ (\d+)\,(\d+)"; var instructionsFlattened = instructions .Select(i => Regex.Match(i, pattern).Groups) .Select(g => new { Action = g[1].Value, From = new { X = int.Parse(g[2].Value), Y = int.Parse(g[3].Value) }, To = new { X = int.Parse(g[4].Value), Y = int.Parse(g[5].Value) } }) .SelectMany(i => from x in Enumerable.Range(i.From.X, 1 + i.To.X - i.From.X) from y in Enumerable.Range(i.From.Y, 1 + i.To.Y - i.From.Y) select new { i.Action, x, y }); // apply the instructions var lights = new bool[1000, 1000]; foreach (var i in instructionsFlattened) { if (i.Action == "turn on") lights[i.x, i.y] = true; else if (i.Action == "turn off") lights[i.x, i.y] = false; else if (i.Action == "toggle") lights[i.x, i.y] = !lights[i.x, i.y]; } // count the lights on (from x in Enumerable.Range(0, 1000) from y in Enumerable.Range(0, 1000) where lights[x, y] select 1).Sum().Dump("lights on");

But I decided I wanted to solve this in a single LINQ expression, and this is possible using LINQ’s Aggregate method, so here’s part b solved in C# with Aggregate

File.ReadAllLines("day6.txt") .Select(i => Regex.Match(i, @"(turn on|toggle|turn off)\ (\d+)\,(\d+)\ through\ (\d+)\,(\d+)").Groups) .Select(g => new { Action = g[1].Value, From = new { X = int.Parse(g[2].Value), Y = int.Parse(g[3].Value) }, To = new { X = int.Parse(g[4].Value), Y = int.Parse(g[5].Value) } }) .SelectMany(i => from x in Enumerable.Range(i.From.X, 1 + i.To.X - i.From.X) from y in Enumerable.Range(i.From.Y, 1 + i.To.Y - i.From.Y) select new { i.Action, x, y }) .Aggregate(new int[1000,1000], (acc, next) => { var brightness = acc[next.x,next.y]; if (next.Action == "turn on") brightness+=1; else if (next.Action == "turn off") brightness = Math.Max(0, brightness - 1); else if (next.Action == "toggle") brightness += 2; acc[next.x, next.y] = brightness; return acc; }) .Cast<int>() // flattens a multi-dimensional array .Sum() // brightness is 14687245

And finally of course, as part of my on-going bid to improve my F# skills, I made an F# version of this solution:

let instructions = File.ReadAllLines("day6.txt") let turnOn n = n + 1 let turnOff n = max (n - 1) 0 let toggle n = n + 2 let selectAction = function | "turn on" -> turnOn | "turn off" -> turnOff | "toggle" -> toggle let parseInstruction actionSelector i = let pattern = @"(turn on|toggle|turn off)\ (\d+)\,(\d+)\ through\ (\d+)\,(\d+)" let groups = Regex.Match(i, pattern).Groups let action = actionSelector groups.[1].Value let fromPos = (int groups.[2].Value), (int groups.[3].Value) let toPos = (int groups.[4].Value), (int groups.[5].Value) (action, fromPos, toPos) let expandPositions (x0,y0) (x1,y1) = seq { for x in x0 .. x1 do for y in y0 .. y1 do yield (x,y) } let applyAction (acc:int[,]) (action,(x,y)) = acc.[x,y] <- action acc.[x,y] acc let calculate actionSelector (input:string[]) = let startState = Array2D.create 1000 1000 0 input |> Seq.map (parseInstruction actionSelector) |> Seq.collect (fun (action,fromPos,toPos) -> seq { for pos in (expandPositions fromPos toPos) do yield (action,pos) }) |> Seq.fold applyAction startState |> Seq.cast<int> // same trick works to flatten 2d array |> Seq.sum calculate selectAction instructions |> Dump let turnOnA n = 1 let turnOffA n = 0 let toggleA n = if n = 0 then 1 else 0 let selectActionA = function | "turn on" -> turnOnA | "turn off" -> turnOffA | "toggle" -> toggleA calculate selectActionA instructions |> DumpAs always, comments on ways I could improve my solutions are very welcome.

Want to learn more about LINQ? Be sure to check out my Pluralsight course More Effective LINQ.