This one seems like a doozy. The problem itself has a looooooong writeup, but it seems mostly to tell you how to implement this odd system. There's only a few ways to do it so.... it's just spending a while doing it.
I have a feeling there will be an efficiency of figuring out some form of caching where, because each starting state will have the same number of pulses with the same ending state for the system, it can loop.
enum ModuleType { Base, FlipFlop, Conjunction };
struct Pulse { string source, destination; bool isHigh; };
class Module
{
public:
ModuleType type;
bool isOn;
map<string, bool> lastPulse;
vector<string> destinations;
vector<Pulse> getNextDestinations(Pulse p)
{
switch(type)
{
case FlipFlop: return getFlipFlopDestinations(p);
case Conjunction: return getConjunctionDestinations(p);
default: return getBaseDestinations(p);
}
}
private:
vector<Pulse> getBaseDestinations(Pulse p)
{
vector<Pulse> toReturn;
for (auto d : destinations)
{
toReturn.push_back(Pulse{ p.destination, d, p.isHigh });
}
return toReturn;
}
vector<Pulse> getFlipFlopDestinations(Pulse p)
{
vector<Pulse> toReturn;
if (p.isHigh) return toReturn;
isOn = !isOn;
for (auto d : destinations)
{
toReturn.push_back(Pulse{ p.destination, d, isOn });
}
return toReturn;
}
vector<Pulse> getConjunctionDestinations(Pulse p)
{
vector<Pulse> toReturn;
lastPulse[p.source] = p.isHigh;
bool allHigh = true;
for (auto d : lastPulse) if (!d.second) allHigh = false;
for (auto d : destinations)
{
toReturn.push_back(Pulse{ p.destination, d, !allHigh });
}
return toReturn;
}
};
Not the cleanest definition, sure, but when I had originally tried with inheritence, getting the proper behavior for the different types just wasn't working; it was defaulting to the subtypes. I don't want to focus on that at the moment, so I just went with this.
Part 2 seems like a simple change. Check the incoming pulse as it comes in, store it's state. However, there were some really neat visualizations that show how the input is really set up - essentially a set of counters that go on a cycle. I'll have to be more clever about doing this rather than brute forcing - one person estimated that it would take about 6 years to brute force it.
I made a small change to my code, to get an idea if these DO go in any sort of cycle, similar to that graph, then I can probably find some cycles. I ran it for a bit, counting the number of cycles it would take for each Conjunction module to pulse low again, and after filtering out a few that pulse every single buttom press, I got this:
bf: 3761 presses (after 3761)
gm: 3767 presses (after 3767)
qr: 4001 presses (after 4001)
cx: 4091 presses (after 4091)
bf: 3761 presses (after 7522)
gm: 3767 presses (after 7534)
qr: 4001 presses (after 8002)
cx: 4091 presses (after 8182)
bf: 3761 presses (after 11283)
gm: 3767 presses (after 11301)
qr: 4001 presses (after 12003)
cx: 4091 presses (after 12273)
...
It's a cycle! Those four pulse high after exactly the same number of presses. My guess is that the answer is the four of those multiplied together - and it is!