Arduinoでメモリーゲーム (Simonクローン) を作ろう – ステップバイステップチュートリアル
必要な部品と材料
| 部品名 | 数量 | 備考 |
|---|---|---|
| Arduino UNO | 1 | メインボード |
| 330Ω 抵抗 | 4 | LED電流制限用 |
| 10kΩ 抵抗 | 4 | ボタンプルダウン用 |
| LED (赤・青・緑・黄 など異色4個) | 4 | ゲーム表示用 |
| ミニスピーカー (圧電ブザー等) | 1 | 効果音用 (省略可) |
| ブレッドボード (フルサイズ) | 1 | |
| ジャンパーワイヤー | 1式 | |
| タクトスイッチ (4個) | 4 | ボタン入力用 (LEDと同色推奨) |
使用ツール
- Arduino IDE
プロジェクト概要
1970〜80年代に大流行した電子ゲーム「Simon (サイモン)」を覚えていますか? 4色のボタンが順番に光り、そのシーケンスを記憶して繰り返すゲームです。筆者も子供の頃夢中になりましたが、引っ越しの際に紛失してしまいました。
大人になってArduinoを知り、失われた友を蘇らせるチャンス到来! このチュートリアルでは、Arduino Unoと少数の部品で同等のゲームを製作します。回路はシンプルですが、プログラムは初心者には少し複雑かもしれません。コード内に詳細なコメントを入れていますので、読み解きながら理解を深めてください。
最短で動かす手順
- 回路図通りに配線する (ワイヤーの色は任意)
- ソースコードをArduino IDEに貼り付け、ボードに書き込む
- 遊ぶ!
動作の流れ
- 起動後約3秒で、全LEDがゆっくり5回点滅 (ゲーム開始合図)
- ランダムに1つのLEDが点灯 → 対応するボタンを押す
- 正解なら、同じLEDが再点灯後、新しいLEDが追加されて2手目に
- これを繰り返し、シーケンスが長くなっていく
- 間違える、または2秒以内に押せないとゲームオーバー (全LED高速点滅)
- 最後の正解シーケンスが再生され (スコア確認用)、再び5回点滅でリスタート


