|
|
@@ -1,45 +1,210 @@
|
|
|
-namespace Day14;
|
|
|
+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<string, int> _keyMap = new Dictionary<string, int>();
|
|
|
|
|
|
public BoulderMap(IList<string> 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;
|
|
|
- for (var x = 0; x < _lines[0].Length; x++)
|
|
|
+ foreach (var s in axis.SecondaryRange)
|
|
|
{
|
|
|
- var freeY = 0;
|
|
|
- for (var y = 0; y < _lines.Length; y++)
|
|
|
+ var free = axis.PrimaryRange.First();
|
|
|
+ foreach (var p in axis.PrimaryRange)
|
|
|
{
|
|
|
- switch (_lines[y][x])
|
|
|
+ switch (axis.Get(p, s))
|
|
|
{
|
|
|
case 'O':
|
|
|
- if (y != freeY)
|
|
|
+ if (p != free)
|
|
|
{
|
|
|
- _lines[y][x] = _lines[freeY][x];
|
|
|
- _lines[freeY][x] = 'O';
|
|
|
+ axis.Swap(p, free, s);
|
|
|
}
|
|
|
- load += _lines.Length - freeY;
|
|
|
- freeY++;
|
|
|
+ load += axis.NorthLoad(free, s);
|
|
|
+ free += axis.Delta;
|
|
|
break;
|
|
|
case '#':
|
|
|
- freeY = y + 1;
|
|
|
+ free = p + axis.Delta;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- foreach (var l in _lines)
|
|
|
+ // foreach (var l in _lines)
|
|
|
+ // {
|
|
|
+ // Console.WriteLine(l);
|
|
|
+ // }
|
|
|
+ // Console.WriteLine();
|
|
|
+
|
|
|
+ return load;
|
|
|
+ }
|
|
|
+
|
|
|
+ public int Cycle(int n)
|
|
|
+ {
|
|
|
+ var loads = new List<int>();
|
|
|
+ for (var i = 1; i <= n; i++)
|
|
|
{
|
|
|
- Console.WriteLine(l);
|
|
|
+ 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 load;
|
|
|
+ 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<int> PrimaryRange { get; }
|
|
|
+ List<int> 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<int> PrimaryRange { get; }
|
|
|
+ public List<int> 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<int> PrimaryRange { get; }
|
|
|
+ public List<int> 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;
|
|
|
+ }
|
|
|
}
|
|
|
}
|