2021aoc/Day16.cs

89 lines
2.5 KiB
C#

// #define Day16
#if Day16
var line = File.ReadAllText("day16/input");
Console.WriteLine(line);
// line = "8A004A801A8002F478";
string binarystring = String.Join(String.Empty,
line.Where(c => !Char.IsWhiteSpace(c)).Select(
c => Convert.ToString(Convert.ToInt32(c.ToString(), 16), 2).PadLeft(4, '0')
)
);
Console.WriteLine(binarystring);
int pos = 0;
long versionSum = 0;
Console.WriteLine(ParsePackage(ref pos, binarystring));
Console.WriteLine(versionSum);
long ParsePackage(ref int pos, string binary) {
var version = ParseTypeOrVersionId(ref pos, binary);
versionSum += version;
var type = ParseTypeOrVersionId(ref pos, binary);
if (type == 4) {
return ParseLiteral(ref pos, binary);
} else {
var lengthTypeId = ParseLength(ref pos, binary, 1);
if (lengthTypeId == 1) {
return ParseOperatorType1(ref pos, binary, type);
} else {
return ParseOperatorType0(ref pos, binary, type);
}
}
}
long ParseTypeOrVersionId(ref int pos, string binary) {
return ParseLength(ref pos, binary, 3);
}
long ParseLiteral(ref int pos, string binary) {
string res = String.Empty;
while (binary[pos] == '1') {
res += binary.Substring(pos + 1, 4);
pos += 5;
}
res += binary.Substring(pos + 1, 4);
pos += 5;
return Convert.ToInt64(res, 2);
}
long ParseLength(ref int pos, string binary, int length) {
var id = binary.Substring(pos, length);
pos += length;
return Convert.ToInt64(id, 2);
}
long ParseOperatorType0(ref int pos, string binary, long type) {
long length = ParseLength(ref pos, binary, 15);
long originalPos = pos;
List<long> values = new List<long>();
while (originalPos+length > pos) {
values.Add(ParsePackage(ref pos, binary));
}
return Calculate(type, values);
}
long ParseOperatorType1(ref int pos, string binary, long type) {
long numberOfSubPackages = ParseLength(ref pos, binary, 11);
List<long> values = new List<long>();
for (int i = 0; i < numberOfSubPackages; i++) {
values.Add(ParsePackage(ref pos, binary));
}
return Calculate(type, values);
}
long Calculate(long type, List<long> values) => (type) switch {
0 => values.Sum(),
1 => values.Aggregate(1L, (acc, val) => acc * val),
2 => values.Min(),
3 => values.Max(),
5 => values[0] > values[1] ? 1 : 0,
6 => values[0] < values[1] ? 1 : 0,
7 => values[0] == values[1] ? 1 : 0,
_ => throw new ArgumentException("not defined")
};
#endif