2021aoc/Day18_WithStringOperations.cs

186 lines
5.7 KiB
C#

// #define Day18_2
#if Day18_2
using System.Text.RegularExpressions;
var lines = File.ReadAllLines("day18/input");
var numberToSplit = new Regex(@"\d{2,}");
var numbersToMatch = new Regex(@"\d+");
var cur = lines.First();
foreach (var l in lines.Skip(1)) {
cur = Add(cur, l);
cur = Reduce(cur);
}
var bla = Node.Parse(cur);
Console.WriteLine(bla);
Console.WriteLine(bla.Magnitude());
List<long> magnitudes = new List<long>();
for (int i = 0; i < lines.Length; i++) {
for (int j = 0; j < lines.Length; j++) {
if (i == j) {continue;}
var test = Add(lines[i], lines[j]);
var reducedTest = Reduce(test);
magnitudes.Add(Node.Parse(reducedTest).Magnitude());
var testReverse = Add(lines[j], lines[i]);
var reducedTestReverse = Reduce(testReverse);
magnitudes.Add(Node.Parse(reducedTestReverse).Magnitude());
}
}
Console.WriteLine(magnitudes.Max());
string Reduce(string number) {
bool changed = false;
do {
(changed, number) = Explode(number);
if (!changed) {
(changed, number) = Split(number);
}
} while (changed);
return number;
}
Changed Explode(string number) {
int depth = 0;
int pos = 0;
while (depth < 5 && pos < number.Length) {
if (number[pos] == '[') {
depth++;
} else if (number[pos] == ']'){
depth--;
}
pos++;
}
if (depth < 5) {
return new Changed(false, number);
}
int startOfExplode = pos;
while (number[pos] != ']') {
pos++;
}
int endOfExplode = pos;
var exploded = number.Substring(startOfExplode, endOfExplode - startOfExplode);
var explodedNumbers = exploded.Split(",").Select(int.Parse).ToList();
var matches = numbersToMatch.Matches(number);
var leftAddMatch = matches.Where(m => m.Index < startOfExplode).MaxBy(m => m.Index);
var rightAddMatch = matches.Where(m => m.Index > endOfExplode).MinBy(m => m.Index);
if (leftAddMatch != null && rightAddMatch != null) {
var before = number.Substring(0, leftAddMatch.Index);
var after = number.Substring(rightAddMatch.Index + rightAddMatch.Length,
number.Length - rightAddMatch.Index - rightAddMatch.Length);
var beforeExplosion = number.Substring(leftAddMatch.Index + leftAddMatch.Length,
startOfExplode - leftAddMatch.Index - leftAddMatch.Length - 1);
var afterExplosion = number.Substring(endOfExplode + 1, rightAddMatch.Index - endOfExplode - 1);
var leftAdded = int.Parse(leftAddMatch.Value) + explodedNumbers[0];
var rightAdded = int.Parse(rightAddMatch.Value) + explodedNumbers[1];
return new Changed(true, $"{before}{leftAdded}{beforeExplosion}0{afterExplosion}{rightAdded}{after}");
} else if (leftAddMatch == null) {
var before = number.Substring(0, startOfExplode - 1);
var after = number.Substring(rightAddMatch.Index + rightAddMatch.Length,
number.Length - rightAddMatch.Index - rightAddMatch.Length);
var afterExplosion = number.Substring(endOfExplode + 1, rightAddMatch.Index - endOfExplode - 1);
var rightAdded = int.Parse(rightAddMatch.Value) + explodedNumbers[1];
return new Changed(true, $"{before}0{afterExplosion}{rightAdded}{after}");
} else if (rightAddMatch == null) {
var before = number.Substring(0, leftAddMatch.Index);
var after = number.Substring(endOfExplode + 1,
number.Length - endOfExplode - 1);
var beforeExplosion = number.Substring(leftAddMatch.Index + leftAddMatch.Length,
startOfExplode - leftAddMatch.Index - leftAddMatch.Length - 1);
var leftAdded = int.Parse(leftAddMatch.Value) + explodedNumbers[0];
return new Changed(true, $"{before}{leftAdded}{beforeExplosion}0{after}");
}
throw new ArgumentException();
}
Changed Split(string number) {
var m = numberToSplit.Match(number);
if (!m.Success) {
return new Changed(false, number);
}
var before = number.Substring(0, m.Index);
var after = number.Substring(m.Index + m.Length, number.Length - m.Index - m.Length);
var value = int.Parse(m.Value);
int first = value / 2;
int second = value - first;
return new Changed(true, $"{before}[{first},{second}]{after}");
}
string Add(string first, string second) {
return $"[{first},{second}]";
}
record Changed(bool changed, string number);
class Node {
public Node? Parent { get; set; }
public Node? Left { get; set; }
public Node? Right { get; set; }
public int? Leaf { get; set; }
public string Print() {
if (Leaf != null) {
return $"{Leaf}";
} else {
return $"[{Left.Print()},{Right.Print()}]";
}
}
public long Magnitude() {
if (Leaf != null) {
return Leaf ?? -9999;
}
return 3 * Left.Magnitude() + 2 * Right.Magnitude();
}
public static Node Parse(string number) {
int pos = 0;
return Parse(ref pos, number, null);
}
public static Node Parse(ref int pos, string number, Node parent) {
var cur = new Node() {Parent = parent};
if (number[pos] == '[') {
pos++;
cur.Left = Node.Parse(ref pos, number, cur);
pos++; // ignore comma
cur.Right = Node.Parse(ref pos, number, cur);
pos++; // ignore closing bracket
} else {
// for debugging
int i = 0;
while ("1234567890".Contains(number[pos + i])) {
i++;
}
cur.Leaf = int.Parse(number.Substring(pos, i));
pos += i;
}
return cur;
}
public override string ToString() {
return Print();
}
}
#endif