/*
  Arduino | general-help
  ecz. — 1/13/25 at 12:50 PM

  heres my idea right
  Interactive potentiometer game.

  The tilt switch controls the status of the entire Arduino,
  it turns on or off the game. The potentiometer decides the servo's
  position, and the push button is used to score a point and turn off
  an LED. The game will function as one of 4 LEDs will light up
  randomly and we need to position the servo using the potentiometer
  to point towards the LED that is lit up. When it is positioned
  correctly we will press the push button, it will play a sound and
  will display 1 representing a point on the LCD. The score will
  increment by one every time you score a successful point.
  If the button is pushed when the servo isn't pointing toward the
  lit-up LED, Incorrect will be displayed on the same LCD, and the score
  will reset as a sign of losing the game.

  Use arrays to simplify the code
  "// Tilt switch to turn the game on/off"
  Do you mean reset? A simple change...
  Changed game logic a bit. - Anon
*/

#include <Servo.h>
#include <LiquidCrystal.h>

const int MAX_SCORE = 10;
const int POS_THRESHOLD = 10; // allowable position error
// servo target position values
const int TARGET_POSITIONS[] = {60, 75, 105, 120};
// pin constants for the parallel LCD
const int RS = 12, EN = 11, D4 = 10, D5 = 9, D6 = 8, D7 = 7;
// other pin constants
const int SERVO_PIN    = 3;
const int GAME_BTN_PIN = 4;   // Push button to score a point
const int BUZZER_PIN   = 5;   // Buzzer to play sound on successful point
const int TILT_BTN_PIN = 6;   // Tilt switch to turn the game on/off
const int GAME_POT_PIN = A5;  // servo position
const int LED_PINS[]  = {A0, A1, A2, A3};

// Create servo object
Servo pointerServo;
// create a parallel LCD object called "lcd"
LiquidCrystal lcd(RS, EN, D4, D5, D6, D7);

// global variables
bool gameMode = false;    // running or not
int score = 0;            // Score counter
int currentLed = 0;       // Current lit LED
int oldGameState = HIGH;  // PULLUP, pin idles HIGH
int oldTiltState = HIGH;  // PULLUP, pin idles HIGH

// function returns true if game switch is pressed
bool checkGameButton()  {
  bool isPressed = false;

  int gameState = digitalRead(GAME_BTN_PIN);
  if (gameState != oldGameState)  {
    oldGameState = gameState;
    if (gameState == LOW)  {
      isPressed = true;
      Serial.println("Game pressed");
    }
    delay(20); // debounce
  }
  return isPressed;
}

// function returns true if tilt switch is activated
bool checkTiltSwitch()  {
  bool isPressed = false;

  int tiltState = digitalRead(TILT_BTN_PIN);
  if (tiltState != oldTiltState)  {
    oldTiltState = tiltState;
    if (tiltState == LOW)  {
      isPressed = true;
      Serial.println("Tilt pressed");
    }
    delay(20); // debounce
  }
  return isPressed;
}

// start a new game
void doStart()  {
  score = 0;
  resetLeds();
  gameMode = false;
  pointerServo.write(90);
  lcd.clear();
  lcd.setCursor(6, 0);
  lcd.print("TILT");
  lcd.setCursor(4, 1);
  lcd.print("to start");
  Serial.println("Game ready");
}

void playSound(bool winLose)  {
  if (winLose)  {
    tone(BUZZER_PIN, 220);
    delay(250);
    tone(BUZZER_PIN, 440);
    delay(250);
    tone(BUZZER_PIN, 880);
    delay(250);
  } else  {
    tone(BUZZER_PIN, 880);
    delay(250);
    tone(BUZZER_PIN, 440);
    delay(250);
    tone(BUZZER_PIN, 220);
    delay(250);
  }
  noTone(BUZZER_PIN);
}

// Function to reset all LEDs
void resetLeds() {
  for (int i = 0; i < 4; i++) {
    digitalWrite(LED_PINS[i], LOW);
  }
}

// Function to pick random LED / position
void setRandom() {
  // turn all LEDs off
  resetLeds();
  delay(500);
  // light up a random LED
  currentLed = (int)random(0, 4);
  digitalWrite(LED_PINS[currentLed], HIGH);
}

// function to show just the score
void showScore(int value) {
  char buffer[16];

  snprintf(buffer, 16, "Score: %2d ", value);
  lcd.setCursor(3, 1);
  lcd.print(buffer);
}

void setup() {
  Serial.begin(115200);
  lcd.begin(16, 2);
  // initialize pins
  pinMode(TILT_BTN_PIN, INPUT_PULLUP);
  pinMode(GAME_BTN_PIN, INPUT_PULLUP);
  pinMode(BUZZER_PIN, OUTPUT);
  for (int i = 0; i < 4; i++) {
    pinMode(LED_PINS[i], OUTPUT);
  }
  // initialize servo
  pointerServo.attach(SERVO_PIN);
  pointerServo.write(90);
  // initialize random number generator
  randomSeed(analogRead(A4));
  // splash screen
  lcd.setCursor(3, 0);
  lcd.print("Servo Game");
  lcd.setCursor(6, 1);
  lcd.print("V1.0");
  delay(2000);  // show splash for 2 seconds
  lcd.clear();
  // show instructions
  doStart();
}

void loop() {
  // check tilt sensor if game not already running
  if (checkTiltSwitch() && !gameMode)  {
    gameMode = true;
    setRandom();
    lcd.clear();
    lcd.setCursor(4, 0);
    lcd.print("Game ON!");
    showScore(score);
    Serial.println("Game running");
  }
  // if game mode was set...
  if (gameMode) {
    // Game is running, get new potentiometer value
    // Read potentiometer and map to servo range
    int mapServoPos = map(analogRead(GAME_POT_PIN), 0, 1023, 50, 130);
    // Move servo to the mapped position
    pointerServo.write(mapServoPos);
    // check game button
    if (checkGameButton())  {
      // uncomment 4 lines below to see values
      Serial.print("Current servo position:");
      Serial.println(mapServoPos);
      Serial.print("Target position:");
      Serial.println(TARGET_POSITIONS[currentLed]);
      // check if current position is close to target position
      if ((mapServoPos >= TARGET_POSITIONS[currentLed] - POS_THRESHOLD) &&
          (mapServoPos <= TARGET_POSITIONS[currentLed] + POS_THRESHOLD)) {
        // winner
        Serial.println("Winner!");
        score++;
        showScore(score);
        playSound(true);
        if (score >= MAX_SCORE)  {
          lcd.setCursor(4, 0);
          lcd.print("WINNER! ");
          delay(2000);
          doStart();
        } else  {
          delay(2000);
          setRandom();
        }
      } else {
        // loser
        Serial.println("Loser!");
        showScore(0);
        playSound(false);
        lcd.setCursor(4, 0);
        lcd.print("Loser...");
        delay(2000);
        doStart();
      }
    }
  }
}
$abcdeabcde151015202530354045505560fghijfghij
$abcdeabcde151015202530fghijfghij
Tilt
Game
ecz. Pointing Game
Created on
AnonEngineering 1/13/25