ROBOTICS · LEVEL 1 · ARDUINO FOUNDATIONS · LESSON 10

Build Arduino Rules, Rounds, and Scores

Make the Arduino remember a rule: fair reaction rounds, secret codes, scores, and a reset button.

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 range10–13
Estimated time65–90 minutes
DifficultyIntermediate beginner
Parent involvementMedium as a game tester and rule challenger; light for wiring
Major conceptsState variable, score, button edge, for loop, function, random(), fair rules, edge-case testing
Suggested session plan15 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 for loop 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

QuantityItemCompatible substitute
1Arduino Uno from the Arduino Student KitGenuine Uno R3 or Uno R3 SMD
1Solderless breadboardStandard half-size breadboard
2Tactile pushbuttons for Reaction branchAny normally-open momentary breadboard buttons
3Tactile pushbuttons for Secret-Code branchAny normally-open momentary breadboard buttons
1 eachGreen and red LEDsAny ordinary 3–5 mm LEDs
2220 Ω resistors330 Ω or 560 Ω resistors; one for each LED
1Piezo buzzer from Lesson 4Passive piezo compatible with Arduino tone()
10–16Male-to-male jumper wiresSolid-core breadboard wires
1USB-A to USB-B data cableArduino-branded USB-A-to-B data cable
1Maker notebookPaper 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 Servo library 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_PULLUP and 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 changes

The important word is state. A state variable remembers a situation that is still true even when nobody is pressing a button right now.

BranchStates it remembersRule it enforcesMain output
Reaction GameWAITING, GO, RESULT; plus each player’s scorePressing before GO is a false start; first correct press after GO winsPlayer LEDs, sound, repeated score flashes
Secret-Code SafecodeStep: how much of the secret order is correctA wrong press resets the attempt; the complete order opens the toy latchGreen/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 ruleUse this code block
You chose a reaction or two-player game—or want a Scorekeeper logic modelBefore GO, no press can win. After GO, the first press earns a point.Branch A: Reaction Game
You chose a Secret-Code SafeOnly button order 1 → 3 → 2 opens the toy latch.Branch B: Secret-Code Safe
You chose Room Sentinel or Pet-Care ReminderLearn 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

  1. Connect Arduino GND to a breadboard ground rail.
  2. Connect the green LED’s short leg to ground and its long leg through a 220 Ω resistor to D10.
  3. Connect the red LED the same way through its own 220 Ω resistor to D11.
  4. 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.

ButtonArduino pinReaction jobSecret-Code job
Button 1D2Player 1Code button 1
Button 2D3Player 2Code button 2
Button 3D4Not usedCode 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

  1. Select Arduino Uno and the correct port.
  2. Copy only one complete code block from Section 10.
  3. Give the sketch a clear name.
  4. Click Verify, repair the first error if needed, then Upload.
  5. 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

  1. Release both buttons and wait for the green GO light and tone.
  2. After GO, each player tries to press first. Only one player should earn a point.
  3. Deliberately press before GO. The false start should give no point.
  4. Try both buttons nearly together. A tie with no point is an acceptable first rule.
  5. Play until one player reaches the winning score and confirm both scores reset.

Branch B: Secret-Code Safe tests

  1. Press Button 1, then 3, then 2. Green feedback marks correct steps; the servo opens after the third.
  2. Press one wrong button. Red feedback appears, the attempt resets, and the latch remains closed.
  3. Start correctly, then make a wrong second press. Confirm the old attempt is forgotten.
  4. 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

CapstoneState or rule to carry into Lesson 11
Reaction GamegameState, player scores, false-start rule, first-to-three win
Secret-Code SafecodeStep, secret order, wrong-code reset, servo unlock
Scorekeeperteam score variables, point and reset rules, for loop to show points
Room SentinelisArmed true/false; sensor matters only when armed
Pet-Care ReminderreminderActive 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 gameState remembers WAITING, GO, or RESULT. Secret Code’s codeStep remembers how many correct presses happened in order. Scores remember points after a round.
  • bool: player button variables are true/false answers to clear questions.
  • for loop: 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(), and unlockSafe() 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

  1. The game has WAITING, green GO, and RESULT periods.
  2. An early press gives no point.
  3. The first press after GO earns a point shown by that player’s LED.
  4. A tie has a stated rule and does not award both players.
  5. Three points celebrates and resets both scores.

Secret-Code Safe

  1. The toy latch begins closed and remains manually openable.
  2. Code 1 → 3 → 2 gives green feedback and opens briefly.
  3. A wrong press gives red feedback, stays closed, and resets codeStep.
  4. Holding one button does not count several steps.
  5. 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

  1. What does your state, score, or code-step variable remember after a button is released?
  2. Why does Reaction need separate WAITING and GO states?
  3. After the second correct safe button, where is that remembered?
  4. What job does a for loop do?
  5. 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 ruleProgressive hints
Reaction GameA false start loses a point only if the player has one, or first to a chosen score winsAdd a score check in falseStart() or change POINTS_TO_WIN; ensure scores never become negative.
Secret-Code SafeTwo wrong attempts cause a short lockout signalAdd wrongAttempts; increment only on wrong presses; at 2, flash red three times and reset it and codeStep.
ScorekeeperFirst team to a chosen score celebrates, then resets fairlyUse one score variable per team and a showScore() function.
Room Sentinel or Pet-CareAdd isArmed or reminderActive that a button changesStart 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 noticeLikely causeSmallest next diagnostic step
Game immediately reports a false startButton rotated or wired wrong, stuck low, or wrong input logicWith buttons untouched, test each input. Every INPUT_PULLUP button should be HIGH.
Only one player button worksD2/D3 wiring crossed or button not across trenchTest players separately and trace pin → button → GND.
Score flashes do not match winnerLED pins or winner/score choice mixed upTest LEDs alone, then inspect only awardPoint().
Game never reaches GOTimer changed or false-start input always lowTemporarily use waitLength = 2000; release buttons and observe.
Safe accepts a wrong sequenceArray, labels, or reset changedWrite the list on paper and confirm the wrong branch has codeStep = 0.
Holding a safe button adds stepsEdge variables missing or bounce too quickConfirm prior readings update at the end of readNewButtonPress().
Servo moves but buzzes or Uno resetsMechanism jam or stressed powerUnplug immediately and return to Lesson 9’s bare-servo test.
for loop runs or flashes incorrectlyCounter start, condition, or increment wrongRead 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 for loop 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 11

Lesson 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