I watched Robert Martin's programming 101 video. I'll explain what problem he talks about in the video for those of you who haven't watched it.
Robert Martin is in his house and shows a light switch. If this switch goes up, a light is on. If switch goes down, the light is off. He wrote a code to handle it. This is simple but the situation is getting more complicated when he shows second, third and fourth light switch. All of them change state of the same light. Each of them is dependent on the others. He also shows how to handle it in a code.
Robert Martin explains that this code is not the best solution because there can be a situation when two people come to the same room and they want to turn the light on. He demonstrated that the code he has written doesn't work well because the light doesn't change its state. It's happening because a computer doesn't see simultaneous events. One of them occurs first. That's happening when two people want to turn on the light. It happens simultaneously only from human perspective. For a computer one person changes state of the light first so in fact the state of the light is changed twice. Fortunately Uncle Bob shows how to solve this problem. He measures time elapsed from the last light state change. If the next change is happening in 500 ms, he rejects it. Now when two people want to turn the light on the light is actually on.
Unfortunately implementing above solution breaks a case when one person quickly turns on and turns off the light. Because the second change is happening in 500 ms it is rejected. So it is not possible to quickly turn on and turn off the light. Uncle Bob didn't show how to solve this problem. He left it as a homework.
It took me long to figure it out how can I solve this but finally I've came to a working solution. I'm not sure though if my solution is good or maybe I only think it is good. Can you tell me if I solved the problem correctly or there is a better solution?
Uncle Bob's code looks like this:
void lightLogic() {
boolean a = switchA.isUp();
boolean b = switchB.isUp();
boolean c = switchC.isUp();
boolean d = switchD.isUp();
int currentSwitchState = 0;
int base=10;
if (a) currentSwitchState += base*base*base;
if (b) currentSwitchState += base*base;
if (c) currentSwitchState += base;
if (d) currentSwitchState += 1;
int currentTime = millis();
if (currentSwitchState != lastSwitchState) {
if (currentTime - lastChangeTime > 500) {
light.state = !light.state;
lastChangeTime = currentTime;
}
}
lastSwitchState = currentSwitchState;
}
I introduced a new variable called penultimateSwitchState and I check if the current state of the light equals to penultimate state. If yes, I know that the same switch has been used to change light state so I accept that change:
void lightLogic() {
boolean a = switchA.isUp();
boolean b = switchB.isUp();
boolean c = switchC.isUp();
boolean d = switchD.isUp();
int currentSwitchState = 0;
int base=10;
if (a) currentSwitchState += base*base*base;
if (b) currentSwitchState += base*base;
if (c) currentSwitchState += base;
if (d) currentSwitchState += 1;
int currentTime = millis();
if (currentSwitchState != lastSwitchState) {
if ((currentTime - lastChangeTime > 500) || (penultimateSwitchState == currentSwitchState)) {
light.state = !light.state;
lastChangeTime = currentTime;
}
penultimateSwitchState = lastSwitchState;
}
lastSwitchState = currentSwitchState;
}
}