Welcome back to the Digilent Blog!
At one point or another, we have all played the “Simon Says” game. In this game, one person, Simon (or Susan, Chad, or whoever happens to be the leader), will say “Simon says” and tell all of the other players to do something, such as raise their left hand. The catch in this game is that if the leader tells the other players to do something without saying the words “Simon says” and the other players do it anyway, they’re out. I personally really enjoy playing Simon Says, but I thought it could even be more fun if you could play Simon Says with a bunch of LEDs…
So that’s exactly what I did. Using a set of nine LEDs, two PmodBTNs (four user buttons on each), a single additional button, and a shift register, I was able to create Simon Says with it being just as fun as I was hoping it would be. Granted, the chipKIT uC32 I designed the game on always gets to be Simon and pressing buttons to make LEDs light up in the same pattern that the uC32 made them isn’t a super intensive cardio workout, but I’m okay with that.
What some of you may be interested in is how I made the game work–how the game compared the user guess to the original pattern, how the person playing the game knew if they got the answer right or wrong, and how the microcontroller came up with the random patterns in the first place.
The comparison between the user guess and the original pattern of LEDs that was provided was done through two arrays. One array kept track of what numbers the uC32 had generated, which corresponded to which LEDs were lit up in the pattern. A second array similarly kept track of which LED was lit up through the player pressing the corresponding button. Once the player was done lighting up the LEDs in the (hopefully) correct order, they press the isolated button off to the far left to light up the single yellow LED, thus submitting their “final answer”.
The uC32 then compares the two arrays, number by number, to see if they match. If the arrays do match, the four green LEDs are flashed a few times to show the player that they got the pattern right and the length of the pattern that they have to match increases by 1.
However, if the two arrays do not match, the red LEDs will flash and the length of the pattern goes back down to just one LED. To make sure that the two arrays aren’t accidentally different somehow, the values of the arrays are both internally reset to all zeros before a new pattern of LEDs (of any length) is displayed.
But how did the microcontroller come up with the “random” patterns? Electronic chips, such as the PIC32 chip from Microchip, do not have any way to arbitrarily come up with a number of some kind, but what the chip on the uC32 does have is a very long sequence of numbers. This sequence of numbers is accessed through the random() function, which chooses a number based on the bounds that you give it. For example, with the eight LEDs that could be lit up, the random() function is written as random(1,9) to choose a number ranging from 1 to 8. The upper number given in the random() function is presumed to be 1 greater than the desired output range of the random() function.
While this is nice, we would find that every time we play Simon Says that the pattern of LEDs that light up will always be the same because the number sequence which random() pulls from is always the same. To get around this and make the game more “random” we can call the randomSeed() function before using the random() function. RandomSeed() will tell the microcontroller where to start pulling numbers from in the number sequence based on what value we give it. Thus, we could tell randomSeed() to get a value based off the analog noise of one of the I/O pins on the microcontroller, getting us a “random” place to start in our number sequence with the random() function.
However, it has been my experience that the electrical noise on a pin tends to be restricted to a very small range of numbers, such as 0 to 5, which is not quite as arbitrary as I would like. So, I instead have the randomSeed() collect its number from the function millis(), which reports the value on the continually running time counter that lasts for nearly 50 days. By using millis(), where the random() function pulls its values from is inherently dependent on how long the player takes to submit their answer. Presuming the player is human instead of another microcontroller, this method guarantees that a different place in the number sequence will be chosen every time the game is played.
You can get the code I used for the game in the text file below (right click on it to open it in a new tab). If you want a little more instruction on how to create the circuit itself, feel free to check out my Instructable for it here. I’ve also included a link below to my code for the project.
Keep coming back to the Digilent Blog to see the other cool things that are always happening here at Digilent!