#pragma warning disable CS8600 //Because fuck warnings, that's why
class Program
{
static void Main(string[] args)
{
string input;
Dictionary<char, string> hexMap = new Dictionary<char, string>();
hexMap.Add('0', "0000");
hexMap.Add('1', "0001");
hexMap.Add('2', "0010");
hexMap.Add('3', "0011");
hexMap.Add('4', "0100");
hexMap.Add('5', "0101");
hexMap.Add('6', "0110");
hexMap.Add('7', "0111");
hexMap.Add('8', "1000");
hexMap.Add('9', "1001");
hexMap.Add('A', "1010");
hexMap.Add('B', "1011");
hexMap.Add('C', "1100");
hexMap.Add('D', "1101");
hexMap.Add('E', "1110");
hexMap.Add('F', "1111");
using (StreamReader sr = new StreamReader(@"../../../../Input.in"))
{
input = sr.ReadLine();
}
string bits = "";
foreach (char c in input)
{
bits += hexMap[c];
}
Packet recv = new Packet();
recv.Read(bits, false, 0);
long sumVer = VersionSum(recv);
ulong ans = Eval(recv);
Console.WriteLine("The sum of version numbers is " + sumVer.ToString());
Console.WriteLine("The evaluated expression sent gives " + ans.ToString() + " as a result");
}
static long VersionSum(Packet p)
{
long subSum = 0;
if (p.subPackets.Count == 0)
{
return p.version;
}
else
{
foreach (Packet s in p.subPackets)
{
subSum += VersionSum(s);
}
subSum += p.version;
}
return subSum;
}
public static ulong Eval(Packet p)
{
if (p.typeID == 4) return p.literalValue;
else
{
switch (p.typeID)
{
case 0:
ulong sumValue = 0;
foreach (Packet s in p.subPackets)
sumValue += Eval(s);
return sumValue;
case 1:
ulong prodValue = 1;
foreach (Packet s in p.subPackets)
prodValue *= Eval(s);
return prodValue;
case 2:
ulong minValue = ulong.MaxValue;
foreach (Packet s in p.subPackets)
{
ulong curr = Eval(s);
minValue = curr < minValue ? curr : minValue;
}
return minValue;
case 3: // this is a maximum of sub breaks
ulong maxValue = ulong.MinValue;
foreach (Packet s in p.subPackets)
{
ulong curr = Eval(s);
maxValue = curr > maxValue ? curr : maxValue;
}
return maxValue;
case 5: // this is a greater than of sub breaks
ulong sub1 = Eval(p.subPackets[0]);
ulong sub2 = Eval(p.subPackets[1]);
return (ulong)(sub1 > sub2 ? 1 : 0);
case 6: // this is a less than of sub breaks
sub1 = Eval(p.subPackets[0]);
sub2 = Eval(p.subPackets[1]);
return (ulong)(sub1 < sub2 ? 1 : 0);
case 7: // this is a equal than of sub breaks
sub1 = Eval(p.subPackets[0]);
sub2 = Eval(p.subPackets[1]);
return (ulong)(sub1 == sub2 ? 1 : 0);
}
}
return 0;
}
}
public class Packet
{
public int version;
public int typeID;
public List<Packet> subPackets;
public int lengthTypeID;
public ulong literalValue;
public Packet()
{
subPackets = new List<Packet>();
}
public int Read(string packetSTR, bool isSub, int packetStart)
{
int totBitsRead = 0;
string verStr = packetSTR.Substring(packetStart, 3);
string typeStr = packetSTR.Substring(packetStart + 3, 3);
totBitsRead += 6;
version = Convert.ToInt32(verStr, 2);
typeID = Convert.ToInt32(typeStr, 2);
if (typeID != 4)
{
lengthTypeID = Convert.ToInt32(packetSTR.Substring(packetStart + totBitsRead, 1), 2);
totBitsRead += 1;
if (lengthTypeID == 0) //read 15 bits to get total length of sub packets in bits
{
int subPacketsTotLength = Convert.ToInt32(packetSTR.Substring(packetStart + totBitsRead, 15), 2);
totBitsRead += 15;
int subPacketBits = 0;
int offset = 0;
//Console.WriteLine("Length Type:{0}, Sub Packet Bit Length:{1}",lengthTypeID, subPacketsTotLength);
while (subPacketBits < subPacketsTotLength)
{
Packet sub = new Packet();
offset = sub.Read(packetSTR, true, packetStart + totBitsRead);
subPacketBits += offset;
totBitsRead += offset;
subPackets.Add(sub);
}
}
else // read 11 bits which is number of packets to read
{
int numPackets = Convert.ToInt32(packetSTR.Substring(packetStart + totBitsRead, 11), 2);
totBitsRead += 11;
int offset = 0;
//Console.WriteLine("Length Type:{0}, numPackets:{1}", lengthTypeID, numPackets);
for (int i = 0; i < numPackets; i++)
{
Packet sub = new Packet();
offset = sub.Read(packetSTR, true, packetStart + totBitsRead);
totBitsRead += offset;
subPackets.Add(sub);
}
}
}
else
{
int bitsRead;
//Console.WriteLine("Reading Literal");
(bitsRead, literalValue) = ParseType(packetSTR.Substring(packetStart + 6), isSub);
//Console.WriteLine("Read Literal bitsRead:{0}, litValue:{0}", bitsRead, literalValue);
totBitsRead += bitsRead;
}
return totBitsRead;
//Console.WriteLine("Finished reading packet");
}
public (int, ulong) ParseType(string literalPayload, bool isSub)
{
string payload = "";
bool foundZero = false;
int numChunks = 0;
while (!foundZero)
{
string chunk = literalPayload.Substring(numChunks * 5, 5);
if (chunk[0] == '0')
{
foundZero = true;
}
payload += chunk.Substring(1, 4);
numChunks++;
}
ulong litValue = Convert.ToUInt64(payload, 2);
int bitsRead = numChunks * 5;
return (bitsRead, litValue);
}
}