# Simon Says Game

A Python-based Simon Says memory game that uses an SMD Red gateway with the RGB LED Module and Buzzer Module for visual and audio feedback. The game presents an ever-growing sequence of colors that the player must repeat correctly to advance to the next round.

About Tools and Materials:

[SMD Red](https://docs.acrome.net/electronics/smd-red) ([Purchase Here](https://www.robotshop.com/products/acrome-smd-red-smart-brushed-motor-driver-with-speed-position-and-current-control-modes))

[SMD USB Gateway](https://docs.acrome.net/electronics/gateway-modules/usb-gateway-module) ([Purchase Here](https://www.robotshop.com/products/acrome-usb-gateway-module-acrome-smd-products))

[Arduino Gateway Module](/electronics/gateway-modules/arduino-gateway-module.md) ([Purchase Here](https://www.robotshop.com/products/acrome-arduino-gateway-shield-module-acrome-smd-products))

[RGB LED Module](/electronics/add-on-modules/rgb-led-module.md) ([Purchase Here](https://www.robotshop.com/products/acrome-rgb-led-add-on-module-acrome-smd-products))

[Buzzer Module](/electronics/add-on-modules/buzzer-module.md) ([Purchase Here](https://www.robotshop.com/products/acrome-buzzer-sound-add-on-module-acrome-smd-products))

## Step 1: Hardware and Software Overview

1. [SMD Red](/electronics/smd-red.md)\
   The SMD acts as a bridge between the script and the modules. It is responsible for interpreting the commands the script sends and translating them into actions that actuate the [RGB LED Module](https://docs.acrome.net/electronics/add-on-modules/rgb-led-module) and the[ Buzzer Module](https://docs.acrome.net/electronics/add-on-modules/buzzer-module).
2. [RGB LED Module](/electronics/add-on-modules/rgb-led-module.md)\
   Depending on the game sequence, this module lights up in Red, Green, or Blue. It helps the player visually memorize the pattern.
3. [Buzzer Module](/electronics/add-on-modules/buzzer-module.md)\
   Emits a short beep along with the LED flash for audio feedback. This pairing enhances the user’s memory and reaction.
4. SMD Libraries\
   The official Acrome SMD Python library handles low-level serial communication, device scanning, and module control, letting you focus on the Simon Says logic and GUI.

### Project Key Features

* Visual + Audible Feedback

Each color is accompanied by a synchronized flash and beep.

* Growing Memory Challenge

The sequence grows with each successful round, increasing difficulty.

* Tkinter Graphical Interface

Simple UI with buttons for Red, Green, and Blue, a start button, and a status message.

* Built-in Hardware Warm-Up

The RGB LED is initialized once before gameplay to bypass any first-flash issues.

## Step 2: Assemble

Getting Started

1. Hardware Setup

* Connect the SMD to the PC or Arduino board using[ the USB Gateway Module](https://acrome.gitbook.io/acrome-smd-docs/electronics/gateway-modules/usb-gateway-module) or[ the Arduino Gateway Module](https://acrome.gitbook.io/acrome-smd-docs/electronics/gateway-modules/arduino-gateway-module).
* Connect the[ ](https://docs.acrome.net/electronics/add-on-modules/button-module)[RGB LED Module](https://docs.acrome.net/electronics/add-on-modules/rgb-led-module) and the[ Buzzer Module](https://docs.acrome.net/electronics/add-on-modules/buzzer-module) to the SMD using an RJ-45 cable.
* Make sure that the SMD is powered and all connections are correct.

### Project Wiring Diagram

<figure><img src="https://lh7-qw.googleusercontent.com/docsz/AD_4nXc8NSK0FpsjsKTaIdRvCrRQHK9lphi-2JvJr4ssVgtGLe153kYozejBq_PhGojGCLlgJEujiWFi06StvgXwUQuf3ubGN69Qb6N8c8N2RxDusZDP042-rq9aMSpE37bobuqoRwJp5g?key=iN1LfuB2rKLGjoje9im4lw" alt=""><figcaption></figcaption></figure>

## Step 3: Run & Test

1. Install Libraries and Run the Script

* Install necessary libraries such as Tkinter, serial, and acrome-smd.
* Execute the script, initiating the Simon Says project and opening the Tkinter UI where you can enter your text.

2. Play the Simon Says Game

* Click Start to begin.
* Watch the color sequence.
* Repeat the sequence using the buttons.
* If correct, the game adds one more color and continues.
* If wrong, the game ends and can be restarted.

## Codes:

{% tabs %}
{% tab title="Python Code" %}
{% code lineNumbers="true" %}

```python
import os, sys
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))


import time
import random
import tkinter as tk
from tkinter import ttk, messagebox
from serial.tools.list_ports import comports
from platform import system
from smd.red import Master, Red


# ─── Hardware Layer ───────────────────────────────────────────────────────────
def find_usb_port():
   ports = list(comports())
   os_name = system()
   usb_names = {
       "Windows": ["USB Serial Port"],
       "Linux": ["/dev/ttyUSB"],
       "Darwin": ["/dev/tty.usbserial", "/dev/tty.usbmodem", "/dev/cu.usbserial"]
   }
   for port, desc, hwid in sorted(ports):
       if any(name in port or name in desc for name in usb_names.get(os_name, [])):
           return port
   return None


class Device:
   def __init__(self, port, baud=115200, smd_id=0, led_id=5, buzzer_id=5):
       self.master = Master(port, baud)
       self.master.attach(Red(smd_id))
       self.master.scan_modules(smd_id)
       self.smd_id = smd_id
       self.led_id = led_id
       self.buzzer_id = buzzer_id


   def led_color(self, r, g, b):
       self.master.set_rgb(self.smd_id, self.led_id, r, g, b)


   def led_off(self):
       self.led_color(0, 0, 0)


   def beep(self, duration=0.2):
       ms = int(duration * 1000)
       self.master.set_buzzer(self.smd_id, self.buzzer_id, ms)
       time.sleep(duration)
       self.master.set_buzzer(self.smd_id, self.buzzer_id, 0)


   def close(self):
       ser = getattr(self.master, 'serial', None)
       if ser and hasattr(ser, 'close'):
           ser.close()


# ─── Simon Says GUI ────────────────────────────────────────────────────────────
COLORS = [
   ("Red",   (255, 0,   0)),
   ("Green", (0,   255, 0)),
   ("Blue",  (0,   0,   255))
]


class SimonSaysApp(tk.Tk):
   def __init__(self, device):
       super().__init__()
       self.title("Simon Says Game")
       self.resizable(False, False)
       self.device = device


       self.sequence = []
       self.user_index = 0
      
       self.device.led_color(*COLORS[0][1])
       self.device.beep(0.8)
       self.device.led_off()
       time.sleep(1.0)
      
       self._build_ui()
      


   def _build_ui(self):
       btn_frame = ttk.Frame(self)
       btn_frame.pack(pady=10)


       self.buttons = []
       for i, (name, color) in enumerate(COLORS):
           hexc = "#%02x%02x%02x" % color
           btn = tk.Button(btn_frame, text=name, bg=hexc, width=8,
                           command=lambda i=i: self._user_press(i))
           btn.grid(row=0, column=i, padx=5)
           self.buttons.append((btn, color))


       control = ttk.Frame(self)
       control.pack(pady=5)


       self.status = ttk.Label(self, text="Press Start to play")
       self.status.pack(pady=(0,5))


       self.start_btn = ttk.Button(control, text="Start", command=self._start_game)
       self.start_btn.pack()


   def _start_game(self):
       self.sequence.clear()
       self._next_round()


   def _next_round(self):
       self.start_btn.config(state="disabled")
       self.user_index = 0
       self.sequence.append(random.randrange(len(COLORS)))
       self.status.config(text=f"Round {len(self.sequence)} – watch...")
       # schedule playback on main thread
       self.after(500, self._play_sequence, 0)


   def _play_sequence(self, idx):
       if idx < len(self.sequence):
           color_idx = self.sequence[idx]
           self._flash(color_idx)
           # schedule next flash
           self.after(700, self._play_sequence, idx+1)
       else:
           self.status.config(text="Your turn")


   def _flash(self, idx):
       _, color = self.buttons[idx]
       self.device.led_color(*color)
       self.device.beep(0.2)
       # turn off after short delay
       self.after(200, self.device.led_off)


   def _user_press(self, idx):
       if not self.sequence:
           return
       self._flash(idx)
       if idx == self.sequence[self.user_index]:
           self.user_index += 1
           if self.user_index == len(self.sequence):
               # correct full sequence
               self.status.config(text="Correct! Next round...")
               self.after(500, self._next_round)
       else:
           self.status.config(text="Wrong! Game Over")
           self.start_btn.config(state="enabled")
           self.sequence.clear()


# ─── Main ─────────────────────────────────────────────────────────────────────
if __name__ == '__main__':
   port = find_usb_port()
   if not port:
       print("No USB gateway detected.")
       sys.exit(1)


   device = Device(port)
   app = SimonSaysApp(device)
   app.protocol("WM_DELETE_WINDOW", lambda: (device.close(), app.destroy()))
   app.mainloop()
```

{% endcode %}
{% endtab %}

{% tab title="Arduino Code" %}
{% code lineNumbers="true" %}

```cpp
#include <AcromeSMD.h>  // You need Acrome's Arduino SMD library


#define SMD_ID 0
#define LED_ID 5
#define BUZZER_ID 5


// Setup SMD and modules
SMDRed smd;
uint8_t sequence[100];
uint8_t userIndex = 0;
uint8_t currentLength = 0;
bool userTurn = false;




const uint8_t COLORS[3][3] = {
  {255, 0, 0},  // Red
  {0, 255, 0},  // Green
  {0, 0, 255}   // Blue
};


// Button pins (connect external buttons to these digital pins)
const int buttonPins[3] = {2, 3, 4};


void setup() {
  Serial.begin(115200);
  smd.begin();


  smd.attachModule(SMD_ID, LED_ID, RGB);
  smd.attachModule(SMD_ID, BUZZER_ID, BUZZER);


  for (int i = 0; i < 3; i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);
  }


  // Hardware init blink + beep
  flashColor(0, 300);
  delay(1000);
  
  startNewGame();
}


void loop() {
  if (userTurn) {
    for (int i = 0; i < 3; i++) {
      if (digitalRead(buttonPins[i]) == LOW) {
        delay(200); // debounce
        
        flashColor(i, 200);
        if (i == sequence[userIndex]) {
          userIndex++;
          if (userIndex == currentLength) {
            Serial.println("Correct! Next round...");
            delay(500);
            nextRound();
          }
        } else {
          Serial.println("Wrong! Game Over.");
          delay(1000);
          startNewGame();
        }
      }
    }
  }
}


void startNewGame() {
  currentLength = 0;
  userIndex = 0;
  nextRound();
}


void nextRound() {
  if (currentLength < sizeof(sequence)) {
    sequence[currentLength] = random(0, 3);
    currentLength++;
    playSequence();
    userIndex = 0;
    userTurn = true;
  }
}


void playSequence() {
  userTurn = false;
  Serial.print("Round ");
  Serial.println(currentLength);
  delay(500);
  for (int i = 0; i < currentLength; i++) {
    flashColor(sequence[i], 200);
    delay(500);
  }
}


void flashColor(uint8_t colorIndex, uint16_t duration) {
  smd.setRGB(SMD_ID, LED_ID, COLORS[colorIndex][0], COLORS[colorIndex][1], COLORS[colorIndex][2]);
  smd.setBuzzer(SMD_ID, BUZZER_ID, duration);
  delay(duration);
  smd.setRGB(SMD_ID, LED_ID, 0, 0, 0);
}
```

{% endcode %}
{% endtab %}
{% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.acrome.net/smd-applications/interactive/simon-says-game.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
