Lights and sounds can react instantly. A game or safe must also remember what happened before.
This lesson your Arduino becomes a rule keeper. It will know whether a reaction round is waiting, ready, or finished—or whether a toy safe is on the first, second, or last button of a code. You will choose one complete rules core, then test ways a real player might try to break it. That is where simple electronics begin to feel like a real invention.
At a glance
| Age range | 10–13 |
|---|---|
| Estimated time | 65–90 minutes |
| Difficulty | Intermediate beginner |
| Parent involvement | Medium as a game tester and rule challenger; light for wiring |
| Major concepts | State variable, score, button edge, for loop, function, random(), fair rules, edge-case testing |
| Suggested session plan | 15 min choose/wire, 25 min guided code, 15 min rule change, 10 min break-the-rules testing; optional 20–30 min enclosure or score display |
What you will learn
- How a variable can remember a game stage, score, or secret-code position.
- How a
forloop repeats a known number of flashes or sounds. - How a named function keeps repeated effects readable.
- How to test buttons as deliberate presses rather than “anything happened sometime.”
- Why false starts, ties, wrong codes, and resets are important engineering tests.
- How to make a rule fair and explain it to another player.
Before you begin
Complete Lesson 8: Choose and Plan Your Arduino Invention first. This lesson has two complete build paths:
- Reaction Game core for the Reaction / Two-Player Game capstone. It also teaches the score logic that a Scorekeeper can adapt.
- Secret-Code Safe core for the Secret-Code Safe capstone. It uses the safe servo mechanism from Lesson 9.
Room Sentinel and Pet-Care Reminder makers should still complete one path—Reaction Game is usually the easier choice—because the skill is the same: use a variable to remember what stage the project is in. In Lesson 11, they will rename that state to something useful, such as isArmed or reminderActive, and connect it to their chosen sensors.
Use the Components guide and Debugging Ladder as needed. Build the physical circuit; do not use Tinkercad as a substitute. The important learning is testing real button behavior, ties, early presses, and physical servo movement.
Arduino’s official For Loop Iteration example is the supporting reference for a repeated effect.
What you need
Required components
| Quantity | Item | Compatible substitute |
|---|---|---|
| 1 | Arduino Uno from the Arduino Student Kit | Genuine Uno R3 or Uno R3 SMD |
| 1 | Solderless breadboard | Standard half-size breadboard |
| 2 | Tactile pushbuttons for Reaction branch | Any normally-open momentary breadboard buttons |
| 3 | Tactile pushbuttons for Secret-Code branch | Any normally-open momentary breadboard buttons |
| 1 each | Green and red LEDs | Any ordinary 3–5 mm LEDs |
| 2 | 220 Ω resistors | 330 Ω or 560 Ω resistors; one for each LED |
| 1 | Piezo buzzer from Lesson 4 | Passive piezo compatible with Arduino tone() |
| 10–16 | Male-to-male jumper wires | Solid-core breadboard wires |
| 1 | USB-A to USB-B data cable | Arduino-branded USB-A-to-B data cable |
| 1 | Maker notebook | Paper works if it includes a rule/test table |
Optional components
- The safely tested servo and cardboard toy latch from Lesson 9—Secret-Code Safe branch only.
- Two to three more LEDs and resistors for a visible Scorekeeper display.
- Cardboard labels for PLAYER 1, PLAYER 2, GO, TRY AGAIN, or button-code symbols.
- Potentiometer from Lesson 5 for an optional reaction-game difficulty control.
Tools
None for the electronics. Scissors, tape, and markers are optional for labels or an enclosure.
Computer/software requirements
- Arduino IDE 2 with Arduino Uno and its port selected.
- The standard Arduino AVR board package. The Secret-Code Safe code also uses the built-in
Servolibrary from Lesson 9. - No simulation account is needed.
Safety and setup notes
- Unplug the Uno before moving wires. Keep every build USB-powered and solderless.
- Each LED needs its own 220 Ω resistor. Buttons use
INPUT_PULLUPand connect to ground—do not add 5V to a button row. - The toy safe is still a toy box. It must not lock a person, pet, or important item. It must always be possible to open it by hand.
- For the Secret-Code Safe branch, reuse Lesson 9’s servo safety limits: one small unloaded servo only; unplug for any horn or cardboard adjustment; stop immediately if it buzzes, stalls, feels warm, or resets the Uno.
- Keep the piezo at a comfortable level and decide in advance how a tie and false start will work.
- The parent should be a deliberate rule tester, not the programmer. Step in for suspected 5V/ground errors, warm parts, servo stress, or confusion about which branch is on the board.
Build overview
Both paths turn button presses into a remembered rule:
Button press → Arduino checks the current state → rule chooses result → LEDs/piezo/servo respond → state changesThe important word is state. A state variable remembers a situation that is still true even when nobody is pressing a button right now.
| Branch | States it remembers | Rule it enforces | Main output |
|---|---|---|---|
| Reaction Game | WAITING, GO, RESULT; plus each player’s score | Pressing before GO is a false start; first correct press after GO wins | Player LEDs, sound, repeated score flashes |
| Secret-Code Safe | codeStep: how much of the secret order is correct | A wrong press resets the attempt; the complete order opens the toy latch | Green/red feedback, sound, servo movement |
Build one branch only today. Keep its known-good code saved with a clear name, such as reaction_game_v1 or secret_safe_v1.
Step-by-step build instructions
Step 1: Choose your rules core
| Choose this path if… | Today’s must-have rule | Use this code block |
|---|---|---|
| You chose a reaction or two-player game—or want a Scorekeeper logic model | Before GO, no press can win. After GO, the first press earns a point. | Branch A: Reaction Game |
| You chose a Secret-Code Safe | Only button order 1 → 3 → 2 opens the toy latch. | Branch B: Secret-Code Safe |
| You chose Room Sentinel or Pet-Care Reminder | Learn Branch A, then note that WAITING later becomes ARMED or REMINDER ACTIVE. | Branch A: Reaction Game |
Checkpoint: write: “When ___, the Arduino will ___, unless ___.” The final “unless” is your fairness or safety rule.
Step 2: Wire the shared LEDs and sound output
- Connect Arduino GND to a breadboard ground rail.
- Connect the green LED’s short leg to ground and its long leg through a 220 Ω resistor to D10.
- Connect the red LED the same way through its own 220 Ω resistor to D11.
- Connect piezo positive to D8 and piezo negative to ground.
Checkpoint: trace D10 → resistor → green LED → GND, D11 → resistor → red LED → GND, and D8 → piezo → GND.
Step 3: Wire the buttons for your branch
All buttons use INPUT_PULLUP. Put each button across the center trench. Connect one side to its pin and the opposite side to ground.
| Button | Arduino pin | Reaction job | Secret-Code job |
|---|---|---|---|
| Button 1 | D2 | Player 1 | Code button 1 |
| Button 2 | D3 | Player 2 | Code button 2 |
| Button 3 | D4 | Not used | Code button 3 |
For Secret Code only, keep the Lesson 9 servo connection: signal D9, red 5V, brown or black GND. Do not connect an LED to D9.
Checkpoint: trace one button at a time: pin → button → ground. Unpressed is HIGH; pressed is LOW.
Step 4: Upload one complete branch sketch
- Select Arduino Uno and the correct port.
- Copy only one complete code block from Section 10.
- Give the sketch a clear name.
- Click Verify, repair the first error if needed, then Upload.
- Press each button separately and predict which output or state should change.
Checkpoint: you know whether the Uno contains Branch A or Branch B and can point to its state or score variable.
Step 5: Test the rule like someone trying to break it
Branch A: Reaction Game tests
- Release both buttons and wait for the green GO light and tone.
- After GO, each player tries to press first. Only one player should earn a point.
- Deliberately press before GO. The false start should give no point.
- Try both buttons nearly together. A tie with no point is an acceptable first rule.
- Play until one player reaches the winning score and confirm both scores reset.
Branch B: Secret-Code Safe tests
- Press Button 1, then 3, then 2. Green feedback marks correct steps; the servo opens after the third.
- Press one wrong button. Red feedback appears, the attempt resets, and the latch remains closed.
- Start correctly, then make a wrong second press. Confirm the old attempt is forgotten.
- Test the toy latch by hand after every servo test. It must be free-moving and manually openable.
Checkpoint: record one surprising result and name the state or variable that should control it before changing code.
Step 6: Map this rules core into your capstone plan
| Capstone | State or rule to carry into Lesson 11 |
|---|---|
| Reaction Game | gameState, player scores, false-start rule, first-to-three win |
| Secret-Code Safe | codeStep, secret order, wrong-code reset, servo unlock |
| Scorekeeper | team score variables, point and reset rules, for loop to show points |
| Room Sentinel | isArmed true/false; sensor matters only when armed |
| Pet-Care Reminder | reminderActive true/false; acknowledge button clears it |
Checkpoint: “In my capstone, the variable that remembers ___ will be named ___.”
Code
Choose one complete sketch. Do not combine the two sketches line by line.
Branch A: Two-player reaction game
const int PLAYER_1_BUTTON = 2;
const int PLAYER_2_BUTTON = 3;
const int GREEN_LED = 10;
const int RED_LED = 11;
const int PIEZO_PIN = 8;
const int WAITING = 0;
const int GO = 1;
const int RESULT = 2;
const int POINTS_TO_WIN = 3;
int gameState = WAITING;
int player1Score = 0;
int player2Score = 0;
unsigned long stateStartedAt = 0;
unsigned long waitLength = 0;
void setup() {
pinMode(PLAYER_1_BUTTON, INPUT_PULLUP);
pinMode(PLAYER_2_BUTTON, INPUT_PULLUP);
pinMode(GREEN_LED, OUTPUT);
pinMode(RED_LED, OUTPUT);
pinMode(PIEZO_PIN, OUTPUT);
randomSeed(analogRead(A5));
startWaiting();
}
void loop() {
bool player1Pressed = digitalRead(PLAYER_1_BUTTON) == LOW;
bool player2Pressed = digitalRead(PLAYER_2_BUTTON) == LOW;
if (gameState == WAITING) {
if (player1Pressed || player2Pressed) {
falseStart();
} else if (millis() - stateStartedAt >= waitLength) {
showGo();
}
} else if (gameState == GO) {
if (player1Pressed && player2Pressed) {
showTie();
} else if (player1Pressed) {
awardPoint(1);
} else if (player2Pressed) {
awardPoint(2);
}
} else if (gameState == RESULT) {
if (millis() - stateStartedAt >= 1200 && !player1Pressed && !player2Pressed) {
startWaiting();
}
}
}
void startWaiting() {
digitalWrite(GREEN_LED, LOW);
digitalWrite(RED_LED, LOW);
noTone(PIEZO_PIN);
waitLength = random(2000, 5000);
stateStartedAt = millis();
gameState = WAITING;
}
void showGo() {
digitalWrite(GREEN_LED, HIGH);
tone(PIEZO_PIN, 1200, 80);
gameState = GO;
}
void falseStart() {
flashBoth(3);
gameState = RESULT;
stateStartedAt = millis();
}
void showTie() {
flashBoth(2);
gameState = RESULT;
stateStartedAt = millis();
}
void awardPoint(int winner) {
int winnerLed = GREEN_LED;
digitalWrite(GREEN_LED, LOW);
digitalWrite(RED_LED, LOW);
if (winner == 1) {
player1Score++;
winnerLed = GREEN_LED;
} else {
player2Score++;
winnerLed = RED_LED;
}
tone(PIEZO_PIN, 700 + winner * 250, 120);
showScore(winnerLed, winner == 1 ? player1Score : player2Score);
if (player1Score >= POINTS_TO_WIN || player2Score >= POINTS_TO_WIN) {
flashBoth(5);
player1Score = 0;
player2Score = 0;
}
gameState = RESULT;
stateStartedAt = millis();
}
void showScore(int ledPin, int score) {
for (int flashNumber = 0; flashNumber < score; flashNumber++) {
digitalWrite(ledPin, HIGH);
delay(180);
digitalWrite(ledPin, LOW);
delay(180);
}
}
void flashBoth(int times) {
for (int flashNumber = 0; flashNumber < times; flashNumber++) {
digitalWrite(GREEN_LED, HIGH);
digitalWrite(RED_LED, HIGH);
tone(PIEZO_PIN, 250, 80);
delay(150);
digitalWrite(GREEN_LED, LOW);
digitalWrite(RED_LED, LOW);
delay(150);
}
}
Branch B: Three-button secret-code safe
#include <Servo.h>
const int BUTTON_1 = 2;
const int BUTTON_2 = 3;
const int BUTTON_3 = 4;
const int GREEN_LED = 10;
const int RED_LED = 11;
const int PIEZO_PIN = 8;
const int SERVO_PIN = 9;
// Use the safe angle values proved in Lesson 9.
const int CLOSED_ANGLE = 30;
const int OPEN_ANGLE = 110;
const int SECRET_LENGTH = 3;
const int secretCode[SECRET_LENGTH] = {1, 3, 2};
int codeStep = 0;
int lastButton1 = HIGH;
int lastButton2 = HIGH;
int lastButton3 = HIGH;
Servo safeServo;
void setup() {
pinMode(BUTTON_1, INPUT_PULLUP);
pinMode(BUTTON_2, INPUT_PULLUP);
pinMode(BUTTON_3, INPUT_PULLUP);
pinMode(GREEN_LED, OUTPUT);
pinMode(RED_LED, OUTPUT);
pinMode(PIEZO_PIN, OUTPUT);
safeServo.attach(SERVO_PIN);
safeServo.write(CLOSED_ANGLE);
}
void loop() {
int newButtonPress = readNewButtonPress();
if (newButtonPress > 0) {
checkCode(newButtonPress);
}
delay(25);
}
int readNewButtonPress() {
int button1Now = digitalRead(BUTTON_1);
int button2Now = digitalRead(BUTTON_2);
int button3Now = digitalRead(BUTTON_3);
int newPress = 0;
if (button1Now == LOW && lastButton1 == HIGH) {
newPress = 1;
} else if (button2Now == LOW && lastButton2 == HIGH) {
newPress = 2;
} else if (button3Now == LOW && lastButton3 == HIGH) {
newPress = 3;
}
lastButton1 = button1Now;
lastButton2 = button2Now;
lastButton3 = button3Now;
return newPress;
}
void checkCode(int buttonNumber) {
if (buttonNumber == secretCode[codeStep]) {
codeStep++;
flashLed(GREEN_LED, 1);
if (codeStep == SECRET_LENGTH) {
unlockSafe();
}
} else {
flashLed(RED_LED, 2);
tone(PIEZO_PIN, 180, 180);
codeStep = 0;
}
}
void unlockSafe() {
for (int noteNumber = 0; noteNumber < 3; noteNumber++) {
tone(PIEZO_PIN, 700 + noteNumber * 200, 100);
delay(140);
}
safeServo.write(OPEN_ANGLE);
flashLed(GREEN_LED, 3);
delay(1800);
safeServo.write(CLOSED_ANGLE);
codeStep = 0;
}
void flashLed(int ledPin, int times) {
for (int flashNumber = 0; flashNumber < times; flashNumber++) {
digitalWrite(ledPin, HIGH);
delay(150);
digitalWrite(ledPin, LOW);
delay(150);
}
}
What the important code means
- State variables: Reaction’s
gameStateremembers WAITING, GO, or RESULT. Secret Code’scodeStepremembers how many correct presses happened in order. Scores remember points after a round. bool: player button variables are true/false answers to clear questions.forloop: the counter starts at 0, repeats while smaller than the goal, and grows by 1 each turn.- Functions: readable names such as
startWaiting(),awardPoint(),checkCode(), andunlockSafe()group repeatable jobs. - Inputs and outputs: buttons are inputs; LEDs, piezo, and servo are outputs. State and rules decide their response.
random(): Reaction chooses a 2–5 second wait;randomSeed(analogRead(A5))makes the first wait less predictable.- Secret-code array:
secretCode[] = {1, 3, 2}is an ordered list;secretCode[codeStep]is the next required button. - Button edge: comparing current and previous readings counts one deliberate press instead of repeatedly counting a held button.
See Arduino’s For Loop Iteration guide and programming reference.
Make it work
Reaction Game
- The game has WAITING, green GO, and RESULT periods.
- An early press gives no point.
- The first press after GO earns a point shown by that player’s LED.
- A tie has a stated rule and does not award both players.
- Three points celebrates and resets both scores.
Secret-Code Safe
- The toy latch begins closed and remains manually openable.
- Code
1 → 3 → 2gives green feedback and opens briefly. - A wrong press gives red feedback, stays closed, and resets
codeStep. - Holding one button does not count several steps.
- You can point to the line remembering the next position.
For either path, explain one memory variable, one function, and one rule preventing unfair or incorrect success.
Understand it
- What does your state, score, or code-step variable remember after a button is released?
- Why does Reaction need separate WAITING and GO states?
- After the second correct safe button, where is that remembered?
- What job does a
forloop do? - What is one edge case a real player might try?
Required “change it” challenge
Desired outcome: add one rule making your project fairer, clearer, or more difficult. Write it in English first, then test it with a real person.
Constraints: use a state or score variable or a for loop; change one rule at a time; test a normal and edge case; record before and after. Changing only colors or pitch is not a rule change.
| If you built… | Add one rule | Progressive hints |
|---|---|---|
| Reaction Game | A false start loses a point only if the player has one, or first to a chosen score wins | Add a score check in falseStart() or change POINTS_TO_WIN; ensure scores never become negative. |
| Secret-Code Safe | Two wrong attempts cause a short lockout signal | Add wrongAttempts; increment only on wrong presses; at 2, flash red three times and reset it and codeStep. |
| Scorekeeper | First team to a chosen score celebrates, then resets fairly | Use one score variable per team and a showScore() function. |
| Room Sentinel or Pet-Care | Add isArmed or reminderActive that a button changes | Start with a bool; show it with an LED before adding the sensor in Lesson 11. |
Parent guidance: ask the child to read the rule and predict two cases before editing. Be the player who tries to break the rule, not the fixer. Save the original branch sketch first.
Optional enhancements
Try this
Give WAITING, GO, wrong code, victory, and false start different brief sounds. Write what each means before changing tone().
Challenge
Create a cardboard score display with LEDs or a Lesson 9 servo pointer. For the Safe, make a three-symbol code card hiding number labels.
Stretch
Use the Lesson 5 potentiometer to choose a safe Reaction difficulty. Keep a minimum wait of at least one second and explain how difficulty can become unfair.
Debugging guide
| What you notice | Likely cause | Smallest next diagnostic step |
|---|---|---|
| Game immediately reports a false start | Button rotated or wired wrong, stuck low, or wrong input logic | With buttons untouched, test each input. Every INPUT_PULLUP button should be HIGH. |
| Only one player button works | D2/D3 wiring crossed or button not across trench | Test players separately and trace pin → button → GND. |
| Score flashes do not match winner | LED pins or winner/score choice mixed up | Test LEDs alone, then inspect only awardPoint(). |
| Game never reaches GO | Timer changed or false-start input always low | Temporarily use waitLength = 2000; release buttons and observe. |
| Safe accepts a wrong sequence | Array, labels, or reset changed | Write the list on paper and confirm the wrong branch has codeStep = 0. |
| Holding a safe button adds steps | Edge variables missing or bounce too quick | Confirm prior readings update at the end of readNewButtonPress(). |
| Servo moves but buzzes or Uno resets | Mechanism jam or stressed power | Unplug immediately and return to Lesson 9’s bare-servo test. |
for loop runs or flashes incorrectly | Counter start, condition, or increment wrong | Read start, keep-going question, and change aloud; test with 1. |
Use the Debugging Ladder. For rule bugs: name current state → predict next input → state expected output → run one test → record result.
Recap
You taught the Arduino to remember and enforce a rule. Reaction needs waiting, GO, result, and a false-start rule. A toy safe needs to remember correct steps and reset after mistakes. Variables, conditions, loops, and functions make those rules testable.
Show what you learned
- What does your state, score, or code-step variable remember?
- Describe one unfair or broken test and how you fixed it.
- What rule did you change, and how did you test it?
- What failed, and how did you diagnose it?
- What would you improve?
- Explain one
forloop or function.
What’s next
Next is Lesson 11: Capstone Build and Debug Lab. Combine tested inputs, outputs, mechanics, and rule code. Bring your Lesson 8 plan, Lesson 9 servo sketch if used, and today’s known-good rules sketch.
NEXT · LESSON 11Lesson 11: Capstone Build and Debug Lab
Parent guide
What to prepare
- Set out the Uno, breadboard, two or three buttons, green/red LEDs, resistors, piezo, wires, USB cable, notebook, and the tested Lesson 9 servo only for Secret Code.
- Confirm uploads work; open the Debugging Ladder, Components guide, and Lesson 8 plan.
- Choose one branch before the session. Do not merge sketches.
- Be ready to false-start, tie, enter a wrong code, or hold a button.
Child independence
Let the child wire, name the state, upload, run normal and edge tests, record state or score, choose the rule change, and document before and after.
Resist taking over
Do not write a more sophisticated state machine or decide ties and false starts first. Let the child observe, describe, and change one rule.
Step in
Step in for electrical risk, heat, branch confusion, unsafe servo behavior, or inability to name the current state. After 15–20 minutes without new evidence, restore the known-good branch and collect wiring, code, port, error, and expected/actual details.
Assessment
Have the student act out the project without electricity, explaining the state transitions and one edge case. Assess safe wiring, readable rule, named memory variable, player-test evidence, and one intentional revision.
Further resource: Arduino: For Loop Iteration