Binary Puzzle
I said we'd take a little detour to make a fully functional puzzle using our two buttons and two lights and so I present to you, a Binary Puzzle. I have made two binary style puzzles before, one was purely mechanical, and the other one used a cabinet lock and a series of switches to activate it (but no blog post). Both of these are simpler ways of making the same puzzle so we need this to be different somehow. Since we have the full power of a microcontroller why not make the codes change over time. Every time you fail to enter the code correctly it will change the code, so let's dig into the system.
For the game play, the system is going to flash a binary code to the player that matches one of the codes on the left hand side of the panel. The player is then required to input the corresponding binary code from the right hand side of the panel as indicated by the arrows. The system should repeat the code so that the player has multiple chances to confirm which code is being used. The player should have one opportunity to input the correct code, the system should indicate if the code is correct or incorrect and if it is incorrect the system should randomly select a new code and let the player try again. This allows us to define some initial states or operation. We also need to define a list of the different codes and answers.
The code in the previous tutorials is set up in a way to control the inputs and outputs and this framework is great for this game. We need to add some code that actually controls the game, this is done after all the inputs have been read and before the outputs are controlled. The code to flash the LEDs has some specific timing requirements so it's best to extract that to its own function rather than keeping it in the switch code block. The system has a 25ms loop time which is far to quick for the player to see a flashing LED so we need to keep the LED on for multiple loops, we also loop through all eight bits within the byte and there needs to be a delay before the pattern repeats so the player can work out which bit is the start of the byte.
The displayCode function makes use of a global counter, displayCount, to keep track of timing and which bit should be display next. It also creates all the gaps between the bits and bytes being displayed. At any point during this flash sequence the player could push a button and interrupt the process as they try and input the solution. A button push should trigger a switch to the next game state but we should also record the button because it will be the first bit of their answer.
As each new button is pressed the value should be recorded and added to the answer but it's also really important to provide some kind of feed back to the player that the button push has been acknowledged so in this case the code flashes the LED next to the button for as long as the player holds the button down. This doesn't work during the initial press when the game changes states but human response times mean that the button will be held down for more than one loop so the button will still be down when the game switches to this new state. Once the player has input eight button presses the game needs to switch to the next state and check the code.
The code checking and response is actually quite simple because we already built the framework to display different states on the LED. If the code is correct we can fade the LEDs, the smooth animation makes it look like the system is functioning correctly. If the code is incorrect we can flicker the LEDs which make it look like there's a problem with the system. The only minor issue is that we need to dwell in these states to allow the user time to acknowledge them before resetting the system. The global displayCount variable can be used again create these delays. Finally we can reset the system, this function just resets all of the global variables but it also switches to a new code. It selects a new code randomly but it checks it against the current code and if it randomly picked the same code, it will try again. This ensures that it doesn't go back to the same code again.
Making this 'simple' puzzle reminded me of the importance of play testing everything. While trying to figure out what to do, my wife only pushed four buttons, stopped to think about it and then tried to put all eight digits in. Of course it reset halfway through the second input sequence. The solution is to add a timeout to the InputCode section, if the use starts to press buttons but stops for more than 5 seconds the system should timeout, move onto the next section where the code will be incorrect and the system will display this to the player before resetting. It's a simple change but also vital for the player interaction.
The full code for this can be found on my github repository
https://github.com/msraynsford/Puzzling/
https://github.com/msraynsford/Puzzling/