186 lines
5.7 KiB
C#
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
|