Das Spiel "Senso"
(auch "Simon" genannt) ist ein bekanntes, elektronisches Geschicklichkeitsspiel, welches ich hier
mit einigen elektronischen Bauteilen und einem Arduino als Steuereinheit nachgebaut habe.
#define PIN_LED_0 4
#define PIN_LED_1 5
#define PIN_LED_2 6
#define PIN_LED_3 7
#define PIN_BUTTON_0 8
#define PIN_BUTTON_1 9
#define PIN_BUTTON_2 10
#define PIN_BUTTON_3 11
#define PIN_PIEZO 12
#define GAME_STATUS_END 1
#define GAME_STATUS_RUNNING 2
#define BUTTON_MAX_INTERVAL 4000 // in milliseconds
#define DELAY_INIT 1000 // in milliseconds
#define DELAY_MIN 100 // in milliseconds
#define DELAY_STEP 50 // in milliseconds
#define BUTTON_DEBOUNCE_INTERVAL 50 // in milliseconds
#define NO_PIN 255
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
bool isWaitingForPlayer, isColorPlayed;
byte ledPins[4] = {PIN_LED_0, PIN_LED_1, PIN_LED_2, PIN_LED_3};
byte buttonPins[4] = {PIN_BUTTON_0, PIN_BUTTON_1, PIN_BUTTON_2, PIN_BUTTON_3};
byte score, gameStatus, sequenceIndex, pressedButton, sequence[100];
int gameDelay, frequencies[4] = {440, 580, 650, 720};
unsigned long lastPlayerAction, lastButtonPressed;
Adafruit_SSD1306 oleDisplay(4);
void setup()
{
// initialize oled with 0x3C (for 128x32)
oleDisplay.begin(SSD1306_SWITCHCAPVCC, 0x3C);
oleDisplay.clearDisplay();
oleDisplay.display();
oleDisplay.setTextSize(1);
oleDisplay.setTextColor(WHITE);
pinMode(PIN_PIEZO, OUTPUT);
for(byte i=0; i<sizeof(buttonPins); i++) {
pinMode(buttonPins[i], INPUT);
pinMode(ledPins[i], OUTPUT);
}
initGame();
}
void loop()
{
checkButtonPressed();
switch(gameStatus)
{
case GAME_STATUS_RUNNING:
if (isWaitingForPlayer == true) {
isPlayerAction();
} else {
playSequence();
}
break;
case GAME_STATUS_END:
if(pressedButton < NO_PIN) {
initGame();
}
break;
}
}
void initGame()
{
score = 0;
sequenceIndex = 0;
lastPlayerAction = 0;
memset(sequence, NO_PIN, sizeof(sequence));
isWaitingForPlayer = false;
isColorPlayed = true;
pressedButton = NO_PIN;
gameDelay = DELAY_INIT;
gameStatus = GAME_STATUS_RUNNING;
randomSeed(analogRead(0));
showScore();
// intro sequence
playColor(0, frequencies[0], 150, 30);
playColor(1, frequencies[1], 150, 30);
playColor(3, frequencies[3], 150, 30);
playColor(1, frequencies[1], 150, 30);
playColor(0, frequencies[0], 150, 30);
playColor(1, frequencies[1], 150, 30);
playColor(3, frequencies[3], 300, 30);
playColor(1, frequencies[1], 300, 30);
playColor(1, frequencies[1], 300, 30);
delay(1000);
}
void playColor(byte ledPinIndex, int toneFrequency, int delayTime, int pauseTime)
{
digitalWrite(ledPins[ledPinIndex], HIGH);
tone(PIN_PIEZO, toneFrequency);
delay(delayTime);
digitalWrite(ledPins[ledPinIndex], LOW);
noTone(PIN_PIEZO);
delay(pauseTime);
}
void setGameOver()
{
gameStatus = GAME_STATUS_END;
oleDisplay.setCursor(20,20);
oleDisplay.print("Game Over!");
oleDisplay.display();
tone(PIN_PIEZO, 100);
delay(2000);
noTone(PIN_PIEZO);
}
void playSuccess()
{
for(byte i=0; i<sizeof(ledPins); i++) {
playColor(i, frequencies[i]*2, 40, 10);
}
delay(1000);
}
void showScore()
{
oleDisplay.clearDisplay();
oleDisplay.setCursor(0,0);
oleDisplay.print("Score: " + String(score));
oleDisplay.display();
}
void playSequence()
{
bool doBreak = false;
for(byte i=0; i<sizeof(sequence); i++) {
if (sequence[i] == NO_PIN) {
sequence[i] = random(0, 4);
doBreak = true;
}
playColor(sequence[i], frequencies[sequence[i]], gameDelay, 200);
if (doBreak == true) {
break;
}
}
sequenceIndex = 0;
isWaitingForPlayer = true;
lastPlayerAction = millis();
}
void isPlayerAction()
{
// player did the whole sequence
if (sequence[sequenceIndex] == NO_PIN) {
isWaitingForPlayer = false;
score++;
showScore();
if (gameDelay > DELAY_MIN && gameDelay > DELAY_STEP) {
gameDelay -= DELAY_STEP;
}
pressedButton = NO_PIN;
playSuccess();
return;
}
// no button pressed wait until timeout
if (pressedButton == NO_PIN) {
if ((millis() - lastPlayerAction) > BUTTON_MAX_INTERVAL) {
setGameOver();
}
return;
}
// repeat color the player pressed
if (!isColorPlayed) {
playColor(pressedButton, frequencies[pressedButton], 300, 50);
isColorPlayed = true;
}
// check current color
if (sequence[sequenceIndex] == pressedButton) {
sequenceIndex++;
} else {
setGameOver();
}
pressedButton = NO_PIN;
}
void checkButtonPressed()
{
if ((millis() - lastButtonPressed) < BUTTON_DEBOUNCE_INTERVAL) {
return;
}
if (digitalRead(buttonPins[pressedButton]) == HIGH) {
// current button is released now
pressedButton = NO_PIN;
}
for(byte i=0; i<sizeof(buttonPins); i++) {
if(digitalRead(buttonPins[i]) == LOW) {
if (pressedButton == i) {
// same button is still pressed
break;
}
pressedButton = i;
isColorPlayed = false;
lastPlayerAction = millis();
}
}
lastButtonPressed = millis();
}
#define PIN_LED_0 4
#define PIN_LED_1 5
#define PIN_LED_2 6
#define PIN_LED_3 7
#define PIN_BUTTON_0 8
#define PIN_BUTTON_1 9
#define PIN_BUTTON_2 10
#define PIN_BUTTON_3 11
#define PIN_PIEZO 12
#define GAME_STATUS_END 1
#define GAME_STATUS_RUNNING 2
#define BUTTON_MAX_INTERVAL 4000 // in milliseconds
#define DELAY_INIT 1000 // in milliseconds
#define DELAY_MIN 100 // in milliseconds
#define DELAY_STEP 50 // in milliseconds
#define BUTTON_DEBOUNCE_INTERVAL 50 // in milliseconds
#define NO_PIN 255
bool isWaitingForPlayer, isColorPlayed;
byte ledPins[4] = {PIN_LED_0, PIN_LED_1, PIN_LED_2, PIN_LED_3};
byte buttonPins[4] = {PIN_BUTTON_0, PIN_BUTTON_1, PIN_BUTTON_2, PIN_BUTTON_3};
byte gameStatus, sequenceIndex, pressedButton, sequence[100];
int gameDelay, frequencies[4] = {440, 580, 650, 720};
unsigned long lastPlayerAction, lastButtonPressed;
void setup()
{
pinMode(PIN_PIEZO, OUTPUT);
for(byte i=0; i<sizeof(buttonPins); i++) {
pinMode(buttonPins[i], INPUT);
pinMode(ledPins[i], OUTPUT);
}
initGame();
}
void loop()
{
checkButtonPressed();
switch(gameStatus)
{
case GAME_STATUS_RUNNING:
if (isWaitingForPlayer == true) {
isPlayerAction();
} else {
playSequence();
}
break;
case GAME_STATUS_END:
if(pressedButton < NO_PIN) {
initGame();
}
break;
}
}
void initGame()
{
sequenceIndex = 0;
lastPlayerAction = 0;
memset(sequence, NO_PIN, sizeof(sequence));
isWaitingForPlayer = false;
isColorPlayed = true;
pressedButton = NO_PIN;
gameDelay = DELAY_INIT;
gameStatus = GAME_STATUS_RUNNING;
randomSeed(analogRead(0));
// intro sequence
playColor(0, frequencies[0], 150, 30);
playColor(1, frequencies[1], 150, 30);
playColor(3, frequencies[3], 150, 30);
playColor(1, frequencies[1], 150, 30);
playColor(0, frequencies[0], 150, 30);
playColor(1, frequencies[1], 150, 30);
playColor(3, frequencies[3], 300, 30);
playColor(1, frequencies[1], 300, 30);
playColor(1, frequencies[1], 300, 30);
delay(1000);
}
void playColor(byte ledPinIndex, int toneFrequency, int delayTime, int pauseTime)
{
digitalWrite(ledPins[ledPinIndex], HIGH);
tone(PIN_PIEZO, toneFrequency);
delay(delayTime);
digitalWrite(ledPins[ledPinIndex], LOW);
noTone(PIN_PIEZO);
delay(pauseTime);
}
void setGameOver()
{
gameStatus = GAME_STATUS_END;
tone(PIN_PIEZO, 100);
delay(2000);
noTone(PIN_PIEZO);
}
void playSuccess()
{
for(byte i=0; i<sizeof(ledPins); i++) {
playColor(i, frequencies[i]*2, 40, 10);
}
delay(1000);
}
void playSequence()
{
bool doBreak = false;
for(byte i=0; i<sizeof(sequence); i++) {
if (sequence[i] == NO_PIN) {
sequence[i] = random(0, 4);
doBreak = true;
}
playColor(sequence[i], frequencies[sequence[i]], gameDelay, 200);
if (doBreak == true) {
break;
}
}
sequenceIndex = 0;
isWaitingForPlayer = true;
lastPlayerAction = millis();
}
void isPlayerAction()
{
// player did the whole sequence
if (sequence[sequenceIndex] == NO_PIN) {
isWaitingForPlayer = false;
if (gameDelay > DELAY_MIN && gameDelay > DELAY_STEP) {
gameDelay -= DELAY_STEP;
}
pressedButton = NO_PIN;
playSuccess();
return;
}
// no button pressed wait until timeout
if (pressedButton == NO_PIN) {
if ((millis() - lastPlayerAction) > BUTTON_MAX_INTERVAL) {
setGameOver();
}
return;
}
// repeat color the player pressed
if (!isColorPlayed) {
playColor(pressedButton, frequencies[pressedButton], 300, 50);
isColorPlayed = true;
}
// check current color
if (sequence[sequenceIndex] == pressedButton) {
sequenceIndex++;
} else {
setGameOver();
}
pressedButton = NO_PIN;
}
void checkButtonPressed()
{
if ((millis() - lastButtonPressed) < BUTTON_DEBOUNCE_INTERVAL) {
return;
}
if (digitalRead(buttonPins[pressedButton]) == HIGH) {
// current button is released now
pressedButton = NO_PIN;
}
for(byte i=0; i<sizeof(buttonPins); i++) {
if(digitalRead(buttonPins[i]) == LOW) {
if (pressedButton == i) {
// same button is still pressed
break;
}
pressedButton = i;
isColorPlayed = false;
lastPlayerAction = millis();
}
}
lastButtonPressed = millis();
}
zurück