2021aoc/Day18.cs

228 lines
5.9 KiB
C#

// #define Day18
#if Day18
var lines = File.ReadAllLines("day18/input");
var numbers = lines.Select(Node.Parse).ToList();
var cur = numbers.First();
foreach (var toAdd in numbers.Skip(1)) {
cur = Node.Add(cur,toAdd);
ExplodeAndSplit(cur);
}
Console.WriteLine(cur);
Console.WriteLine(cur.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 = Node.Add(Node.Parse(lines[i]), Node.Parse(lines[j]));
ExplodeAndSplit(test);
magnitudes.Add(test.Magnitude());
var testReverse = Node.Add(Node.Parse(lines[j]), Node.Parse(lines[i]));
ExplodeAndSplit(testReverse);
magnitudes.Add(testReverse.Magnitude());
}
}
Console.WriteLine(magnitudes.Max());
sw.Stop();
Console.WriteLine(sw.Elapsed);
void ExplodeAndSplit(Node number) {
bool changed = false;
do {
changed = number.Explode(1);
if (!changed) {
changed = number.Split();
}
} while (changed);
}
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 Add(Node left, Node right) {
var top = new Node() {Left = left, Right = right};
left.Parent = top;
right.Parent = top;
return top;
}
public bool Explode(int depth) {
if (depth >= 4 && Leaf == null && (Left.Leaf == null || Right.Leaf == null)) {
if (Left.Leaf == null) {
var oldLeft = Left;
Left = new Node() {Leaf = 0, Parent = this};
if (oldLeft.Left.Leaf == null || oldLeft.Right.Leaf == null) {
throw new ArgumentException("left or right was null");
} else {
Parent?.AddValueLeftParent(oldLeft.Left.Leaf ?? -9999, this);
Right.AddValueLeftChild(oldLeft.Right.Leaf ?? -9999);
}
return true;
}
if (Right.Leaf == null) {
var oldRight = Right;
Right = new Node() {Leaf = 0, Parent = this};
if (oldRight.Left.Leaf == null || oldRight.Right.Leaf == null) {
throw new ArgumentException("left or right was null");
} else {
Left.AddValueRightChild(oldRight.Left.Leaf ?? -9999);
Parent?.AddValueRightParent(oldRight.Right.Leaf ?? -9999, this);
}
return true;
}
} else if (Leaf == null) {
if (Left.Explode(depth + 1)) {
return true;
} else if (Right.Explode(depth + 1)) {
return true;
}
}
return false;
}
public bool AddValueLeftParent(int value, Node from) {
if (Leaf != null) {
Leaf += value;
return true;
}
if (Left == from) {
if (Parent == null) {
return false;
}
return Parent.AddValueLeftParent(value, this);
}
if (Right == from) {
return Left.AddValueRightChild(value);
}
return AddValueRightChild(value);
}
public bool AddValueRightParent(int value, Node from) {
if (Leaf != null) {
Leaf += value;
return true;
}
if (Right == from) {
if (Parent == null) {
return false;
}
return Parent.AddValueRightParent(value, this);
}
if (Left == from) {
return Right.AddValueLeftChild(value);
}
return AddValueLeftChild(value);
}
public bool AddValueLeftChild(int value) {
if (Leaf != null) {
Leaf += value;
return true;
}
return Left.AddValueLeftChild(value);
}
public bool AddValueRightChild(int value) {
if (Leaf != null) {
Leaf += value;
return true;
}
return Right.AddValueRightChild(value);
}
public bool Split() {
if (Leaf == null) {
if (Left.Split()) {
return true;
}
if (Right.Split()) {
return true;
}
return false;
} else if (Leaf > 9){
var leftValue = Leaf / 2;
var rightValue = Leaf - leftValue;
Leaf = null;
Left = new Node() {Leaf = leftValue, Parent = this};
Right = new Node() {Leaf = rightValue, Parent = this};
return true;
}
return false;
}
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