Day 13 solution

I am not completely happy with this data structure, but it's functional enough. I wanted to implement comparers and equality overrides for the classes to make part 2 shorter, but it would have come at the cost of a bunch of boilerplate code, so whatever.
This commit is contained in:
2022-12-13 17:15:16 -06:00
parent 61227ba688
commit ba6ad54329
4 changed files with 681 additions and 909 deletions

View File

@ -60,6 +60,7 @@
<EmbeddedResource Include="inputs\12a.txt" /> <EmbeddedResource Include="inputs\12a.txt" />
<EmbeddedResource Include="inputs\13.txt" /> <EmbeddedResource Include="inputs\13.txt" />
<None Remove="inputs\14.txt" /> <None Remove="inputs\14.txt" />
<EmbeddedResource Include="inputs\13a.txt" />
<EmbeddedResource Include="inputs\14.txt" /> <EmbeddedResource Include="inputs\14.txt" />
<None Remove="inputs\15.txt" /> <None Remove="inputs\15.txt" />
<EmbeddedResource Include="inputs\15.txt" /> <EmbeddedResource Include="inputs\15.txt" />

File diff suppressed because it is too large Load Diff

23
inputs/13a.txt Normal file
View File

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

209
src/13.cs Normal file
View File

@ -0,0 +1,209 @@
using System.Text;
namespace aoc2022;
internal class Day13 : Day
{
abstract class entry
{
}
class packet : entry
{
public packet(params entry[] _entries)
{
entries = new List<entry>(_entries);
}
public readonly List<entry> entries;
public packet? parent;
public override string ToString() => $"[{string.Join(",", entries)}]";
}
class entryint : entry
{
public entryint(int _num)
{
num = _num;
}
public readonly int num;
public override string ToString() => $"{num}";
}
private readonly List<(packet, packet)> packets = new();
internal override void Parse()
{
packet? one = null;
packet? two = null;
foreach (var line in Util.Parsing.ReadAllLines("13"))
{
if (string.IsNullOrEmpty(line))
{
continue;
}
if (one == null)
{
one = parsePacket(line);
}
else if (two == null)
{
two = parsePacket(line);
packets.Add((one, two));
one = null;
two = null;
}
}
}
private packet parsePacket(string line)
{
packet? curr = new();
StringBuilder sb = new();
for (int i = 1; i < line.Length-1; i++)
{
var ch = line[i];
switch (ch)
{
case '[':
packet embedded = new() { parent = curr };
curr!.entries.Add(embedded);
curr = embedded;
break;
case ']':
if (sb.Length > 0)
{
curr!.entries.Add(new entryint(int.Parse(sb.ToString())));
}
sb.Clear();
curr = curr!.parent;
break;
case ',':
if (sb.Length > 0)
{
curr!.entries.Add(new entryint(int.Parse(sb.ToString())));
}
sb.Clear();
break;
default:
sb.Append(ch);
break;
}
}
if (sb.Length > 0)
{
curr!.entries.Add(new entryint(int.Parse(sb.ToString())));
}
return curr!;
}
private bool? isValid((packet, packet) pair)
{
for (int i = 0; i < pair.Item1.entries.Count; i++)
{
if (pair.Item2.entries.Count <= i)
{
return false;
}
var left = pair.Item1.entries[i];
var right = pair.Item2.entries[i];
if (left is entryint li && right is entryint ri)
{
if (li.num < ri.num)
{
return true;
}
if (li.num > ri.num)
{
return false;
}
}
else if (left is packet ll && right is packet rl)
{
var valid = isValid((ll, rl));
if (valid.HasValue)
{
return valid;
}
}
else
{
var one = left as packet;
var two = right as packet;
if (left is entryint ei1)
{
one = new packet(ei1);
}
else if (right is entryint ei2)
{
two = new packet(ei2);
}
var valid = isValid((one!, two!));
if (valid.HasValue)
{
return valid;
}
}
}
if (pair.Item1.entries.Count < pair.Item2.entries.Count)
{
return true;
}
return null;
}
internal override string Part1()
{
List<int> validIndices = new();
for (int i = 0; i < packets.Count; i++)
{
var pair = packets[i];
var valid = isValid(pair);
if (valid != false)
{
validIndices.Add(i + 1);
}
}
return $"Sum of valid indices (1-based): <+white>{validIndices.Sum()}";
}
internal override string Part2()
{
var sentinels = new List<packet>
{
parsePacket("[[2]]"),
parsePacket("[[6]]"),
};
var l = new List<packet>(sentinels);
foreach (var p in packets)
{
l.Add(p.Item1);
l.Add(p.Item2);
}
l.Sort((a, b) => isValid((a, b)) != false ? -1 : 1);
int total = 1;
foreach (var s in sentinels)
{
total *= l.FindIndex(p => p.ToString() == s.ToString()) + 1;
}
return $"Sum of sentinel packet indices (1-based) after sorting: <+white>{total}";
}
}