namespace Day16; public class Panel { private readonly Tile[,] _tiles; private readonly int _width; private readonly int _height; private readonly Dictionary _results = new Dictionary(); public Panel(Tile[,] tiles) { _tiles = tiles; _width = tiles.GetLength(0); _height = tiles.GetLength(1); } public int Energize(int x, int y, IRay start) { var result = Energize(new InitialVector(x, y, start)); Print(); return result; } public void MaximizeEnergy() { var max = 0; InitialVector? init = null; foreach (var v in InitialVectors()) { if (!_results.ContainsKey(v)) { var count = Energize(v); if (count > max) { max = count; init = v; } } } Console.WriteLine($"Initial Vector: {init?.X} / {init?.Y} => {init?.Ray}"); Console.WriteLine($"Energized: {max}"); } private void Print() { Console.WriteLine($"{_width} x {_height}"); for (var y = 0; y < _height; y++) { for (var x = 0; x < _width; x++) { Console.Write(_tiles[x, y].IsEnergized ? '#' : _tiles[x, y].Value); } Console.WriteLine(); } Console.WriteLine(); } private int Count() { var energized = 0; for (var y = 0; y < _height; y++) { for (var x = 0; x < _width; x++) { energized += _tiles[x, y].IsEnergized ? 1 : 0; _tiles[x, y].Clear(); } } return energized; } private int Energize(InitialVector vector) { var tile = _tiles[vector.X, vector.Y]; var stack = new Stack<(IRay Ray, Tile Tile)>(); stack.Push((vector.Ray, tile)); var result = new Result(); _results[vector] = result; while (stack.Count > 0) { var item = stack.Pop(); foreach (var r in item.Tile.Process(item.Ray)) { var next = Next(r, item.Tile); if (next == null) { var equivalentInitialVector = new InitialVector(item.Tile.X, item.Tile.Y, r.Rotate().Rotate()); _results[equivalentInitialVector] = result; } else { stack.Push((r, next)); } } } result.Energized = Count(); return result.Energized; } private Tile? Next(IRay ray, Tile tile) { var (x, y) = ray.Apply(tile); return x >= 0 && x < _width && y >= 0 && y < _height ? _tiles[x, y] : null; } private IEnumerable InitialVectors() { for (var x = 0; x < _width; x++) { yield return new InitialVector(x, 0, Rays.South); yield return new InitialVector(x, _height - 1, Rays.North); } for (var y = 0; y < _height; y++) { yield return new InitialVector(0, y, Rays.East); yield return new InitialVector(_width - 1, y, Rays.West); } } private record InitialVector(int X, int Y, IRay Ray); private class Result { public int Energized { get; set; } public IList InitialVectors { get; } = new List(); } }