using System.Text; namespace Day14; public class BoulderMap { private readonly char[][] _lines; private readonly IAxis _north; private readonly IAxis _east; private readonly IAxis _south; private readonly IAxis _west; private readonly Dictionary _keyMap = new Dictionary(); public BoulderMap(IList lines) { _lines = lines.Select(l => l.ToCharArray()).ToArray(); _north = new NorthSouth(_lines, 1); _east = new EastWest(_lines, -1); _south = new NorthSouth(_lines, -1); _west = new EastWest(_lines, 1); } public int CalculateMaxNorthLoad() { return CalculateDirectionalLoad(_north); } private int CalculateDirectionalLoad(IAxis axis) { var load = 0; foreach (var s in axis.SecondaryRange) { var free = axis.PrimaryRange.First(); foreach (var p in axis.PrimaryRange) { switch (axis.Get(p, s)) { case 'O': if (p != free) { axis.Swap(p, free, s); } load += axis.NorthLoad(free, s); free += axis.Delta; break; case '#': free = p + axis.Delta; break; } } } // foreach (var l in _lines) // { // Console.WriteLine(l); // } // Console.WriteLine(); return load; } public int Cycle(int n) { var loads = new List(); for (var i = 1; i <= n; i++) { CalculateDirectionalLoad(_north); CalculateDirectionalLoad(_west); CalculateDirectionalLoad(_south); loads.Add(CalculateDirectionalLoad(_east)); var key = GetKey(); Console.WriteLine($"Key: {key} => {loads.Last()}"); if (_keyMap.TryGetValue(key, out int value)) { Console.WriteLine($"CYCLE: @{i} from {value}"); var offset = value; var cycle = i - value; var remainder = (1000000000 - offset) % cycle; return loads[loads.Count - (cycle - remainder) - 1]; } _keyMap[key] = i; } return -1; } private string GetKey() { var result = new StringBuilder(); var start = 0; var run = 0; for (var y = 0; y < _lines.Length; y++) { for (var x = 0; x < _lines[0].Length; x++) { if (_lines[y][x] == 'O') { run++; } else { if (run > 0) { result.Append(start); result.Append(':'); result.Append(run); result.Append('|'); run = 0; } start = y * _lines[0].Length + x; } } } if (run > 0) { result.Append(start); result.Append(':'); result.Append(run); result.Append('|'); } return result.ToString(); } private interface IAxis { int Delta { get; } List PrimaryRange { get; } List SecondaryRange { get; } char Get(int primary, int secondary); void Swap(int primaryA, int primaryB, int secondary); int NorthLoad(int primary, int secondary); } private class NorthSouth : IAxis { private readonly char[][] _lines; public int Delta { get; } public List PrimaryRange { get; } public List SecondaryRange { get; } public NorthSouth(char[][] lines, int delta) { Delta = delta; _lines = lines; PrimaryRange = Enumerable.Range(0, _lines.Length).ToList(); if (delta < 0) { PrimaryRange.Reverse(); } SecondaryRange = Enumerable.Range(0, _lines[0].Length).ToList(); } public char Get(int primary, int secondary) { return _lines[primary][secondary]; } public void Swap(int primaryA, int primaryB, int secondary) { (_lines[primaryA][secondary], _lines[primaryB][secondary]) = (_lines[primaryB][secondary], _lines[primaryA][secondary]); } public int NorthLoad(int primary, int secondary) { return Delta > 0 ? PrimaryRange.Count - primary : primary; } } private class EastWest : IAxis { private readonly char[][] _lines; public int Delta { get; } public List PrimaryRange { get; } public List SecondaryRange { get; } public EastWest(char[][] lines, int delta) { Delta = delta; _lines = lines; PrimaryRange = Enumerable.Range(0, _lines[0].Length).ToList(); if (delta < 0) { PrimaryRange.Reverse(); } SecondaryRange = Enumerable.Range(0, _lines.Length).ToList(); } public char Get(int primary, int secondary) { return _lines[secondary][primary]; } public void Swap(int primaryA, int primaryB, int secondary) { (_lines[secondary][primaryA], _lines[secondary][primaryB]) = (_lines[secondary][primaryB], _lines[secondary][primaryA]); } public int NorthLoad(int primary, int secondary) { return SecondaryRange.Count - secondary; } } }