From a145075eb812fff718bbc4bd9308846930f61db4 Mon Sep 17 00:00:00 2001 From: David Montero Crespo Date: Mon, 9 Mar 2026 02:13:47 -0300 Subject: [PATCH] Add Simon Game with Score Display and Pong Game - Created pitches.h to define musical note frequencies. - Implemented Simon Game in simon-with-score.ino, featuring LED indicators, button inputs, and score display using a 74HC595 shift register. - Added game logic for sequence playback, user input validation, and game over conditions. - Included README.md for Simon Game instructions and hardware setup. - Added Wokwi project files for simulation of Simon Game. - Introduced Pong game with basic mechanics, including paddle movement and scoring, in pong.ino. - Included Wokwi project files for simulation of Pong game. --- .gitignore | 1 - example_zip/ServoOverdone.zip | Bin 0 -> 17555 bytes .../extracted/ServoOverdone/ServoOverdone.ino | 260 ++++++++++++ .../extracted/ServoOverdone/diagram.json | 370 ++++++++++++++++++ .../extracted/ServoOverdone/libraries.txt | 1 + .../extracted/ServoOverdone/wokwi-project.txt | 3 + example_zip/extracted/pong/diagram.json | 50 +++ example_zip/extracted/pong/libraries.txt | 7 + example_zip/extracted/pong/pong.ino | 276 +++++++++++++ example_zip/extracted/pong/wokwi-project.txt | 3 + .../extracted/simon-with-score/README.md | 56 +++ .../extracted/simon-with-score/diagram.json | 133 +++++++ .../extracted/simon-with-score/pitches.h | 94 +++++ .../simon-with-score/simon-with-score.ino | 202 ++++++++++ .../simon-with-score/wokwi-project.txt | 3 + example_zip/pong.zip | Bin 0 -> 8254 bytes example_zip/simon-with-score.zip | Bin 0 -> 14547 bytes 17 files changed, 1458 insertions(+), 1 deletion(-) create mode 100644 example_zip/ServoOverdone.zip create mode 100644 example_zip/extracted/ServoOverdone/ServoOverdone.ino create mode 100644 example_zip/extracted/ServoOverdone/diagram.json create mode 100644 example_zip/extracted/ServoOverdone/libraries.txt create mode 100644 example_zip/extracted/ServoOverdone/wokwi-project.txt create mode 100644 example_zip/extracted/pong/diagram.json create mode 100644 example_zip/extracted/pong/libraries.txt create mode 100644 example_zip/extracted/pong/pong.ino create mode 100644 example_zip/extracted/pong/wokwi-project.txt create mode 100644 example_zip/extracted/simon-with-score/README.md create mode 100644 example_zip/extracted/simon-with-score/diagram.json create mode 100644 example_zip/extracted/simon-with-score/pitches.h create mode 100644 example_zip/extracted/simon-with-score/simon-with-score.ino create mode 100644 example_zip/extracted/simon-with-score/wokwi-project.txt create mode 100644 example_zip/pong.zip create mode 100644 example_zip/simon-with-score.zip diff --git a/.gitignore b/.gitignore index 300fc22..526891b 100644 --- a/.gitignore +++ b/.gitignore @@ -77,5 +77,4 @@ wokwi-libs/*/.cache/ .claude/settings.local.json .history/* .daveagent/* -example_zip/* data/* diff --git a/example_zip/ServoOverdone.zip b/example_zip/ServoOverdone.zip new file mode 100644 index 0000000000000000000000000000000000000000..d91345a879ab4b53a1cc527767890d439ce79f21 GIT binary patch literal 17555 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 F@juwsx^w^l literal 0 HcmV?d00001 diff --git a/example_zip/extracted/ServoOverdone/ServoOverdone.ino b/example_zip/extracted/ServoOverdone/ServoOverdone.ino new file mode 100644 index 0000000..569860d --- /dev/null +++ b/example_zip/extracted/ServoOverdone/ServoOverdone.ino @@ -0,0 +1,260 @@ +// ServoOverdone.ino +// +// Example for multiple Servo objects in a array. +// +// Version 1, 28 July 2021, by Koepel. +// Version 2, 15 August 2021, by Koepel. +// changed timing, a little slower +// diagram.json has servos in reverse order (I think it is visually better) +// Added fourth sequence: "compass" +// +// Public Domain +// + +#include + +#define NUM_SERVOS 32 +Servo myServo[NUM_SERVOS]; + +void setup() +{ + // Attach pins from the Arduino Mega board to the Servo objects. + // Starting from pin 22, there happen to be exactly 32 pins on the double row pins. + for( int i=0; i=0; r--) + { + for( int i=0; i (NUM_SERVOS / 2)) + d = NUM_SERVOS - d; + + int angle = 90 - (10 * d); + if( angle < 0) + angle = 0; + myServo[j].write( angle); + } + delay(40); + } + } + + // Sequence four. + // A "compass" + // Start by pointing upwards + int pointer = NUM_SERVOS * 3 / 4; + showPointer( pointer); + delay( 1000); // let the viewer get used to new pattern + + for( int i=0; i<5; i++) + { + showPointer( --pointer); + delay( 150); + } + delay( 200); + for( int i=0; i<9; i++) + { + showPointer( ++pointer); + delay( 150); + } + delay( 200); + for( int i=0; i<5; i++) + { + showPointer( --pointer); + delay( 150); + } + delay( 200); + for( int i=0; i<4; i++) + { + showPointer( ++pointer); + delay( 150); + } + delay( 160); + for( int i=0; i<2; i++) + { + showPointer( --pointer); + delay( 150); + } + delay( 80); + for( int i=0; i<1; i++) + { + showPointer( ++pointer); + delay( 150); + } + + delay( 2000); +} + +// This function makes a "pointer" with the servos. +// It is used to create the "compass". +// The parameter 's' is the servo motor that has the pointer. +// It is allowed that 's' is below zero or larger than the numbers of servo motors. +void showPointer( int s) +{ + int pointerA = s % NUM_SERVOS; // Using the '%' (remainder) for valid number + int pointerB = (s + 1) % NUM_SERVOS; // pointer is made with the next servo motor + int tailA = (s + 16) % NUM_SERVOS; + int tailB = (s + 17) % NUM_SERVOS; + + // make pointer with servo motor s and s+1. + myServo[pointerA].write(180-56); + myServo[pointerB].write(56); + + // make tail with servo motor s+16 and s+17. + myServo[tailA].write(95); + myServo[tailB].write(85); + + // Set servos right of pointer + int n = (NUM_SERVOS / 2) - 2; + int start = pointerB + 1; + for( int i=0; i=0; i--) + { + float rotate = float( i) * (360.0 / float( NUM_SERVOS)); + float rad = rotate / 360.0 * 2.0 * M_PI; + float top = (300.0 * sin( rad)) + 300.0; + float left = (300.0 * cos( rad)) + 300.0; + Serial.print( " {\n"); + Serial.print( " \"type\": \"wokwi-servo\",\n"); + Serial.print( " \"id\": \"servo"); + Serial.print( i); + Serial.print( "\",\n"); + Serial.print( " \"top\": "); + Serial.print( top); + Serial.print( ",\n"); + Serial.print( " \"left\": "); + Serial.print( left); + Serial.print( ",\n"); + Serial.print( " \"rotate\": "); + Serial.print( rotate); + Serial.print( ",\n"); + Serial.print( " \"attrs\": { \"hornColor\": \"Red\" }\n"); + Serial.print( " }"); + if( i != 0) + Serial.print( ","); + Serial.print( "\n"); + } + + Serial.print( " ],\n"); + Serial.print( " \"connections\": [\n"); + + for( int i=0; i +#include +#include +#include + +#define UP_BUTTON 2 +#define DOWN_BUTTON 3 + +const unsigned long PADDLE_RATE = 64; +const unsigned long BALL_RATE = 16; +const uint8_t PADDLE_HEIGHT = 12; +const uint8_t SCORE_LIMIT = 9; + +Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire); + +bool game_over, win; + +uint8_t player_score, mcu_score; +uint8_t ball_x = 53, ball_y = 26; +uint8_t ball_dir_x = 1, ball_dir_y = 1; + +unsigned long ball_update; +unsigned long paddle_update; + +const uint8_t MCU_X = 12; +uint8_t mcu_y = 16; + +const uint8_t PLAYER_X = 115; +uint8_t player_y = 16; + +void setup() +{ + display.begin(SSD1306_SWITCHCAPVCC, 0x3C); + + // Display the splash screen (we're legally required to do so) + display.display(); + unsigned long start = millis(); + + pinMode(UP_BUTTON, INPUT_PULLUP); + pinMode(DOWN_BUTTON, INPUT_PULLUP); + + display.clearDisplay(); + drawCourt(); + + while(millis() - start < 2000); + + display.display(); + + ball_update = millis(); + paddle_update = ball_update; +} + +void loop() +{ + bool update_needed = false; + unsigned long time = millis(); + + static bool up_state = false; + static bool down_state = false; + + up_state |= (digitalRead(UP_BUTTON) == LOW); + down_state |= (digitalRead(DOWN_BUTTON) == LOW); + + if(time > ball_update) + { + uint8_t new_x = ball_x + ball_dir_x; + uint8_t new_y = ball_y + ball_dir_y; + + // Check if we hit the vertical walls + if(new_x == 0 || new_x == 127) + { + ball_dir_x = -ball_dir_x; + new_x += ball_dir_x + ball_dir_x; + + if (new_x < 64) + { + player_scoreTone(); + player_score++; + } + else + { + mcu_scoreTone(); + mcu_score++; + } + + if (player_score == SCORE_LIMIT || mcu_score == SCORE_LIMIT) + { + win = player_score > mcu_score; + game_over = true; + } + } + + // Check if we hit the horizontal walls. + if(new_y == 0 || new_y == 53) + { + wallTone(); + ball_dir_y = -ball_dir_y; + new_y += ball_dir_y + ball_dir_y; + } + + // Check if we hit the CPU paddle + if(new_x == MCU_X && new_y >= mcu_y && new_y <= mcu_y + PADDLE_HEIGHT) + { + mcuPaddleTone(); + ball_dir_x = -ball_dir_x; + new_x += ball_dir_x + ball_dir_x; + } + + // Check if we hit the player paddle + if(new_x == PLAYER_X && new_y >= player_y && new_y <= player_y + PADDLE_HEIGHT) + { + playerPaddleTone(); + ball_dir_x = -ball_dir_x; + new_x += ball_dir_x + ball_dir_x; + } + + display.drawPixel(ball_x, ball_y, BLACK); + display.drawPixel(new_x, new_y, WHITE); + ball_x = new_x; + ball_y = new_y; + + ball_update += BALL_RATE; + + update_needed = true; + } + + if(time > paddle_update) + { + paddle_update += PADDLE_RATE; + + // CPU paddle + display.drawFastVLine(MCU_X, mcu_y, PADDLE_HEIGHT, BLACK); + const uint8_t half_paddle = PADDLE_HEIGHT >> 1; + + if(mcu_y + half_paddle > ball_y) + { + int8_t dir = ball_x > MCU_X ? -1 : 1; + mcu_y += dir; + } + + if(mcu_y + half_paddle < ball_y) + { + int8_t dir = ball_x > MCU_X ? 1 : -1; + mcu_y += dir; + } + + if(mcu_y < 1) + { + mcu_y = 1; + } + + if(mcu_y + PADDLE_HEIGHT > 53) + { + mcu_y = 53 - PADDLE_HEIGHT; + } + + // Player paddle + display.drawFastVLine(MCU_X, mcu_y, PADDLE_HEIGHT, WHITE); + display.drawFastVLine(PLAYER_X, player_y, PADDLE_HEIGHT, BLACK); + + if(up_state) + { + player_y -= 1; + } + + if(down_state) + { + player_y += 1; + } + + up_state = down_state = false; + + if(player_y < 1) + { + player_y = 1; + } + + if(player_y + PADDLE_HEIGHT > 53) + { + player_y = 53 - PADDLE_HEIGHT; + } + + display.drawFastVLine(PLAYER_X, player_y, PADDLE_HEIGHT, WHITE); + + update_needed = true; + } + + if(update_needed) + { + if (game_over) + { + const char* text = win ? "YOU WIN!!" : "YOU LOSE!"; + display.clearDisplay(); + display.setCursor(40, 28); + display.print(text); + display.display(); + + delay(5000); + + display.clearDisplay(); + ball_x = 53; + ball_y = 26; + ball_dir_x = 1; + ball_dir_y = 1; + mcu_y = 16; + player_y = 16; + mcu_score = 0; + player_score = 0; + game_over = false; + drawCourt(); + } + + display.setTextColor(WHITE, BLACK); + display.setCursor(0, 56); + display.print(mcu_score); + display.setCursor(122, 56); + display.print(player_score); + display.display(); + } +} + +void playerPaddleTone() +{ + tone(11, 250, 25); + delay(25); + noTone(11); +} + +void mcuPaddleTone() +{ + tone(11, 225, 25); + delay(25); + noTone(11); +} + +void wallTone() +{ + tone(11, 200, 25); + delay(25); + noTone(11); +} + +void player_scoreTone() +{ + tone(11, 200, 25); + delay(50); + noTone(11); + delay(25); + tone(11, 250, 25); + delay(25); + noTone(11); +} + +void mcu_scoreTone() +{ + tone(11, 250, 25); + delay(25); + noTone(11); + delay(25); + tone(11, 200, 25); + delay(25); + noTone(11); +} + +void drawCourt() +{ + display.drawRect(0, 0, 128, 54, WHITE); +} \ No newline at end of file diff --git a/example_zip/extracted/pong/wokwi-project.txt b/example_zip/extracted/pong/wokwi-project.txt new file mode 100644 index 0000000..492e28d --- /dev/null +++ b/example_zip/extracted/pong/wokwi-project.txt @@ -0,0 +1,3 @@ +Downloaded from https://wokwi.com/projects/348849468083274322 + +Simulate this project on https://wokwi.com diff --git a/example_zip/extracted/simon-with-score/README.md b/example_zip/extracted/simon-with-score/README.md new file mode 100644 index 0000000..8de7275 --- /dev/null +++ b/example_zip/extracted/simon-with-score/README.md @@ -0,0 +1,56 @@ +Simon is a simple electronic memory game: the user has to repeat a growing sequence of +colors. The sequence is displayed by lighting up the LEDs. Each color also has a +corresponding tone. + +In each turn, the game will play the sequence, and then wait for the user to repeat +the sequence by pressing the buttons according to the color sequence. If the user +repeated the sequence correctly, the game will play a "leveling-up" sound, add a new +color at the end of the sequence, and move to the next turn. + +The game continues until the user has made a mistake. Then a game over sound is +played, and the game restarts. + +![Simon Game Shield for Arduino Uno](https://i.imgur.com/CBVsVxzh.jpg) + +### Hardware + +| Item | Quantity | Notes | +| ---------------- | -------- | ---------------------------- | +| Arduino Uno R3 | 1 | | +| 5mm LED | 4 | Red, Green, Blue, and Yellow | +| 12mm Push button | 4 | Red, Green, Blue, and Yellow | +| Resistor | 4 | 220Ω | +| Piezo Buzzer | 1 | | + +
+ Simon hardware kit +
+ Hardware for the Simon game, + + kit available on Tindie + +
+
+ +### Diagram + +
+ diagram +
Simon connection diagram
+
+ +### Pin Connections + +| Arduino Pin | Device | +| ----------- | ------------- | +| 12 | Red LED | +| 11 | Green LED | +| 10 | Blue LED | +| 9 | Yellow LED | +| 8 | Buzzer | +| 5 | Red Button | +| 4 | Green Button | +| 3 | Blue Button | +| 2 | Yellow Button | + +- The LEDs are connected through a 220Ω resistor each. diff --git a/example_zip/extracted/simon-with-score/diagram.json b/example_zip/extracted/simon-with-score/diagram.json new file mode 100644 index 0000000..6b9e8d5 --- /dev/null +++ b/example_zip/extracted/simon-with-score/diagram.json @@ -0,0 +1,133 @@ +{ + "version": 1, + "author": "Uri Shaked", + "editor": "wokwi", + "parts": [ + { "type": "wokwi-arduino-uno", "id": "uno", "top": 183, "left": 18.6, "attrs": {} }, + { + "type": "wokwi-buzzer", + "id": "buzzer", + "top": 16, + "left": 124, + "attrs": { "volume": "0.1" } + }, + { "type": "wokwi-led", "id": "led-red", "top": 10, "left": 6, "attrs": { "color": "red" } }, + { + "type": "wokwi-led", + "id": "led-green", + "top": 73, + "left": 6, + "attrs": { "color": "green" } + }, + { + "type": "wokwi-led", + "id": "led-blue", + "top": 10, + "left": 270, + "attrs": { "color": "blue" } + }, + { + "type": "wokwi-led", + "id": "led-yellow", + "top": 73, + "left": 270, + "attrs": { "color": "yellow" } + }, + { + "type": "wokwi-pushbutton", + "id": "btn-red", + "top": 10, + "left": 46, + "attrs": { "color": "red", "key": "1", "label": "1" } + }, + { + "type": "wokwi-pushbutton", + "id": "btn-green", + "top": 76, + "left": 46, + "attrs": { "color": "green", "key": "2", "label": "2" } + }, + { + "type": "wokwi-pushbutton", + "id": "btn-blue", + "top": 10, + "left": 200, + "attrs": { "color": "blue", "key": "3", "label": "3" } + }, + { + "type": "wokwi-pushbutton", + "id": "btn-yellow", + "top": 76, + "left": 200, + "attrs": { "color": "yellow", "key": "4", "label": "4" } + }, + { + "type": "wokwi-74hc595", + "id": "sr1", + "top": 171.8, + "left": 361.16, + "rotate": 180, + "attrs": {} + }, + { + "type": "wokwi-74hc595", + "id": "sr2", + "top": 171.8, + "left": 457.16, + "rotate": 180, + "attrs": {} + }, + { "type": "wokwi-7segment", "id": "sevseg1", "top": 47.16, "left": 379.48, "attrs": {} }, + { "type": "wokwi-7segment", "id": "sevseg2", "top": 47.16, "left": 446.68, "attrs": {} } + ], + "connections": [ + [ "uno:GND.1", "buzzer:1", "black", [ "v-12", "*", "h0" ] ], + [ "uno:2", "btn-yellow:1.l", "gold", [ "v-48", "*", "h-6" ] ], + [ "uno:GND.1", "btn-yellow:2.r", "black", [ "v-12", "*", "h6" ] ], + [ "uno:3", "btn-blue:1.l", "blue", [ "v-44", "*", "h-10" ] ], + [ "uno:GND.1", "btn-blue:2.r", "black", [ "v-12", "*", "h6" ] ], + [ "uno:4", "btn-green:2.r", "green", [ "v-40", "*", "h6" ] ], + [ "uno:GND.1", "btn-green:1.l", "black", [ "v-12", "*", "h-6" ] ], + [ "uno:5", "btn-red:2.r", "orange", [ "v-36", "*", "h10" ] ], + [ "uno:GND.1", "btn-red:1.l", "black", [ "v-12", "*", "h-6" ] ], + [ "uno:8", "buzzer:2", "purple", [ "v-32", "*", "h0" ] ], + [ "uno:9", "led-yellow:A", "gold", [ "v-28", "*", "h0" ] ], + [ "uno:GND.1", "led-yellow:C", "black", [ "v-12", "*", "h-15", "v4" ] ], + [ "uno:10", "led-blue:A", "blue", [ "v-24", "*", "h8" ] ], + [ "uno:GND.1", "led-blue:C", "black", [ "v-12", "*", "h-15", "v4" ] ], + [ "uno:11", "led-green:A", "green", [ "v-20", "*", "h0" ] ], + [ "uno:GND.1", "led-green:C", "black", [ "v-12", "*", "h-8", "v4" ] ], + [ "uno:12", "led-red:A", "orange", [ "v-16", "*", "h6" ] ], + [ "uno:GND.1", "led-red:C", "black", [ "v-12", "*", "h-8", "v4" ] ], + [ "uno:5V", "sr1:VCC", "red", [ "v57.5", "h253.4" ] ], + [ "uno:A2", "sr1:SHCP", "gray", [ "v19.1", "h138.4" ] ], + [ "uno:A1", "sr1:STCP", "purple", [ "v28.7", "h157.5" ] ], + [ "uno:A0", "sr1:DS", "blue", [ "v38.3", "h186.2" ] ], + [ "sr1:SHCP", "sr2:SHCP", "gray", [ "v47", "h106.12" ] ], + [ "sr1:STCP", "sr2:STCP", "purple", [ "v37.4", "h96.52" ] ], + [ "sr1:Q7S", "sr2:DS", "blue", [ "h0.52", "v56.6", "h144" ] ], + [ "sr1:VCC", "sr1:MR", "red", [ "v17", "h-57.6" ] ], + [ "sr1:VCC", "sr2:MR", "red", [ "v17", "h38.4" ] ], + [ "sr1:VCC", "sr2:VCC", "red", [ "v17", "h96" ] ], + [ "sr1:OE", "sr2:OE", "black", [ "v26.6", "h96" ] ], + [ "sr1:MR", "sevseg1:COM.1", "red", [ "v17", "h-57.6", "v-96", "h76.8" ] ], + [ "sevseg1:COM.1", "sevseg2:COM.1", "red", [ "h0", "v9.6", "h57.6" ] ], + [ "sr2:Q0", "sevseg2:A", "green", [ "v7.4", "h28.8", "v-182.4", "h-67.2" ] ], + [ "sr2:Q1", "sevseg2:B", "green", [ "v0", "h9.6", "v-134.4", "h-48" ] ], + [ "sr2:Q2", "sevseg2:C", "green", [ "v-38.4", "h-38.4" ] ], + [ "sr2:Q3", "sevseg2:D", "green", [ "v-33.6", "h-33.6", "v-9.6", "h-14.4" ] ], + [ "sr2:Q4", "sevseg2:E", "green", [ "v-28.8", "h-28.8", "v-9.6", "h-14.4" ] ], + [ "sr2:Q5", "sevseg2:F", "green", [ "v-24", "h-24", "v-9.6", "h-24", "v-110.4", "h19.2" ] ], + [ "sr2:Q6", "sevseg2:G", "green", [ "v-19.2", "h-43.2", "v-115.2", "h14.4" ] ], + [ "sr1:GND", "sr2:GND", "black", [ "v-9.6", "h96" ] ], + [ "sr1:Q1", "sevseg1:B", "green", [ "v-134.4", "h-19.2" ] ], + [ "sr1:Q2", "sevseg1:C", "green", [ "v-38.4", "h-19.2" ] ], + [ "sr1:Q3", "sevseg1:D", "green", [ "v-33.6", "h-24" ] ], + [ "sr1:Q4", "sevseg1:E", "green", [ "v-28.8", "h-28.8" ] ], + [ "uno:GND.3", "sr1:GND", "black", [ "v47.9", "h157.6", "v-259.2", "h9.6" ] ], + [ "sr1:GND", "sr1:OE", "black", [ "v-9.6", "h-9.6", "v67.2", "h172.8" ] ], + [ "sr1:Q0", "sevseg1:A", "green", [ "v65", "h-76.8", "v-240", "h57.6" ] ], + [ "sr1:Q5", "sevseg1:F", "green", [ "v-24", "h-19.2", "v-110.4", "h19.2" ] ], + [ "sr1:Q6", "sevseg1:G", "green", [ "v-19.2", "h-14.4", "v-110.4", "h14.4" ] ] + ] +} \ No newline at end of file diff --git a/example_zip/extracted/simon-with-score/pitches.h b/example_zip/extracted/simon-with-score/pitches.h new file mode 100644 index 0000000..c597c5a --- /dev/null +++ b/example_zip/extracted/simon-with-score/pitches.h @@ -0,0 +1,94 @@ +/************************************************** + This file defines constants with the frequency + of different musical notes. + *************************************************/ + +#define NOTE_B0 31 +#define NOTE_C1 33 +#define NOTE_CS1 35 +#define NOTE_D1 37 +#define NOTE_DS1 39 +#define NOTE_E1 41 +#define NOTE_F1 44 +#define NOTE_FS1 46 +#define NOTE_G1 49 +#define NOTE_GS1 52 +#define NOTE_A1 55 +#define NOTE_AS1 58 +#define NOTE_B1 62 +#define NOTE_C2 65 +#define NOTE_CS2 69 +#define NOTE_D2 73 +#define NOTE_DS2 78 +#define NOTE_E2 82 +#define NOTE_F2 87 +#define NOTE_FS2 93 +#define NOTE_G2 98 +#define NOTE_GS2 104 +#define NOTE_A2 110 +#define NOTE_AS2 117 +#define NOTE_B2 123 +#define NOTE_C3 131 +#define NOTE_CS3 139 +#define NOTE_D3 147 +#define NOTE_DS3 156 +#define NOTE_E3 165 +#define NOTE_F3 175 +#define NOTE_FS3 185 +#define NOTE_G3 196 +#define NOTE_GS3 208 +#define NOTE_A3 220 +#define NOTE_AS3 233 +#define NOTE_B3 247 +#define NOTE_C4 262 +#define NOTE_CS4 277 +#define NOTE_D4 294 +#define NOTE_DS4 311 +#define NOTE_E4 330 +#define NOTE_F4 349 +#define NOTE_FS4 370 +#define NOTE_G4 392 +#define NOTE_GS4 415 +#define NOTE_A4 440 +#define NOTE_AS4 466 +#define NOTE_B4 494 +#define NOTE_C5 523 +#define NOTE_CS5 554 +#define NOTE_D5 587 +#define NOTE_DS5 622 +#define NOTE_E5 659 +#define NOTE_F5 698 +#define NOTE_FS5 740 +#define NOTE_G5 784 +#define NOTE_GS5 831 +#define NOTE_A5 880 +#define NOTE_AS5 932 +#define NOTE_B5 988 +#define NOTE_C6 1047 +#define NOTE_CS6 1109 +#define NOTE_D6 1175 +#define NOTE_DS6 1245 +#define NOTE_E6 1319 +#define NOTE_F6 1397 +#define NOTE_FS6 1480 +#define NOTE_G6 1568 +#define NOTE_GS6 1661 +#define NOTE_A6 1760 +#define NOTE_AS6 1865 +#define NOTE_B6 1976 +#define NOTE_C7 2093 +#define NOTE_CS7 2217 +#define NOTE_D7 2349 +#define NOTE_DS7 2489 +#define NOTE_E7 2637 +#define NOTE_F7 2794 +#define NOTE_FS7 2960 +#define NOTE_G7 3136 +#define NOTE_GS7 3322 +#define NOTE_A7 3520 +#define NOTE_AS7 3729 +#define NOTE_B7 3951 +#define NOTE_C8 4186 +#define NOTE_CS8 4435 +#define NOTE_D8 4699 +#define NOTE_DS8 4978 diff --git a/example_zip/extracted/simon-with-score/simon-with-score.ino b/example_zip/extracted/simon-with-score/simon-with-score.ino new file mode 100644 index 0000000..8529eaf --- /dev/null +++ b/example_zip/extracted/simon-with-score/simon-with-score.ino @@ -0,0 +1,202 @@ +/** + Simon Game for Arduino with Score display + + Copyright (C) 2022, Uri Shaked + + Released under the MIT License. +*/ + +#include "pitches.h" + +/* Constants - define pin numbers for LEDs, + buttons and speaker, and also the game tones: */ +const uint8_t ledPins[] = {9, 10, 11, 12}; +const uint8_t buttonPins[] = {2, 3, 4, 5}; +#define SPEAKER_PIN 8 + +// These are connected to 74HC595 shift register (used to show game score): +const int LATCH_PIN = A1; // 74HC595 pin 12 +const int DATA_PIN = A0; // 74HC595pin 14 +const int CLOCK_PIN = A2; // 74HC595 pin 11 + +#define MAX_GAME_LENGTH 100 + +const int gameTones[] = { NOTE_G3, NOTE_C4, NOTE_E4, NOTE_G5}; + +/* Global variables - store the game state */ +uint8_t gameSequence[MAX_GAME_LENGTH] = {0}; +uint8_t gameIndex = 0; + +/** + Set up the Arduino board and initialize Serial communication +*/ +void setup() { + Serial.begin(9600); + for (byte i = 0; i < 4; i++) { + pinMode(ledPins[i], OUTPUT); + pinMode(buttonPins[i], INPUT_PULLUP); + } + pinMode(SPEAKER_PIN, OUTPUT); + pinMode(LATCH_PIN, OUTPUT); + pinMode(CLOCK_PIN, OUTPUT); + pinMode(DATA_PIN, OUTPUT); + + // The following line primes the random number generator. + // It assumes pin A3 is floating (disconnected): + randomSeed(analogRead(A3)); +} + +/* Digit table for the 7-segment display */ +const uint8_t digitTable[] = { + 0b11000000, + 0b11111001, + 0b10100100, + 0b10110000, + 0b10011001, + 0b10010010, + 0b10000010, + 0b11111000, + 0b10000000, + 0b10010000, +}; +const uint8_t DASH = 0b10111111; + +void sendScore(uint8_t high, uint8_t low) { + digitalWrite(LATCH_PIN, LOW); + shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, low); + shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, high); + digitalWrite(LATCH_PIN, HIGH); +} + +void displayScore() { + int high = gameIndex % 100 / 10; + int low = gameIndex % 10; + sendScore(high ? digitTable[high] : 0xff, digitTable[low]); +} + +/** + Lights the given LED and plays a suitable tone +*/ +void lightLedAndPlayTone(byte ledIndex) { + digitalWrite(ledPins[ledIndex], HIGH); + tone(SPEAKER_PIN, gameTones[ledIndex]); + delay(300); + digitalWrite(ledPins[ledIndex], LOW); + noTone(SPEAKER_PIN); +} + +/** + Plays the current sequence of notes that the user has to repeat +*/ +void playSequence() { + for (int i = 0; i < gameIndex; i++) { + byte currentLed = gameSequence[i]; + lightLedAndPlayTone(currentLed); + delay(50); + } +} + +/** + Waits until the user pressed one of the buttons, + and returns the index of that button +*/ +byte readButtons() { + while (true) { + for (byte i = 0; i < 4; i++) { + byte buttonPin = buttonPins[i]; + if (digitalRead(buttonPin) == LOW) { + return i; + } + } + delay(1); + } +} + +/** + Play the game over sequence, and report the game score +*/ +void gameOver() { + Serial.print("Game over! your score: "); + Serial.println(gameIndex - 1); + gameIndex = 0; + delay(200); + + // Play a Wah-Wah-Wah-Wah sound + tone(SPEAKER_PIN, NOTE_DS5); + delay(300); + tone(SPEAKER_PIN, NOTE_D5); + delay(300); + tone(SPEAKER_PIN, NOTE_CS5); + delay(300); + for (byte i = 0; i < 10; i++) { + for (int pitch = -10; pitch <= 10; pitch++) { + tone(SPEAKER_PIN, NOTE_C5 + pitch); + delay(5); + } + } + noTone(SPEAKER_PIN); + + sendScore(DASH, DASH); + delay(500); +} + +/** + Get the user's input and compare it with the expected sequence. +*/ +bool checkUserSequence() { + for (int i = 0; i < gameIndex; i++) { + byte expectedButton = gameSequence[i]; + byte actualButton = readButtons(); + lightLedAndPlayTone(actualButton); + if (expectedButton != actualButton) { + return false; + } + } + + return true; +} + +/** + Plays a hooray sound whenever the user finishes a level +*/ +void playLevelUpSound() { + tone(SPEAKER_PIN, NOTE_E4); + delay(150); + tone(SPEAKER_PIN, NOTE_G4); + delay(150); + tone(SPEAKER_PIN, NOTE_E5); + delay(150); + tone(SPEAKER_PIN, NOTE_C5); + delay(150); + tone(SPEAKER_PIN, NOTE_D5); + delay(150); + tone(SPEAKER_PIN, NOTE_G5); + delay(150); + noTone(SPEAKER_PIN); +} + +/** + The main game loop +*/ +void loop() { + displayScore(); + + // Add a random color to the end of the sequence + gameSequence[gameIndex] = random(0, 4); + gameIndex++; + if (gameIndex >= MAX_GAME_LENGTH) { + gameIndex = MAX_GAME_LENGTH - 1; + } + + playSequence(); + if (!checkUserSequence()) { + gameOver(); + } + + delay(300); + + if (gameIndex > 0) { + playLevelUpSound(); + delay(300); + } +} diff --git a/example_zip/extracted/simon-with-score/wokwi-project.txt b/example_zip/extracted/simon-with-score/wokwi-project.txt new file mode 100644 index 0000000..c4394e3 --- /dev/null +++ b/example_zip/extracted/simon-with-score/wokwi-project.txt @@ -0,0 +1,3 @@ +Downloaded from https://wokwi.com/projects/328451800839488084 + +Simulate this project on https://wokwi.com diff --git a/example_zip/pong.zip b/example_zip/pong.zip new file mode 100644 index 0000000000000000000000000000000000000000..3c2c53ac392215534312ad549777fee49e204538 GIT binary patch literal 8254 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 Ij~%-EEuXt8%>V!Z literal 0 HcmV?d00001