Built-in project · Arduino Uno R3
Reaction duel on an Arduino Uno
Two buttons, three lamps and a piezo: the Uno lights the middle lamp and the first press wins. The whole build, an Arduino Uno and 9 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.
IntermediateRuns in your browser. Free, and no account needed.
Hold the button
The circuit itself, running here on the simulator. Press what can be pressed; click anything else to open it in the editor.
The code
The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.
sketch.ino · Arduino Uno R3
// Reaction duel: two players, one lamp, and whoever presses first wins.
//
// pin 9 the go lamp, through 220 ohm to GND
// pin 10 player one's lamp pin 2 player one's button, to GND
// pin 11 player two's lamp pin 3 player two's button, to GND
// pin 7 a passive piezo straight to GND
//
// Both buttons use the pad's internal pull-up, so a button is one wire to the
// pin and one to ground and nothing else. A round waits a random one and a
// half to four seconds, lights the go lamp, and then watches both pins until
// one of them falls.
//
// Pressing before the lamp is a false start and hands the round to the other
// player, which is the rule that makes the game worth playing: you cannot win
// by holding the button down.
//
// The margin is the gap between the two presses. Anything under twenty
// milliseconds is a tie as far as a person is concerned, and the sketch says
// so rather than printing a number nobody could have felt.
#include "mokxi_tone.h"
const int GO_LAMP = 9;
const int LAMP_A = 10;
const int LAMP_B = 11;
const int BUTTON_A = 2;
const int BUTTON_B = 3;
const int PIEZO = 7;
/** How long the round waits for the second player before calling it. */
const long LATE_MS = 400;
static bool downA() { return digitalRead(BUTTON_A) == LOW; }
static bool downB() { return digitalRead(BUTTON_B) == LOW; }
static void win(int lamp, const char *who, long ms, long margin) {
digitalWrite(GO_LAMP, LOW);
digitalWrite(lamp, HIGH);
Serial.print(who);
Serial.print(" wins in ");
Serial.print(ms);
Serial.print(" ms, by ");
if (margin < 20) {
Serial.println("a whisker");
} else {
Serial.print(margin);
Serial.println(" ms");
}
mokxiTone(PIEZO, NOTE_C5, 90);
mokxiTone(PIEZO, NOTE_G5, 140);
delay(900);
digitalWrite(lamp, LOW);
}
static void falseStart(const char *who, int otherLamp) {
Serial.print(who);
Serial.println(" jumped the lamp: the round goes the other way");
mokxiTone(PIEZO, 160, 250);
digitalWrite(otherLamp, HIGH);
delay(700);
digitalWrite(otherLamp, LOW);
}
void setup() {
pinMode(GO_LAMP, OUTPUT);
pinMode(LAMP_A, OUTPUT);
pinMode(LAMP_B, OUTPUT);
pinMode(PIEZO, OUTPUT);
pinMode(BUTTON_A, INPUT_PULLUP);
pinMode(BUTTON_B, INPUT_PULLUP);
Serial.begin(115200);
Serial.println("Mokxi Arduino Uno: reaction duel");
Serial.println("wait for the middle lamp, then press first");
}
void loop() {
digitalWrite(GO_LAMP, LOW);
digitalWrite(LAMP_A, LOW);
digitalWrite(LAMP_B, LOW);
// a round starts with both buttons up
while (downA() || downB()) {
delay(10);
}
delay(400);
unsigned long wait = 1500UL + (unsigned long)random(2500);
unsigned long start = millis();
while (millis() - start < wait) {
if (downA()) {
falseStart("player one", LAMP_B);
return;
}
if (downB()) {
falseStart("player two", LAMP_A);
return;
}
delay(2);
}
digitalWrite(GO_LAMP, HIGH);
unsigned long lit = millis();
int winner = 0;
long winnerMs = 0;
long loserMs = -1;
while (millis() - lit < 5000UL) {
long now = (long)(millis() - lit);
if (winner == 0) {
if (downA()) {
winner = 1;
winnerMs = now;
} else if (downB()) {
winner = 2;
winnerMs = now;
}
} else if (winner == 1 && downB()) {
loserMs = now;
break;
} else if (winner == 2 && downA()) {
loserMs = now;
break;
} else if (now - winnerMs > LATE_MS) {
break;
}
delay(1);
}
if (winner == 0) {
Serial.println("nobody pressed: round abandoned");
mokxiTone(PIEZO, 220, 200);
return;
}
long margin = loserMs < 0 ? LATE_MS : loserMs - winnerMs;
if (winner == 1) {
win(LAMP_A, "player one", winnerMs, margin);
} else {
win(LAMP_B, "player two", winnerMs, margin);
}
}
Parts list
11 parts, plus the jumper wires. Every one is in the editor's parts bin.
- 1 × Arduino Uno R3
- 1 × Full-size breadboard
- 3 × Resistor, 220 Ω
- 1 × LED, red
- 1 × LED, white
- 1 × LED, blue
- 2 × Pushbutton
- 1 × Piezo speaker
How it is wired
10 connections, pin by pin, read from the circuit itself. Each line is one set of pins joined together, by a jumper wire or a breadboard strip.
- Ground: Arduino Uno R3 pin GND; LED, red pin C; LED, white pin C; LED, blue pin C; Pushbutton (1) pin 2a; Pushbutton (2) pin 2a; Piezo speaker pin 2
- Arduino Uno R3 pin 11; Resistor, 220 Ω (3) pin 1
- Arduino Uno R3 pin 10; Resistor, 220 Ω (1) pin 1
- Arduino Uno R3 pin 9; Resistor, 220 Ω (2) pin 1
- Arduino Uno R3 pin 7; Piezo speaker pin 1
- Arduino Uno R3 pin 3; Pushbutton (2) pin 1a
- Arduino Uno R3 pin 2; Pushbutton (1) pin 1a
- Resistor, 220 Ω (1) pin 2; LED, red pin A
- Resistor, 220 Ω (2) pin 2; LED, white pin A
- Resistor, 220 Ω (3) pin 2; LED, blue pin A
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.