Day 18 solution

I have a very strong feeling that I massively over-complicated this, but it works. I spent a ton of time making sure each component of the problem was implemented correctly so I could quickly identify where things went wrong, and that setup was convenient enough that I just formalized it and left it in. Maybe it'll be useful for another day...
This commit is contained in:
2021-12-18 16:23:54 -06:00
parent 67a5560dd8
commit fd0fd238f7
4 changed files with 904 additions and 1 deletions

View File

@ -69,6 +69,9 @@
<None Update="inputs\17.txt"> <None Update="inputs\17.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
<None Update="inputs\18.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup> </ItemGroup>
</Project> </Project>

100
inputs/18.txt Normal file
View File

@ -0,0 +1,100 @@
[3,[5,[7,[3,9]]]]
[[[[7,0],0],[2,[2,8]]],[[[7,8],1],3]]
[[[[2,7],0],7],4]
[[2,1],[9,0]]
[[[[7,1],[3,2]],[[9,8],5]],[2,7]]
[[[8,9],[[8,7],0]],[[[8,7],[6,3]],[[1,7],[8,9]]]]
[[8,6],[[9,[1,7]],[6,[3,9]]]]
[[2,[[5,6],6]],[[4,[5,9]],[3,[4,5]]]]
[[[[2,0],[1,1]],[6,6]],[[1,9],[[2,7],[6,8]]]]
[[[4,6],[[6,3],[3,9]]],[[[2,6],[6,1]],[[9,9],[1,5]]]]
[[[4,[3,1]],3],6]
[[0,[[5,2],8]],[1,[9,[4,3]]]]
[[[[8,6],[2,1]],[2,[8,6]]],[[[7,1],[3,9]],0]]
[[[[4,7],[2,7]],[[8,9],2]],[[[2,4],[7,2]],[3,7]]]
[[5,[2,2]],[[1,6],[[9,1],[5,0]]]]
[[5,[[1,2],[6,4]]],[6,8]]
[[[5,[1,7]],7],[7,[8,1]]]
[[1,9],[[0,3],[[6,7],[2,4]]]]
[1,[7,[[0,6],0]]]
[[[[5,7],9],[[3,2],7]],[[5,1],[9,9]]]
[[[[0,4],[9,6]],[[8,3],[7,4]]],[7,[6,2]]]
[[[[1,6],0],[[8,0],[3,4]]],[[3,[0,3]],4]]
[4,[[7,8],[4,[9,7]]]]
[[[2,[3,7]],5],[0,[9,9]]]
[[[2,0],[[5,8],[7,6]]],[[9,[6,2]],[3,2]]]
[[[3,1],3],[[[3,7],6],[9,8]]]
[[7,[[2,5],5]],[5,[3,[4,5]]]]
[[[6,7],6],[2,[[9,3],9]]]
[[[[5,6],7],[[3,2],5]],[[9,[4,3]],[3,8]]]
[0,7]
[[[4,6],[2,9]],[[[7,6],[5,1]],7]]
[[0,5],[[1,[4,1]],[[7,3],9]]]
[[[2,[3,8]],5],[[[5,9],8],[7,0]]]
[[[6,[8,6]],[[3,6],7]],[[2,1],[6,[7,5]]]]
[[2,[[6,3],[8,9]]],[[[5,6],4],[[7,0],1]]]
[[[[7,1],[5,6]],8],[[[8,9],4],[8,3]]]
[[[9,2],[1,0]],0]
[[5,[5,[8,5]]],4]
[[3,[5,[4,9]]],3]
[[8,[[7,7],6]],5]
[[4,[[5,1],1]],[1,[1,[9,8]]]]
[[[7,[3,6]],[[2,8],[4,7]]],[[[8,8],[4,0]],[2,4]]]
[[[[3,6],3],[0,9]],2]
[[2,8],[[8,[8,6]],[[1,1],[4,5]]]]
[[2,[1,[1,0]]],[[[6,2],[7,4]],[[7,1],6]]]
[3,[8,[7,[8,6]]]]
[[1,0],[[[0,4],[0,5]],[1,5]]]
[[[[5,0],4],[[7,8],[8,8]]],[[1,7],0]]
[1,[[[4,1],7],[6,[9,0]]]]
[[[1,8],2],[[5,5],[8,5]]]
[[4,[9,[0,6]]],[[[8,9],[4,5]],4]]
[[[[5,4],[1,7]],[[3,1],[7,9]]],[[[0,8],[4,7]],[[5,9],6]]]
[[[[8,0],9],4],[[7,[1,3]],5]]
[[[[5,0],6],[[6,1],8]],[[9,1],7]]
[[9,[6,[8,8]]],[7,[[7,1],6]]]
[[[5,[1,5]],[3,[4,2]]],[[[5,2],7],[[6,9],[2,8]]]]
[[[5,[5,5]],[5,7]],[4,[[2,9],7]]]
[[[[0,4],0],[[0,6],[3,0]]],[0,[[8,1],2]]]
[[[7,[4,6]],[[7,2],[4,6]]],[[[9,3],[4,9]],6]]
[[6,7],7]
[[[4,1],[8,[1,5]]],[[4,6],0]]
[[[4,[5,5]],5],[[0,[2,7]],[1,1]]]
[[[[0,1],3],[6,7]],[4,7]]
[[4,[6,4]],[[[9,8],1],[9,3]]]
[[[4,9],0],[[[7,0],[0,9]],[1,[1,0]]]]
[[[7,9],[[9,5],[6,9]]],[[0,[3,0]],[0,[5,9]]]]
[9,[[0,0],[[1,9],9]]]
[[[5,[0,5]],[[9,8],[9,5]]],[[0,[2,5]],7]]
[[[[5,8],6],9],[[[2,7],7],[[7,8],5]]]
[[8,[[4,7],6]],2]
[[[[7,1],[9,0]],[9,[1,7]]],[[8,[6,7]],[2,5]]]
[[4,[2,9]],8]
[[[[7,6],[5,3]],[5,[9,7]]],[[6,[8,1]],[[6,4],9]]]
[[7,[[7,8],4]],[[1,3],[4,[9,7]]]]
[[[6,[6,7]],[[2,8],3]],[7,[6,[0,3]]]]
[[9,8],[[0,[4,8]],[[9,1],1]]]
[[[[4,0],[5,9]],7],[6,[[5,9],[9,6]]]]
[[8,1],[1,[9,[8,3]]]]
[[[1,[5,1]],[6,7]],[[5,9],[2,[6,7]]]]
[[[3,7],[[7,8],1]],[[0,[6,3]],[8,0]]]
[[5,[[9,3],[1,2]]],7]
[[[1,[9,9]],3],[[6,4],[4,1]]]
[[6,[1,[3,6]]],[2,9]]
[[2,[0,2]],[5,[[9,4],[5,0]]]]
[[4,[[3,1],[7,0]]],[[9,1],[[5,5],[6,7]]]]
[[3,[[7,1],[3,4]]],[7,[9,[9,4]]]]
[[9,9],[[5,4],[[9,7],4]]]
[[[5,1],8],[[6,7],9]]
[[[0,[9,5]],[4,3]],[3,2]]
[[[6,[4,1]],[[8,7],[5,3]]],[[[1,2],5],[[9,2],5]]]
[[[[7,4],[9,0]],[[1,8],[2,9]]],[[5,[1,9]],[4,0]]]
[[[4,[3,8]],[[3,3],[2,8]]],[[[1,3],9],[[8,5],6]]]
[[[[6,4],[7,9]],[[7,6],8]],[7,[9,8]]]
[[7,[3,5]],7]
[[[[5,0],[2,3]],[3,7]],[[4,[6,3]],[7,[4,4]]]]
[[6,[3,[7,6]]],[[[5,8],[8,1]],[3,[1,5]]]]
[[8,[9,[5,2]]],2]
[[1,[5,4]],[[7,[8,0]],8]]
[[[[2,7],4],3],[[1,4],[8,4]]]
[3,[9,2]]

