Source: https://mokxi.com/learn/arduino-whack-a-mole

Learn

# A whack-a-mole game on an Arduino

Intermediate

Written by the Mokxi team

Start building free Open the editor

Or see every lesson.

- 455 parts on the bench
- 43 boards running now
- 1.00x real time, on every board

Press any button to start a round

The Whack-a-mole example: four lamps, four buttons, a piezo and a TM1637. Press any button to start a thirty-second round.

In whack-a-mole a light pops up and you hit the button under it before it goes out. It is a great party game and a great project, because it is the first one where the Arduino has to do several things at once: time the round, time each mole, read four buttons, beep, and update a display, all without waiting on any one of them.

The circuit above is an Arduino Uno with four LED moles, a button under each, a passive buzzer and a TM1637 four-digit display. Press any button to start a thirty-second round. The display shows the seconds left on the left and your score on the right. Each hit scores a point and makes the next mole a little quicker; a wrong button costs a point. When time runs out the display shows your best score of the session.

## What you need

- An Arduino Uno
- Four LEDs and four 220 ohm resistors
- Four pushbuttons
- A passive buzzer (piezo)
- A TM1637 four-digit display
- A breadboard and jumper wires

## Wiring

Part and pin | Goes to | Note

Mole LEDs 1 to 4, through 220 ohm | Pins 2, 3, 4, 5 | Cathodes to GND

Buttons 1 to 4 | Pins 6, 7, 8, 9 | Other leg to GND, INPUT_PULLUP; button 1 under mole 1

Piezo | Pin 10 | Other leg to GND

TM1637 CLK | A0 | Analog pins work as digital pins

TM1637 DIO | A1 |

TM1637 VCC and GND | 5 V and GND |

## Doing five things at once

The sketch never calls a long delay(). Instead loop() runs every 5 ms and asks a few questions about the clock. Is the round over? Is the lit mole past its time? Is it time for the next mole? It keeps the answers in a handful of variables: when the round started, when the current mole goes back down, and when the next one pops up.

That is the pattern behind every game, robot and gadget that has to watch more than one thing. Compare it with delay(900) to keep a mole up: during those 900 ms the buttons would not be read at all, and every hit would be missed.

The buttons are read for new presses only. Each button’s state from the last pass is kept in wasDown[], and a press counts when the pin is down now and was up last time. Holding a button scores once, not every 5 ms.

## Getting harder as you score

A mole starts out up for 900 ms. Every hit takes 30 ms off, until it would drop below 380 ms. Do the sum and the 18th hit is the last to shorten it, to 360 ms, which is fast for most people. A wrong button costs a point but does not slow the game back down.

Which mole comes next is random, and a mole never pops up under the button you just pressed. The random number generator is seeded from micros() at the first press, which is a person’s reaction time and something nothing can predict. Without that, every session would play the same moles in the same order.

Each sound is a short tone(): 1047 Hz to start, 1568 Hz for a hit, a low 147 Hz for a miss and 392 Hz at the end. Because tone() with a length runs on a timer, the beep plays while the game carries on.

The core of loop()

## The score display

The TM1637 takes two wires and draws four digits with a colon. showNumberDecEx(seconds * 100 + score, 0b01000000, true) puts the seconds on the left, the score on the right, the colon between them and leading zeros on. Between rounds, two dashes and the best score show instead.

The comparisons with (int32_t)(now - moleUntil) >= 0 look odd but matter: they keep working when millis() rolls over after about 49 days, which a plain now >= moleUntil does not.

## Common mistakes

Using delay() to time the moles. The buttons go deaf while it waits. Use millis() as the sketch does.

Counting a held button as many hits. Score on the change from up to down, not on "is down".

An active buzzer instead of a passive one. An active buzzer has its own oscillator and plays one pitch whatever tone() asks for. The four different sounds need a passive piezo.

A blank display. Check CLK and DIO are not swapped and that the display has 5 V and GND.

Moles that never move. If randomSeed() is called in setup() with a fixed number, or not at all, the order repeats every time. Seed from the first press.

## Questions

How do I make a whack-a-mole game with Arduino?

Wire four LEDs and four buttons, light a random LED, record when it lit with millis(), and score a point if its button is pressed before a time limit. Shorten the limit after each hit and end the round after thirty seconds.

Can I use arcade buttons with built-in lights?

Yes. Wire the button switch like a pushbutton and the lamp like the LED, through the right resistor for its voltage. Mokxi has lit arcade buttons in its parts list.

How do I keep a high score after power off?

Save it with EEPROM.put() when a round beats it and read it with EEPROM.get() in setup(). The Uno’s EEPROM is good for about 100,000 writes per cell, so write only on a new best.

Can this run on an Arduino Nano?

Yes. The Nano has the same chip and the same pin numbers, so the sketch runs unchanged.

Related

## Keep going

Arduino Game Projects You Can Play in Your Browser Arduino Blink Without Delay: Two LEDs, Two Rates Arduino TM1637 Display: Library and Countdown Arduino Simon Says Game: Four LEDs, Four Buttons Arduino Tone Melody: Play a Song on a Piezo The Whack-a-mole project Intermediate The Arduino Uno simulator The TM1637 display, pin by pin The project page, with the full sketch Intermediate

## Build this for real

Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.

Start building free Open the editor
