# 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](https://docs.acrome.net/electronics/gateway-modules/arduino-gateway-module) ([Purchase Here](https://www.robotshop.com/products/acrome-arduino-gateway-shield-module-acrome-smd-products))

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

[Buzzer Module](https://docs.acrome.net/electronics/add-on-modules/buzzer-module) ([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](https://docs.acrome.net/electronics/smd-red)\
   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](https://docs.acrome.net/electronics/add-on-modules/rgb-led-module)\
   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](https://docs.acrome.net/electronics/add-on-modules/buzzer-module)\
   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 %}
