Whack a Mole Game
A Game Using Random Numbers
We will make a game where light blink at random and you must move the joystick towards the light. If you do you will continue on, if you move to in the direction of the wrong light or you wait too long you get a strike against you, 3 strikes and you are out.
Random Lights
We will use the code from the prior lesson to set up the blinking lights. We will modify it a little to use only 4 lights. Start with the code below, There has been a little clean up of this code, specifically the testLED function was rewritten to use the lightLEDs function and setUp was moved to just before loop. The result is the same.
const int xStick = A0; //global constants for pin connections const int yStick = A1; const int white = 3; const int blue = 4; const int green = 5; const int yellow = 6; const int red = 7; void testLED() { //Turn them all on to test lightLEDs(1, 0, 0, 0, 0); delay(500); lightLEDs(1, 1, 0, 0, 0); delay(500); lightLEDs(1, 1, 1, 0, 0); delay(500); lightLEDs(1, 1, 1, 1, 0); delay(500); lightLEDs(1, 1, 1, 1, 1); delay(500); //Then turn them off lightLEDs(1, 1, 1, 1, 0); delay(500); lightLEDs(1, 1, 1, 0, 0); delay(500); lightLEDs(1, 1, 0, 0, 0); delay(500); lightLEDs(1, 0, 0, 0, 0); delay(500); lightLEDs(0, 0, 0, 0, 0); delay(500); } void lightLEDs(bool redState, bool yellowState, bool greenState, bool blueState, bool whiteState) { digitalWrite(red, redState); digitalWrite(yellow, yellowState); digitalWrite(green, greenState); digitalWrite(blue, blueState); digitalWrite(white, whiteState); } //function to get the joystick value, returns and integer int getJoystick(int stickPin) { int val = analogRead(stickPin); return val; } void lightShow(int val) { if (val < 150) lightLEDs(0, 0, 0, 0, 0); else if (val < 300) lightLEDs(1, 0, 0, 0, 0); else if (val < 450) lightLEDs(0, 1, 0, 0, 0); else if (val < 600) lightLEDs(0, 0, 1, 0, 0); else if (val < 750) lightLEDs(0, 0, 0, 1, 0); else lightLEDs(0, 0, 0, 0, 1); } void randomLights() { int lights = random(0, 5); Serial.print("light = "); Serial.println(lights); switch (lights) { case 0: lightLEDs(1, 0, 0, 0, 0); break; case 1: lightLEDs(0, 1, 0, 0, 0); break; case 2: lightLEDs(0, 0, 1, 0, 0); break; case 3: lightLEDs(0, 0, 0, 1, 0); break; case 4: lightLEDs(0, 0, 0, 0, 1); break; default: // statements break; } } void setup() { // put your setup code here, to run once: Serial.begin(9600); //start a serial connection //Set LED s as output pinMode(white, OUTPUT); pinMode(blue, OUTPUT); pinMode(green, OUTPUT); pinMode(yellow, OUTPUT); pinMode(red, OUTPUT); testLED(); } void loop() { // put your main code here, to run repeatedly: randomLights(); delay(200); }
to make the change to only 4 lights we just change the random number generator line
int lights = random(0, 5);
change to:
int lights = random(0, 4);
This will now blink only 4 lights. Try it with the existing circuit from the previous lesson. Next we will change the circuit.
Circuit for the "Mole Field"
Rearrange the LED lights to make a symmetric mole field with one up, one down and one right and one left. We will use 4 new LEDs and resistors but use the same wires from before. For simplicity we are using the negative blue line on both sides of the board so that must be connected across, done with the black jumper wire. In this case I am relying on your knowledge of circuits to build this from the photo. Of it is not clear take a look back at the circuit lesson .
![mole leds](/sites/default/files/images/moleField.jpg)
4 LED circuits arranged in a cross Top, Right, Bottom, and Left. Each LED circuit has a 220 ohm resistor connected to GND. The pin connections are: Top to pin 7, Right to pin 6, Bottom to pin 5, and Left to pin 4. don't forget the black jumper wire on the right that is connecting the two negative lines together.
Using the Joystick to Whack a Mole
We will use the joystick to whack the moles. If the Top mole light is lit you push the joystick up, if the Right light is lit push the joystick to the right and so on. We need some way to read the joystick and know if it was moved in the correct direction. lets look again at the hardware and circuit
![Joystick axis](/sites/default/files/images/joyXY.jpg)
Looking at the joystick with the wires at the bottom, we have Y as the up and down axis and X as the right and left axis. in the joystick lesson we connected these to analog pins X to A1 and Y to A0. When we do analogRead(A1) we get the value of X from 0 to 1023, full right is 1023, full left is 0. Similarly when we do analogRead(A0) we get the Y value from 0 to 1023 with full up being 1023 and full down being 0. The center of both is about 512.
Code for the Whack
First we need to know which light was lit. We will do this by changing our randomLights function from a void to an int. The int function will return an integer value when called. In this case the value will be which random number was selected. We get this value back when we make this call:
int mole = randomLights();
now the variable mole will have the value of the random number indicating which light is lit. the new function looks like this. Note that now it is type int and has a return as the last line.
int randomLights() { int lights = random(0, 4); Serial.print("light = "); Serial.println(lights); switch (lights) { case 0: lightLEDs(1, 0, 0, 0, 0); break; case 1: lightLEDs(0, 1, 0, 0, 0); break; case 2: lightLEDs(0, 0, 1, 0, 0); break; case 3: lightLEDs(0, 0, 0, 1, 0); break; case 4: lightLEDs(0, 0, 0, 0, 1); break; default: // statements break; } return lights; }
Now that we have the value of mole we can check if the joystick is moved in the correct direction. If the Top mole light is lit mole = 0 then the joystick value should be Y=1023, X = 512 anything else is a miss. Similar for the other lights. let's set these conditions.
- 0 Top Y < 600
- 1 Right X >600
- 2 Bottom Y < 400
- 3 Left X < 400
Each time we set a randomLight we need to then check the value of the joystick and see if it meets the condition of a hit.
Boolean Function to check for a hit
We write the boolean function checkWhack. A boolean function will return true or false, in this case true means we hit the mole and false indicates a miss. So we start by setting up some variables:
bool checkWhack(int mole)//mole indicates which mole is lit { int xWhack; //joystick X value int yWhack; // joystick Y value int count = 0; // a loop counter int timeOut = 300; // how many loops to wait for a whack bool done = false; //breaks the loop when true bool hit = false; // true is a hit false is a miss
Next we loop until the joystick is moved or the timeOut is reached:
while (done == false && count < timeOut)
We get the value of the joystick each time through the loop and then check to see if it moved. When the joystick is moved the If condition is true
xWhack = getJoystick(A1); yWhack = getJoystick(A0); if (xWhack >= 600 || xWhack <= 400 || yWhack >= 600 || yWhack <= 400) //checks if user moved Joystick
Then we set done to true and use the switch case to see if we have a hit.
{ done = true; //check if they moved it towards the lit light switch (mole) { case 0: if (yWhack >= 600) hit = true; break; case 1: if (xWhack >= 600) hit = true; break; case 2: if (yWhack <= 400) hit = true; break; case 3: if (xWhack <= 400) hit = true; break; default: // statements break; }
Since done is now true the while loop will break and we return the value of hit. if the joystick was not moved we wait 10 msec , increment the counter and loop again.
The complete function is here:
bool checkWhack(int mole) //mole indicates which mole is lit { int xWhack; //joystick X value int yWhack; // joystick Y value int count = 0; // a loop counter int timeOut = 300; // how many loops to wait for a whack bool done = false; //breaks the loop when true bool hit = false; // true is a hit false is a miss while (done == false && count < timeOut) { xWhack = getJoystick(A1); yWhack = getJoystick(A0); if (xWhack >= 600 || xWhack <= 400 || yWhack >= 600 || yWhack <= 400) //checks if user moved Joystick { done = true; //check if they moved it towards the lit light switch (mole) { case 0: if (yWhack >= 600) hit = true; break; case 1: if (xWhack >= 600) hit = true; break; case 2: if (yWhack <= 400) hit = true; break; case 3: if (xWhack <= 400) hit = true; break; default: // statements break; } } delay(10); count++; } lightLEDs(0, 0, 0, 0, 0); return hit; }
Code for Hit or Miss Indicator
We will use the 5th LED to indicate a hit. The checkWhack function returns true indicating a hit or false if it is a miss. We use this as the condition in an if statement. if hit is true we light the 5th LED, if hit is false all the moles pop up and laugh at you. This is indicted by blinking the mole lights.
here is the code needed in the loop to implement this:
void loop() { int mole = randomLights(); if (checkWhack(mole) == true) { lightLEDs(0, 0, 0, 0, 1); //light the 5th LED } else { lightLEDs(1,1,1,1,0); delay(200); lightLEDs(0,0,0,0,0); delay(200); lightLEDs(1,1,1,1,0); delay(200); lightLEDs(0,0,0,0,0); delay(200); lightLEDs(1,1,1,1,0); } delay(1000); }
Example CODE
Here is the complete working code
const int xStick = A0; //global constants for pin connections const int yStick = A1; const int white = 3; const int blue = 4; const int green = 5; const int yellow = 6; const int red = 7; void testLED() { //Turn them all on to test lightLEDs(1, 0, 0, 0, 0); delay(500); lightLEDs(1, 1, 0, 0, 0); delay(500); lightLEDs(1, 1, 1, 0, 0); delay(500); lightLEDs(1, 1, 1, 1, 0); delay(500); lightLEDs(1, 1, 1, 1, 1); delay(500); //Then turn them off lightLEDs(1, 1, 1, 1, 0); delay(500); lightLEDs(1, 1, 1, 0, 0); delay(500); lightLEDs(1, 1, 0, 0, 0); delay(500); lightLEDs(1, 0, 0, 0, 0); delay(500); lightLEDs(0, 0, 0, 0, 0); delay(500); } void lightLEDs(bool redState, bool yellowState, bool greenState, bool blueState, bool whiteState) { digitalWrite(red, redState); digitalWrite(yellow, yellowState); digitalWrite(green, greenState); digitalWrite(blue, blueState); digitalWrite(white, whiteState); } //function to get the joystick value, returns and integer int getJoystick(int stickPin) { int val = analogRead(stickPin); return val; } void lightShow(int val) { if (val < 150) lightLEDs(0, 0, 0, 0, 0); else if (val < 300) lightLEDs(1, 0, 0, 0, 0); else if (val < 450) lightLEDs(0, 1, 0, 0, 0); else if (val < 600) lightLEDs(0, 0, 1, 0, 0); else if (val < 750) lightLEDs(0, 0, 0, 1, 0); else lightLEDs(0, 0, 0, 0, 1); } int randomLights() { int lights = random(0, 4); Serial.print("light = "); Serial.println(lights); switch (lights) { case 0: lightLEDs(1, 0, 0, 0, 0); break; case 1: lightLEDs(0, 1, 0, 0, 0); break; case 2: lightLEDs(0, 0, 1, 0, 0); break; case 3: lightLEDs(0, 0, 0, 1, 0); break; case 4: lightLEDs(0, 0, 0, 0, 1); break; default: // statements break; } return lights; } bool checkWhack(int mole) //mole indicates which mole is lit { int xWhack; //joystick X value int yWhack; // joystick Y value int count = 0; // a loop counter int timeOut = 300; // how many loops to wait for a whack bool done = false; //breaks the loop when true bool hit = false; // true is a hit false is a miss while (done == false && count < timeOut) { xWhack = getJoystick(A1); yWhack = getJoystick(A0); if (xWhack >= 600 || xWhack <= 400 || yWhack >= 600 || yWhack <= 400) //checks if user moved Joystick { done = true; //check if they moved it towards the lit light switch (mole) { case 0: if (yWhack >= 600) hit = true; break; case 1: if (xWhack >= 600) hit = true; break; case 2: if (yWhack <= 400) hit = true; break; case 3: if (xWhack <= 400) hit = true; break; default: // statements break; } } delay(10); count++; } lightLEDs(0, 0, 0, 0, 0); return hit; } void strikeLights(int lights) { } void setup() { // put your setup code here, to run once: Serial.begin(9600); //start a serial connection //Set LED s as output pinMode(white, OUTPUT); pinMode(blue, OUTPUT); pinMode(green, OUTPUT); pinMode(yellow, OUTPUT); pinMode(red, OUTPUT); testLED(); } void loop() { int mole = randomLights(); if (checkWhack(mole) == true) { lightLEDs(0, 0, 0, 0, 1); //light the 5th LED } else { lightLEDs(1,1,1,1,0); delay(200); lightLEDs(0,0,0,0,0); delay(200); lightLEDs(1,1,1,1,0); delay(200); lightLEDs(0,0,0,0,0); delay(200); lightLEDs(1,1,1,1,0); } delay(1000); }