# Advent of Code Day 18–Game of Lights

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

The day 18 Advent of Code challenge basically requires us to create the Conway’s Game of Life algorithm and run it repeatedly on a 100x100 grid. See how I tackled this problem in C# and F# in this video:

I won’t post both parts of my C# solution as they were very similar, but here’s what I cam up with for part b. It probably could do with a bit of refactoring, but sadly time didn’t permit today:

var start = File.ReadAllLines("day18.txt"); var repetitions = 100; var state = start.Select(s => s.Trim().Select(c => c == '#' ? 1 : 0).ToArray()).ToArray(); Func<int, int, int> getLight = (x, y) => { if (x < 0 || x >= state.Length) return 0; if (y < 0 || y >= state[x].Length) return 0; if (x == 0 && y == 0) return 1; if (x == state.Length - 1 && y == 0) return 1; if (x == 0 && y == state[x].Length - 1) return 1; if (x == state.Length - 1 && y == state[x].Length - 1) return 1; return state[x][y]; }; Func<int, int, int> getNeighbourSum = (x, y) => getLight(x - 1, y - 1) + getLight(x, y - 1) + getLight(x + 1, y - 1) + getLight(x - 1, y) + getLight(x + 1, y) + getLight(x - 1, y + 1) + getLight(x, y + 1) + getLight(x + 1, y + 1); Func<int, int, int> getNextValue = (x, y) => { if (x == 0 && y == 0) return 1; if (x == state.Length - 1 && y == 0) return 1; if (x == 0 && y == state[x].Length - 1) return 1; if (x == state.Length - 1 && y == state[x].Length - 1) return 1; return getNeighbourSum(x, y) == 3 ? 1 : (getNeighbourSum(x, y) == 2 && getLight(x, y) == 1) ? 1 : 0; }; for (int a = 0; a < repetitions; a++) { var nextState = Enumerable.Range(0, state.Length) .Select(x => Enumerable.Range(0, state[x].Length) .Select(y => getNextValue(x, y)).ToArray()).ToArray(); state = nextState; } state.Sum(row => row.Sum()).Dump(); // 924

My F# version is similar except I did make the effort to write one bit of code to solve both parts of the solution, and I left the state as simply an array of strings. To avoid any use of mutable variables, I used `Seq.fold`

to repeatedly run the animate function to return the next state. I can’t help thinking there must be a nicer way to do this. Also, my F# solution performs quite poorly for part b, so could do with some optimisation (I think my `cornersOn`

method is probably a significant contributing factor).

let isOn (state:string[]) isStuckOn (x,y) = match x,y with | _,_ when x < 0 || y < 0 || x >= state.Length || y >= state.[x].Length -> false | _,_ when isStuckOn (x,y) -> true | _ -> state.[x].[y] = '#' let getNeighbourSum (state:string[]) isStuckOn (x,y) = [(-1,-1);(0,-1);(1,-1);(-1,0);(1,0);(-1,1);(0,1);(1,1)] |> Seq.map (fun (a,b) -> (x+a,y+b)) |> Seq.filter (isOn state isStuckOn) |> Seq.length let getNextValue (state:string[]) isStuckOn (x,y) = if isStuckOn (x,y) then '#' else match getNeighbourSum state isStuckOn (x,y) with | 3 -> '#' | 2 -> if isOn state isStuckOn (x,y) then '#' else '.' | _ -> '.' let animate (state:string[]) isStuckOn = [|for x in 0..state.Length-1 -> new System.String [|for y in 0..state.[x].Length-1 -> getNextValue state isStuckOn (x,y)|] |] let countLights (state:string[]) = state |> Seq.map (fun r -> r .Replace(".","").Length) |> Seq.sum let animated state n isStuckOn = [1..n] |> Seq.fold (fun s _ -> animate s isStuckOn) state let startState = "day18.txt" |> File.ReadAllLines let testState = [|".#.#.#";"...##.";"#....#";"..#...";"#.#..#";"####.."|] let cornersOn (x,y) = List.exists ((=) (x,y)) [(0,0);(0,99);(99,0);(99,99)] animated startState 100 (fun (x,y)->false) |> countLights |> printfn "a: %d" // a: 814 animated startState 100 cornersOn |> countLights |> printfn "b: %d" // b: 924