トラブルシューティング
- LEDが点かない: 配線確認。動くLEDと入れ替えてLED不良か判別
- ボタン反応しない: タクトスイッチがブレッドボードから浮いてないか確認 (よくある)
難易度調整・拡張
- 制限時間変更:
#define PLAYER_WAIT_TIME 2000(ミリ秒) を短くする - LED/ボタン追加: 回路を1セット追加し、コードの
byte noPins = 4とbyte pins[] = {2, 13, 10, 8}を書き換え (例: 5個ならnoPins=5, pins[]={2,13,10,8,6})
コーディングの小ネタ
void setup() {
delay(3000); // 起動直後の3秒待機
Serial.begin(9600);
Reset();
}
setup() 先頭に delay(3000) を入れておくと、暴走ループで書き込み不能になった際、リセット→即書き込みで復旧しやすくなります。
ソースコード (完全版)
#define PLAYER_WAIT_TIME 2000 // ボタン入力猶予 2秒
byte sequence[100]; // シーケンス格納 (最大100手)
byte curLen = 0; // 現在のシーケンス長
byte inputCount = 0; // 今回のターンで正解した入力数
byte lastInput = 0; // 最後に押されたボタン
byte expRd = 0; // 期待される正解ボタン (LEDピン番号)
bool btnDwn = false; // ボタン押下中フラグ
bool wait = false; // プレイヤー入力待ちフラグ
bool resetFlag = false; // ゲームオーバーフラグ
byte soundPin = 5; // スピーカー出力ピン
byte noPins = 4; // LED/ボタン数
byte pins[] = {2, 13, 10, 8}; // 各LED/ボタンのピン番号 (LED出力兼ボタン入力)
long inputTime = 0; // 入力開始時刻 (タイムアウト判定用)
void setup() {
delay(3000);
Serial.begin(9600);
Reset();
}
// 全ピンの方向一括設定
void setPinDirection(byte dir) {
for (byte i = 0; i < noPins; i++) pinMode(pins[i], dir);
}
// 全LED一括点灯/消灯
void writeAllPins(byte val) {
for (byte i = 0; i < noPins; i++) digitalWrite(pins[i], val);
}
// ビープ音 (PWMで簡易トーン)
void beep(byte freq) {
analogWrite(soundPin, 2);
delay(freq);
analogWrite(soundPin, 0);
delay(freq);
}
// 全LED点滅 (freq小→高速, 大→低速)
void flash(short freq) {
setPinDirection(OUTPUT);
for (int i = 0; i < 5; i++) {
writeAllPins(HIGH); beep(50); delay(freq);
writeAllPins(LOW); delay(freq);
}
}
// ゲーム状態リセット
void Reset() {
flash(500); // 低速5回点滅
curLen = 0; inputCount = 0; lastInput = 0; expRd = 0;
btnDwn = false; wait = false; resetFlag = false;
}
// ゲームオーバー演出 (高速点滅)
void Lose() { flash(50); }
// シーケンス再生 (覚えるフェーズ / ゲームオーバー時の答え合わせ)
void playSequence() {
for (int i = 0; i < curLen; i++) {
Serial.print("Seq: "); Serial.print(i); Serial.print(" Pin: "); Serial.println(sequence[i]);
digitalWrite(sequence[i], HIGH); delay(500);
digitalWrite(sequence[i], LOW); delay(250);
}
}
// 敗北処理
void DoLoseProcess() {
Lose(); delay(1000);
playSequence(); // 最後のシーケンス再生 (スコア確認)
delay(1000);
Reset(); // 新ゲーム開始
}
void loop() {
if (!wait) {
// ===== Arduinoのターン: シーケンス生成・提示 =====
setPinDirection(OUTPUT);
randomSeed(analogRead(A0)); // 乱数シード (ノイズ利用)
sequence[curLen] = pins[random(0, noPins)]; // ランダムに1手追加
curLen++;
playSequence(); // 全シーケンス再生
beep(50); // 合図音
wait = true; // プレイヤーのターンへ
inputTime = millis(); // タイムアウト計測開始
} else {
// ===== プレイヤーのターン: 入力受付 =====
setPinDirection(INPUT);
// タイムアウト判定
if (millis() - inputTime > PLAYER_WAIT_TIME) { DoLoseProcess(); return; }
if (!btnDwn) {
expRd = sequence[inputCount]; // 期待される正解
Serial.print("Expected: "); Serial.println(expRd);
// 誤入力チェック (正解以外のボタンが押されたか)
for (int i = 0; i < noPins; i++) {
if (pins[i] == expRd) continue;
if (digitalRead(pins[i]) == HIGH) {
lastInput = pins[i];
resetFlag = true; // 不正解
btnDwn = true;
Serial.print("Read (wrong): "); Serial.println(lastInput);
}
}
}
// 正解ボタンが押されたか
if (digitalRead(expRd) == HIGH && !btnDwn) {
inputTime = millis(); // タイムアウトリセット
inputCount++; // 正解カウント
btnDwn = true;
Serial.print("Read (correct): "); Serial.println(expRd);
} else {
// ボタン離した瞬間の処理
if (btnDwn && digitalRead(lastInput) == LOW) {
btnDwn = false;
delay(20); // チャタリング対策
if (resetFlag) { DoLoseProcess(); } // 不正解だった
else {
if (inputCount == curLen) { // 全手正解
wait = false; // 次はArduinoのターン
inputCount = 0;
delay(1500); // 少し間を置く
}
}
}
}
}
}
回路図 (Fritzing)

各LEDのアノードをピン (2, 13, 10, 8) に、カソードを330Ω抵抗経由でGNDへ。各ボタンの一端を同じピンに、もう一端を10kΩ抵抗経由でGND (プルダウン)、さらにもう一端を5Vへ。スピーカーはピン5とGND間に接続。
発展アイデア
携帯型にする、LEGOと連携させる (参考: Lego Mini Memory Game)、スコアをEEPROMに保存してハイスコア機能を付ける、などさらに発展させるアイデアは無限大です。楽しんでください!
製造プロセス
- Arduinoで作るモニター用Ambilightシステム:没入感アップの自作ガイド
- Arduino NanoとMPU-6050で作るリアルタイムジャイロスコープゲーム
- NeoPixelリングとArduinoで作るインタラクティブジャイロスコープLEDディスプレイ
- Arduino UNOとOLEDディスプレイでクラシックPongゲームを自作:ステップバイステップチュートリアル
- DIY Arduino USBゲームコントローラー - 高性能ゲームパッドを自作
- Arduinoタッチブレークアウトゲーム:2.4インチTFT LCDでクラシックアーケードを再現
- Pixie: Arduino Pro Miniで作るNeoPixel腕時計 - アナログとデジタル融合のDIY光る時計
- Pixel Chaser: Arduino Nanoで作るワンタップLEDゲーム
- Arduinoで自動化するChrome恐竜ゲーム – LDRとPythonで障害物を検知してジャンプ
- 携帯型リモート監視カメラロボット - Raspberry PiとArduinoで構築
- スマート手話グローブ:ジェスチャーをテキスト/音声に変換