Okay, the second one today. I took a break to go shopping for a white elephant gift, and it's... obnoxious and I love it. Whoever gets this gift is going to enjoy it. Or hate it. I'm not sure.
Either way, I'm going to do another AoC before I head over to that party.
This looks familiar... not quite the same, but the input has a similar format. I'll do something similar to what I did last year and make a nested class for it. It'll either be just a number, or a list of other itself.
For the sample code, they have a decent order of simple-to-complex rules and examples. I'll just keep building this out until all of the samples work, one-at-a-time. Annoyingly, the input data has digits 0
-10
, which means because of 10
existing, I can't just look at the characters. I have to actually be a little smart about parsing.
class PacketList {
public:
enum Type { Number, List } type;
int num;
vector<PacketList> items;
PacketList(int n) { type = Number; num = n; }
PacketList(string s)
{
type = List;
// Strip outermost brackets
s = s.substr(1, s.size()-2);
int i = 0;
while (i < s.size())
{
switch(s[i])
{
// Somehow a comma, just move on
case ',': i++; break;
// If list, find matching close bracket and call recursively
case '[':
{
int bracketCount = 1, j = i + 1;
while (bracketCount > 0)
{
switch (s[j++])
{
case '[': bracketCount++; continue;
case ']': bracketCount--; continue;
}
}
items.push_back(PacketList(s.substr(i, j-i)));
i = j+1;
break;
}
// Assumed digit
default:
{
int t = 0;
while (i < s.size() && s[i] != ',')
{
t *= 10;
t += s[i] - '0';
i++;
}
items.push_back(PacketList(t));
i++;
break;
}
}
}
}
};
Maybe not the cleanest code, but it works. There was probably an easier way, but this runs efficiently enough. Now to tackle the actual comparison logic.
// -1 == false, 1 == true, 0 == continue
int Compare (PacketList left, PacketList right)
{
int i = 0;
while(i < left.items.size())
{
if (right.items.size() <= i) return -1;
PacketList l = left.items[i];
PacketList r = right.items[i];
// Convert number to list, if necessary
if (l.type != r.type) { l.convert(); r.convert(); }
switch (l.type)
{
case PacketList::Type::Number:
if (l.num < r.num) return 1;
if (l.num > r.num) return -1;
i++;
continue;
case PacketList::Type::List:
{
int result = Compare(l, r);
if (result > 0) return 1;
if (result < 0) return -1;
i++;
continue;
}
}
}
if (left.items.size() < right.items.size()) return 1;
return 0;
}
Shockingly easy to do once I had the data structure down!
Oookay, now it's time to order packets? Hmm. I made a comparitor already, so I just need to put everything into a list and compare everything together using sort()
. Will that work though?
It did. It was that simple. I just needed to add a wrapper function to convert it to a bool
.
bool CompareSort(PacketList left, PacketList right)
{
return Compare(left, right) == 1;
}
//...
sort(packets.begin(), packets.end(), CompareSort);
Amazingly easy. It taught me to make a comparitor function just to compare two, then had me do it for a sort function. Awesome that it just worked immediately.