my advent of code solutions
1namespace Solutions._2020;
2
3/// <summary>
4/// Day 11: <a href="https://adventofcode.com/2020/day/11" />
5/// </summary>
6public sealed class Day11SeatingSystem() : Day(2020, 11, "Seating System")
7{
8 public override object Part1()
9 {
10 var prev = new LifeGame(Input);
11
12 while (true)
13 {
14 var next = prev.StepPart1();
15 var same = true;
16 for (var i = 0; i < next.Grid.Length; i++)
17 if (!next.Grid[i].SequenceEqual(prev.Grid[i]))
18 {
19 same = false;
20 break;
21 }
22
23 if (same) break;
24 prev = next;
25 }
26
27 return prev.TotalSeated;
28 }
29
30 public override object Part2()
31 {
32 var prev = new LifeGame(Input);
33 while (true)
34 {
35 var next = prev.StepPart2();
36 var same = true;
37 for (var i = 0; i < next.Grid.Length; i++)
38 if (!next.Grid[i].SequenceEqual(prev.Grid[i]))
39 {
40 same = false;
41 break;
42 }
43
44 if (same) break;
45 prev = next;
46 }
47
48 return prev.TotalSeated;
49 }
50
51 private class LifeGame
52 {
53 private int _h, _w;
54 public char[][] Grid;
55
56 public LifeGame(IEnumerable<string> input)
57 {
58 Grid = input.Select(line => line.ToCharArray()).ToArray();
59 _h = Grid.Length;
60 _w = Grid[0].Length;
61 }
62
63 private LifeGame() => Grid = [];
64
65 public int TotalSeated =>
66 Grid.Sum(l => l.Count(c => c == '#'));
67
68 public LifeGame StepPart1()
69 {
70 var next = new LifeGame { _h = _h, _w = _w, Grid = Grid.Select(s => s.ToArray()).ToArray() };
71 for (var y = 0; y < _h; y++)
72 for (var x = 0; x < _w; x++)
73 next.Grid[y][x] = Grid[y][x] switch
74 {
75 'L' when CountAdjacent(y, x) == 0 => '#',
76 '#' when CountAdjacent(y, x) >= 4 => 'L',
77 _ => Grid[y][x],
78 };
79
80 // next.PrintBoard();
81 return next;
82 }
83
84 private char At(int y, int x) =>
85 x < 0 || y < 0 || x >= _w || y >= _h ? '.' : Grid[y][x];
86
87 private int CountAdjacent(int y, int x) =>
88 new[]
89 {
90 At(y - 1, x - 1), At(y - 1, x + 0), At(y - 1, x + 1), At(y + 0, x - 1), At(y + 0, x + 1),
91 At(y + 1, x - 1), At(y + 1, x + 0), At(y + 1, x + 1),
92 }.Count(c => c == '#');
93
94 public LifeGame StepPart2()
95 {
96 var next = new LifeGame { _h = _h, _w = _w, Grid = Grid.Select(s => s.ToArray()).ToArray() };
97 for (var y = 0; y < _h; y++)
98 for (var x = 0; x < _w; x++)
99 next.Grid[y][x] = Grid[y][x] switch
100 {
101 'L' when CanSee(y, x) == 0 => '#',
102 '#' when CanSee(y, x) >= 5 => 'L',
103 _ => Grid[y][x],
104 };
105
106 // next.PrintBoard();
107 return next;
108 }
109
110 private int CanSee(int y, int x) =>
111 new[]
112 {
113 TraceRay(y, x, -1, -1), TraceRay(y, x, -1, +0), TraceRay(y, x, -1, +1), TraceRay(y, x, +0, -1),
114 TraceRay(y, x, +0, +1), TraceRay(y, x, +1, -1), TraceRay(y, x, +1, +0), TraceRay(y, x, +1, +1),
115 }.Count(c => c == '#');
116
117 private char TraceRay(int y, int x, int dy, int dx)
118 {
119 y += dy;
120 x += dx;
121 while (y >= 0 && y < _h && x >= 0 && x < _w)
122 {
123 if (Grid[y][x] != '.') return Grid[y][x];
124 y += dy;
125 x += dx;
126 }
127
128 return '.';
129 }
130 }
131}