799
src/18.cs Normal file
View File

@ -0,0 +1,799 @@
using System.Diagnostics;
namespace aoc2021;
internal class Day18 : Day
{
class SFNum
{
public int? left;
public int? right;
public SFNum? leftNum;
public SFNum? rightNum;
public SFNum? owner;
public bool exploding;
public bool splittingLeft;
public bool splittingRight;
public override string ToString() => $"{(exploding ? "<+white>" : "")}" +
$"[" +
$"{leftNum?.ToString() ?? ""}{(splittingLeft ? "<+white>" : "")}{left?.ToString() ?? ""}{(splittingLeft ? "<r>" : "")}" +
$"," +
$"{rightNum?.ToString() ?? ""}{(splittingRight ? "<+white>" : "")}{right?.ToString() ?? ""}{(splittingRight ? "<r>" : "")}" +
$"]" +
$"{(exploding ? "<r>" : "")}";
public SFNum()
{
}
public SFNum(SFNum other)
{
left = other.left;
right = other.right;
if (other.leftNum != null)
{
leftNum = new SFNum(other.leftNum)
{
owner = this
};
}
if (other.rightNum != null)
{
rightNum = new SFNum(other.rightNum)
{
owner = this
};
}
exploding = other.exploding;
splittingLeft = other.splittingLeft;
splittingRight = other.splittingRight;
}
public SFNum Root
{
get
{
SFNum curr = this;
while (curr.owner != null)
{
curr = curr.owner;
}
return curr;
}
}
public long Magnitude
{
get
{
long result = 0;
if (leftNum != null)
{
result += 3 * leftNum.Magnitude;
}
else
{
result += 3 * (int)left!;
}
if (rightNum != null)
{
result += 2 * rightNum.Magnitude;
}
else
{
result += 2 * (int)right!;
}
return result;
}
}
}
[Conditional("DEBUG")]
private static void DoTests()
{
DoExplodeTests();
DoSplitTests();
DoMagnitudeTests();
DoAddTests();
DoReduceTests();
DoPart1Tests();
}
private static void DoExplodeTests()
{
Logger.Log("<underline>test: explode<r>");
var tests = new List<string>()
{
"[[[[[9,8],1],2],3],4]",
"[7,[6,[5,[4,[3,2]]]]]",
"[[6,[5,[4,[3,2]]]],1]",
"[[3,[2,[1,[7,3]]]],[6,[5,[4,[3,2]]]]]",
"[[3,[2,[8,0]]],[9,[5,[4,[3,2]]]]]",
"[[[[[4,3],4],4],[7,[[8,4],9]]],[1,1]]",
"[[[[0,7],4],[7,[[8,4],9]]],[1,1]]",
"[[[[0,7],4],[[7,8],[0,[6,7]]]],[1,1]]",
};
var exploded = new List<string>()
{
"[[[[0,9],2],3],4]",
"[7,[6,[5,[7,0]]]]",
"[[6,[5,[7,0]]],3]",
"[[3,[2,[8,0]]],[9,[5,[4,[3,2]]]]]",
"[[3,[2,[8,0]]],[9,[5,[7,0]]]]",
"[[[[0,7],4],[7,[[8,4],9]]],[1,1]]",
"[[[[0,7],4],[15,[0,13]]],[1,1]]",
"[[[[0,7],4],[[7,8],[6,0]]],[8,1]]",
};
for (int i = 0; i < tests.Count; i++)
{
Logger.Log($"<magenta>1.{(i + 1)}<r>");
SFNum test = ParseSFNum(tests[i]);
SFNum result = ParseSFNum(exploded[i]);
var didExplode = CheckExplodes(test);
if (!didExplode || test.ToString() != result.ToString())
{
throw new Exception();
}
Logger.Log("<green>✓<r>");
}
var twoStepTests = new List<string>()
{
"[[[[[4,3],4],4],[7,[[8,4],9]]],[1,1]]",
};
var twoStepExploded = new List<string>()
{
"[[[[0,7],4],[15,[0,13]]],[1,1]]",
};
for (int i = 0; i < twoStepTests.Count; i++)
{
Logger.Log($"<magenta>2.{(i + 1)}<r>");
SFNum test = ParseSFNum(twoStepTests[i]);
SFNum result = ParseSFNum(twoStepExploded[i]);
var didExplode = CheckExplodes(test);
if (!didExplode)
{
throw new Exception();
}
didExplode = CheckExplodes(test);
if (!didExplode || test.ToString() != result.ToString())
{
throw new Exception();
}
Logger.Log("<green>✓<r>");
}
}
private static void DoSplitTests()
{
Logger.Log("<underline>test: split<r>");
var tests = new List<string>()
{
"[[[[0,7],4],[15,[0,13]]],[1,1]]",
"[[[[0,7],4],[[7,8],[0,13]]],[1,1]]",
"[[[[7,7],[7,8]],[[9,5],[8,0]]],[[[9,10],20],[8,[9,0]]]]",
};
var split = new List<string>()
{
"[[[[0,7],4],[[7,8],[0,13]]],[1,1]]",
"[[[[0,7],4],[[7,8],[0,[6,7]]]],[1,1]]",
"[[[[7,7],[7,8]],[[9,5],[8,0]]],[[[9,[5,5]],20],[8,[9,0]]]]",
};
for (int i = 0; i < tests.Count; i++)
{
Logger.Log($"<magenta>{(i + 1)}<r>");
SFNum test = ParseSFNum(tests[i]);
SFNum result = ParseSFNum(split[i]);
var didSplit = CheckSplits(test);
if (!didSplit || test.ToString() != result.ToString())
{
throw new Exception();
}
// todo: add tests verifying owners are correct
Logger.Log("<green>✓<r>");
}
}
private static void DoMagnitudeTests()
{
Logger.Log("<underline>test: magnitude<r>");
var tests = new List<string>()
{
"[9,1]",
"[1,9]",
"[[9,1],[1,9]]",
"[[1,2],[[3,4],5]]",
"[[[[0,7],4],[[7,8],[6,0]]],[8,1]]",
"[[[[1,1],[2,2]],[3,3]],[4,4]]",
"[[[[3,0],[5,3]],[4,4]],[5,5]]",
"[[[[5,0],[7,4]],[5,5]],[6,6]]",
"[[[[8,7],[7,7]],[[8,6],[7,7]]],[[[0,7],[6,6]],[8,7]]]",
};
var magnitudes = new List<long>()
{
29,
21,
129,
143,
1384,
445,
791,
1137,
3488,
};
for (int i = 0; i < tests.Count; i++)
{
Logger.Log($"<magenta>{(i + 1)}<r>");
SFNum test = ParseSFNum(tests[i]);
var magnitude = test.Magnitude;
if (magnitude != magnitudes[i])
{
throw new Exception();
}
Logger.Log("<green>✓<r>");
}
}
private static void DoAddTests()
{
Logger.Log("<underline>test: add<r>");
var tests = new List<List<string>>()
{
new()
{
"[[[[4,3],4],4],[7,[[8,4],9]]]",
"[1,1]",
},
};
var results = new List<string>()
{
"[[[[[4,3],4],4],[7,[[8,4],9]]],[1,1]]",
};
for (int i = 0; i < tests.Count; i++)
{
Logger.Log($"<magenta>{(i + 1)}<r>");
SFNum test = ParseSFNum(tests[i][0]);
for (int j = 1; j < tests[i].Count; j++)
{
test = Add(test, ParseSFNum(tests[i][j]));
}
SFNum result = ParseSFNum(results[i]);
if (test.ToString() != result.ToString())
{
throw new Exception();
}
if (result.leftNum!.owner != result || result.rightNum!.owner != result)
{
throw new Exception();
}
Logger.Log("<green>✓<r>");
}
}
private static void DoReduceTests()
{
Logger.Log("<underline>test: reduce<r>");
var tests = new List<string>()
{
"[[[[[4,3],4],4],[7,[[8,4],9]]],[1,1]]",
};
var results = new List<string>()
{
"[[[[0,7],4],[[7,8],[6,0]]],[8,1]]",
};
for (int i = 0; i < tests.Count; i++)
{
Logger.Log($"<magenta>{(i + 1)}<r>");
SFNum test = ParseSFNum(tests[i]);
SFNum result = ParseSFNum(results[i]);
Reduce(test);
if (test.ToString() != result.ToString())
{
throw new Exception();
}
Logger.Log("<green>✓<r>");
}
}
private static void DoPart1Tests()
{
Logger.Log("<underline>test: add+reduce<r>");
var vals = new List<List<SFNum>>()
{
new()
{
ParseSFNum("[1,1]"),
ParseSFNum("[2,2]"),
ParseSFNum("[3,3]"),
ParseSFNum("[4,4]"),
},
new()
{
ParseSFNum("[1,1]"),
ParseSFNum("[2,2]"),
ParseSFNum("[3,3]"),
ParseSFNum("[4,4]"),
ParseSFNum("[5,5]"),
},
new()
{
ParseSFNum("[1,1]"),
ParseSFNum("[2,2]"),
ParseSFNum("[3,3]"),
ParseSFNum("[4,4]"),
ParseSFNum("[5,5]"),
ParseSFNum("[6,6]"),
},
new()
{
ParseSFNum("[[[[4,3],4],4],[7,[[8,4],9]]]"),
ParseSFNum("[1,1]"),
},
new()
{
ParseSFNum("[[[0,[4,5]],[0,0]],[[[4,5],[2,6]],[9,5]]]"),
ParseSFNum("[7,[[[3,7],[4,3]],[[6,3],[8,8]]]]"),
},
new()
{
ParseSFNum("[[[[4,0],[5,4]],[[7,7],[6,0]]],[[8,[7,7]],[[7,9],[5,0]]]]"),
ParseSFNum("[[2,[[0,8],[3,4]]],[[[6,7],1],[7,[1,6]]]]"),
},
new()
{
ParseSFNum("[[[[6,7],[6,7]],[[7,7],[0,7]]],[[[8,7],[7,7]],[[8,8],[8,0]]]]"),
ParseSFNum("[[[[2,4],7],[6,[0,5]]],[[[6,8],[2,8]],[[2,1],[4,5]]]]"),
},
new()
{
ParseSFNum("[[[[7,0],[7,7]],[[7,7],[7,8]]],[[[7,7],[8,8]],[[7,7],[8,7]]]]"),
ParseSFNum("[7,[5,[[3,8],[1,4]]]]"),
},
new()
{
ParseSFNum("[[[[7,7],[7,8]],[[9,5],[8,7]]],[[[6,8],[0,8]],[[9,9],[9,0]]]]"),
ParseSFNum("[[2,[2,2]],[8,[8,1]]]"),
},
new()
{
ParseSFNum("[[[[6,6],[6,6]],[[6,0],[6,7]]],[[[7,7],[8,9]],[8,[8,1]]]]"),
ParseSFNum("[2,9]"),
},
new()
{
ParseSFNum("[[[[6,6],[7,7]],[[0,7],[7,7]]],[[[5,5],[5,6]],9]]"),
ParseSFNum("[1,[[[9,3],9],[[9,0],[0,7]]]]"),
},
new()
{
ParseSFNum("[[[[7,8],[6,7]],[[6,8],[0,8]]],[[[7,7],[5,0]],[[5,5],[5,6]]]]"),
ParseSFNum("[[[5,[7,4]],7],1]"),
},
new()
{
ParseSFNum("[[[[7,7],[7,7]],[[8,7],[8,7]]],[[[7,0],[7,7]],9]]"),
ParseSFNum("[[[[4,2],2],6],[8,7]]"),
},
};
var results = new List<SFNum>()
{
ParseSFNum("[[[[1,1],[2,2]],[3,3]],[4,4]]"),
ParseSFNum("[[[[3,0],[5,3]],[4,4]],[5,5]]"),
ParseSFNum("[[[[5,0],[7,4]],[5,5]],[6,6]]"),
ParseSFNum("[[[[0,7],4],[[7,8],[6,0]]],[8,1]]"),
ParseSFNum("[[[[4,0],[5,4]],[[7,7],[6,0]]],[[8,[7,7]],[[7,9],[5,0]]]]"),
ParseSFNum("[[[[6,7],[6,7]],[[7,7],[0,7]]],[[[8,7],[7,7]],[[8,8],[8,0]]]]"),
ParseSFNum("[[[[7,0],[7,7]],[[7,7],[7,8]]],[[[7,7],[8,8]],[[7,7],[8,7]]]]"),
ParseSFNum("[[[[7,7],[7,8]],[[9,5],[8,7]]],[[[6,8],[0,8]],[[9,9],[9,0]]]]"),
ParseSFNum("[[[[6,6],[6,6]],[[6,0],[6,7]]],[[[7,7],[8,9]],[8,[8,1]]]]"),
ParseSFNum("[[[[6,6],[7,7]],[[0,7],[7,7]]],[[[5,5],[5,6]],9]]"),
ParseSFNum("[[[[7,8],[6,7]],[[6,8],[0,8]]],[[[7,7],[5,0]],[[5,5],[5,6]]]]"),
ParseSFNum("[[[[7,7],[7,7]],[[8,7],[8,7]]],[[[7,0],[7,7]],9]]"),
ParseSFNum("[[[[8,7],[7,7]],[[8,6],[7,7]]],[[[0,7],[6,6]],[8,7]]]"),
};
for (int i = 0; i < vals.Count; i++)
{
Logger.Log($"<magenta>{(i + 1)}<r>");
SFNum curr = vals[i][0];
for (int j = 1; j < vals[i].Count; j++)
{
curr = Add(curr, vals[i][j]);
Reduce(curr);
}
if (curr.ToString() != results[i].ToString())
{
Logger.Log($" expected: {results[i]}");
throw new Exception();
}
Logger.Log("<green>✓<r>");
}
}
internal override void Go()
{
DoTests();
var lines = Util.ReadAllLines("inputs/18.txt");
List<SFNum> nums = new();
foreach (var line in lines)
{
SFNum parsed = ParseSFNum(line);
nums.Add(parsed);
}
Part1(nums);
Part2(nums);
}
private static SFNum ParseSFNum(string line)
{
int phase = 0;
SFNum root = new();
SFNum? curr = null;
string numStr = string.Empty;
var assignNum = () =>
{
if (numStr.Length == 0)
{
return;
}
var val = Convert.ToInt32(numStr);
if (phase == 0)
{
curr!.left = val;
}
else
{
curr!.right = val;
}
numStr = string.Empty;
};
foreach (var ch in line)
{
switch (ch)
{
case '[':
if (curr == null)
{
curr = root;
break;
}
if (phase == 0)
{
curr!.leftNum = new()
{
owner = curr,
};
curr = curr.leftNum;
}
else
{
curr!.rightNum = new()
{
owner = curr,
};
curr = curr.rightNum;
}
phase = 0;
break;
case ',':
assignNum();
phase = 1;
break;
case ']':
assignNum();
curr = curr!.owner;
break;
default:
numStr += ch;
break;
}
}
return root;
}
private static void Part1(IEnumerable<SFNum> nums)
{
using var t = new Timer();
SFNum? curr = null;
foreach (var num in nums)
{
if (curr == null)
{
curr = num;
continue;
}
curr = Add(curr, num);
Reduce(curr);
}
t.Stop();
Logger.Log($"<+black>> part1: {curr} -> <+white>{curr!.Magnitude}<r>");
}
private static void Part2(IEnumerable<SFNum> nums)
{
using var t = new Timer();
List<(SFNum first, SFNum second, SFNum reduced, long magnitude)> totals = new();
for (int i = 0; i < nums.Count() - 1; i++)
{
for (int j = i + 1; j < nums.Count(); j++)
{
var first = nums.ElementAt(i);
var second = nums.ElementAt(j);
var curr = Add(first, second);
Reduce(curr);
totals.Add((first, second, curr, curr.Magnitude));
curr = Add(second, first);
Reduce(curr);
totals.Add((second, first, curr, curr.Magnitude));
}
}
var highest = totals.MaxBy(x => x.magnitude);
t.Stop();
Logger.Log($"<+black>> part2: {highest.first} + {highest.second} = {highest.reduced} -> <+white>{highest.magnitude}<r>");
}
private static SFNum Add(SFNum first, SFNum second)
{
var result = new SFNum()
{
leftNum = new SFNum(first),
rightNum = new SFNum(second),
};
result.leftNum.owner = result;
result.rightNum.owner = result;
return result;
}
private static void Reduce(SFNum num)
{
for (int i = 0; i < 10000; i++)
{
if (CheckExplodes(num))
{
continue;
}
if (CheckSplits(num))
{
continue;
}
return;
}
throw new Exception();
}
private static bool CheckExplodes(SFNum num, int depth = 0)
{
#if DEBUG
var initial = new SFNum()
{
left = num.left,
right = num.right,
leftNum = num.leftNum,
rightNum = num.rightNum,
owner = num.owner,
};
#endif
if (num.leftNum == null && num.rightNum == null && depth >= 4)
{
Explode(num);
#if DEBUG
if (initial.Root.ToString() == num.Root.ToString())
{
throw new Exception();
}
#endif
return true;
}
if (num.leftNum != null)
{
if (CheckExplodes(num.leftNum, depth + 1))
{
return true;
}
}
if (num.rightNum != null)
{
if (CheckExplodes(num.rightNum, depth + 1))
{
return true;
}
}
return false;
}
private static void Explode(SFNum num)
{
#if DEBUG
num.exploding = true;
Logger.Log($"exploding: {num.Root}");
#endif
var curr = num;
var last = num;
while (true)
{
curr = curr.owner;
if (curr == null)
{
break;
}
if (last == curr.leftNum)
{
last = curr;
continue;
}
if (curr.leftNum != null)
{
curr = curr.leftNum;
while (curr.rightNum != null)
{
curr = curr.rightNum;
}
curr.right += num.left;
}
else
{
curr.left += num.left;
}
break;
}
curr = num;
last = num;
while (true)
{
curr = curr.owner;
if (curr == null)
{
break;
}
if (last == curr.rightNum)
{
last = curr;
continue;
}
if (curr.rightNum != null)
{
curr = curr.rightNum;
while (curr.leftNum != null)
{
curr = curr.leftNum;
}
curr.left += num.right;
}
else
{
curr.right += num.right;
}
break;
}
if (num == num.owner?.leftNum)
{
num.owner.leftNum = null;
num.owner.left = 0;
}
else if (num == num.owner?.rightNum)
{
num.owner.rightNum = null;
num.owner.right = 0;
}
#if DEBUG
Logger.Log($" -> {num.Root}");
#endif
num.owner = null;
}
private static bool CheckSplits(SFNum num)
{
if (num.leftNum != null)
{
if (CheckSplits(num.leftNum))
{
return true;
}
}
if (Split(num))
{
return true;
}
if (num.rightNum != null)
{
if (CheckSplits(num.rightNum))
{
return true;
}
}
return false;
}
private static bool Split(SFNum num)
{
if (num.left != null && num.left >= 10)
{
num.splittingLeft = true;
#if DEBUG
Logger.Log($"splitting: {num.Root}");
#endif
num.leftNum = new()
{
left = (int)Math.Floor((int)num.left / 2.0),
right = (int)Math.Ceiling((int)num.left / 2.0),
owner = num,
};
num.left = null;
num.splittingLeft = false;
#if DEBUG
Logger.Log($" -> {num.Root}");
#endif
return true;
}
if (num.right != null && num.right >= 10)
{
num.splittingRight = true;
#if DEBUG
Logger.Log($"splitting: {num.Root}");
#endif
num.rightNum = new()
{
left = (int)Math.Floor((int)num.right / 2.0),
right = (int)Math.Ceiling((int)num.right / 2.0),
owner = num,
};
num.right = null;
num.splittingRight = false;
#if DEBUG
Logger.Log($" -> {num.Root}");
#endif
return true;
}
return false;
}
}

View File

@ -35,7 +35,8 @@ else
"14" => new Day14(), "14" => new Day14(),
"15" => new Day15(), "15" => new Day15(),
"16" => new Day16(), "16" => new Day16(),
_ => new Day17(), "17"=> new Day17(),
_ => new Day18(),
}; };
day.Go(); day.Go();
} }