// #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 values = new List(); 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 values = new List(); for (int i = 0; i < numberOfSubPackages; i++) { values.Add(ParsePackage(ref pos, binary)); } return Calculate(type, values); } long Calculate(long type, List 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